Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMai Lavelle <mai.lavelle@gmail.com>2016-07-17 02:42:28 +0300
committerMai Lavelle <mai.lavelle@gmail.com>2016-07-29 10:36:30 +0300
commitc96ae81160ad1a943fafaca44a7d5e97c2d7a0d7 (patch)
tree83905d5a6bf2583f44d9dcf90410b5a0c024822c /intern/cycles/subd
parentf74645578c9dd38c2543d1211b779a019363b04f (diff)
Cycles microdisplacement: ngons and attributes for subdivision meshes
This adds support for ngons and attributes on subdivision meshes. Ngons are needed for proper attribute interpolation as well as correct Catmull-Clark subdivision. Several changes are made to achieve this: - new primitive `SubdFace` added to `Mesh` - 3 more textures are used to store info on patches from subd meshes - Blender export uses loop interface instead of tessface for subd meshes - `Attribute` class is updated with a simplified way to pass primitive counts around and to support ngons. - extra points for ngons are generated for O(1) attribute interpolation - curves are temporally disabled on subd meshes to avoid various bugs with implementation - old unneeded code is removed from `subd/` - various fixes and improvements Reviewed By: brecht Differential Revision: https://developer.blender.org/D2108
Diffstat (limited to 'intern/cycles/subd')
-rw-r--r--intern/cycles/subd/CMakeLists.txt2
-rw-r--r--intern/cycles/subd/subd_dice.cpp166
-rw-r--r--intern/cycles/subd/subd_dice.h46
-rw-r--r--intern/cycles/subd/subd_mesh.cpp419
-rw-r--r--intern/cycles/subd/subd_mesh.h78
-rw-r--r--intern/cycles/subd/subd_patch.cpp26
-rw-r--r--intern/cycles/subd/subd_patch.h18
-rw-r--r--intern/cycles/subd/subd_split.cpp199
-rw-r--r--intern/cycles/subd/subd_split.h8
9 files changed, 36 insertions, 926 deletions
diff --git a/intern/cycles/subd/CMakeLists.txt b/intern/cycles/subd/CMakeLists.txt
index d1708868fd0..db497013693 100644
--- a/intern/cycles/subd/CMakeLists.txt
+++ b/intern/cycles/subd/CMakeLists.txt
@@ -14,14 +14,12 @@ set(INC_SYS
set(SRC
subd_dice.cpp
- subd_mesh.cpp
subd_patch.cpp
subd_split.cpp
)
set(SRC_HEADERS
subd_dice.h
- subd_mesh.h
subd_patch.h
subd_split.h
)
diff --git a/intern/cycles/subd/subd_dice.cpp b/intern/cycles/subd/subd_dice.cpp
index 7c74f21950e..36981a20f3c 100644
--- a/intern/cycles/subd/subd_dice.cpp
+++ b/intern/cycles/subd/subd_dice.cpp
@@ -48,6 +48,11 @@ void EdgeDice::reserve(int num_verts)
vert_offset = mesh->verts.size();
tri_offset = mesh->num_triangles();
+ /* todo: optimize so we can reserve in advance, this is like push_back_slow() */
+ if(vert_offset + num_verts > mesh->verts.capacity()) {
+ mesh->reserve_mesh(size_t((vert_offset + num_verts) * 1.2), mesh->num_triangles());
+ }
+
mesh->resize_mesh(vert_offset + num_verts, tri_offset);
Attribute *attr_vN = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL);
@@ -66,6 +71,7 @@ int EdgeDice::add_vert(Patch *patch, float2 uv)
mesh_P[vert_offset] = P;
mesh_N[vert_offset] = N;
+ params.mesh->vert_patch_uv[vert_offset] = make_float2(uv.x, uv.y);
if(params.ptex) {
Attribute *attr_ptex_uv = params.mesh->attributes.add(ATTR_STD_PTEX_UV);
@@ -75,6 +81,8 @@ int EdgeDice::add_vert(Patch *patch, float2 uv)
ptex_uv[vert_offset] = make_float3(uv.x, uv.y, 0.0f);
}
+ params.mesh->num_subd_verts++;
+
return vert_offset++;
}
@@ -86,7 +94,8 @@ void EdgeDice::add_triangle(Patch *patch, int v0, int v1, int v2)
if(mesh->triangles.size() == mesh->triangles.capacity())
mesh->reserve_mesh(mesh->verts.size(), size_t(max(mesh->num_triangles() + 1, 1) * 1.2));
- mesh->add_triangle(v0, v1, v2, params.shader, params.smooth, false);
+ mesh->add_triangle(v0, v1, v2, patch->shader, true);
+ params.mesh->triangle_patch[params.mesh->num_triangles()-1] = patch->patch_index;
if(params.ptex) {
Attribute *attr_ptex_face_id = params.mesh->attributes.add(ATTR_STD_PTEX_FACE_ID);
@@ -340,160 +349,5 @@ void QuadDice::dice(SubPatch& sub, EdgeFactors& ef)
assert(vert_offset == params.mesh->verts.size());
}
-/* TriangleDice */
-
-TriangleDice::TriangleDice(const SubdParams& params_)
-: EdgeDice(params_)
-{
-}
-
-void TriangleDice::reserve(EdgeFactors& ef, int M)
-{
- int num_verts = ef.tu + ef.tv + ef.tw;
-
- for(int m = M-2; m > 0; m -= 2)
- num_verts += 3 + (m-1)*3;
-
- if(!(M & 1))
- num_verts++;
-
- EdgeDice::reserve(num_verts);
-}
-
-float2 TriangleDice::map_uv(SubPatch& sub, float2 uv)
-{
- /* map UV from subpatch to patch parametric coordinates */
- return uv.x*sub.Pu + uv.y*sub.Pv + (1.0f - uv.x - uv.y)*sub.Pw;
-}
-
-int TriangleDice::add_vert(SubPatch& sub, float2 uv)
-{
- return EdgeDice::add_vert(sub.patch, map_uv(sub, uv));
-}
-
-void TriangleDice::add_grid(SubPatch& sub, EdgeFactors& ef, int M)
-{
- // XXX normals are flipped, why?
-
- /* grid is constructed starting from the outside edges, and adding
- * progressively smaller inner triangles that connected to the outer
- * one, until M = 1 or 2, the we fill up the last part. */
- vector<int> outer_u, outer_v, outer_w;
- int m;
-
- /* add outer corners vertices */
- {
- float2 p_u = make_float2(1.0f, 0.0f);
- float2 p_v = make_float2(0.0f, 1.0f);
- float2 p_w = make_float2(0.0f, 0.0f);
-
- int corner_u = add_vert(sub, p_u);
- int corner_v = add_vert(sub, p_v);
- int corner_w = add_vert(sub, p_w);
-
- outer_u.push_back(corner_v);
- outer_v.push_back(corner_w);
- outer_w.push_back(corner_u);
-
- for(int i = 1; i < ef.tu; i++)
- outer_u.push_back(add_vert(sub, interp(p_v, p_w, i/(float)ef.tu)));
- for(int i = 1; i < ef.tv; i++)
- outer_v.push_back(add_vert(sub, interp(p_w, p_u, i/(float)ef.tv)));
- for(int i = 1; i < ef.tw; i++)
- outer_w.push_back(add_vert(sub, interp(p_u, p_v, i/(float)ef.tw)));
-
- outer_u.push_back(corner_w);
- outer_v.push_back(corner_u);
- outer_w.push_back(corner_v);
- }
-
- for(m = M-2; m > 0; m -= 2) {
- vector<int> inner_u, inner_v, inner_w;
-
- const float t0 = m / (float)M;
- float2 center = make_float2(1.0f/3.0f, 1.0f/3.0f);
-
- /* 3 corner vertices */
- float2 p_u = interp(center, make_float2(1.0f, 0.0f), t0);
- float2 p_v = interp(center, make_float2(0.0f, 1.0f), t0);
- float2 p_w = interp(center, make_float2(0.0f, 0.0f), t0);
-
- int corner_u = add_vert(sub, p_u);
- int corner_v = add_vert(sub, p_v);
- int corner_w = add_vert(sub, p_w);
-
- /* construct array of vertex indices for each side */
- inner_u.push_back(corner_v);
- inner_v.push_back(corner_w);
- inner_w.push_back(corner_u);
-
- for(int i = 1; i < m; i++) {
- /* add vertices between corners */
- const float t1 = i / (float)m;
-
- inner_u.push_back(add_vert(sub, interp(p_v, p_w, t1)));
- inner_v.push_back(add_vert(sub, interp(p_w, p_u, t1)));
- inner_w.push_back(add_vert(sub, interp(p_u, p_v, t1)));
- }
-
- inner_u.push_back(corner_w);
- inner_v.push_back(corner_u);
- inner_w.push_back(corner_v);
-
- /* stitch together inner/outer with triangles */
- stitch_triangles(sub.patch, outer_u, inner_u);
- stitch_triangles(sub.patch, outer_v, inner_v);
- stitch_triangles(sub.patch, outer_w, inner_w);
-
- outer_u = inner_u;
- outer_v = inner_v;
- outer_w = inner_w;
- }
-
- /* fill up last part */
- if(m == -1) {
- /* single triangle */
- add_triangle(sub.patch, outer_w[0], outer_u[0], outer_v[0]);
- }
- else {
- /* center vertex + up to 6 triangles */
- int center = add_vert(sub, make_float2(1.0f/3.0f, 1.0f/3.0f));
-
- add_triangle(sub.patch, outer_w[0], outer_w[1], center);
- /* if this is false then there is only one triangle on this side */
- if(outer_w.size() > 2)
- add_triangle(sub.patch, outer_w[1], outer_w[2], center);
-
- add_triangle(sub.patch, outer_u[0], outer_u[1], center);
- if(outer_u.size() > 2)
- add_triangle(sub.patch, outer_u[1], outer_u[2], center);
-
- add_triangle(sub.patch, outer_v[0], outer_v[1], center);
- if(outer_v.size() > 2)
- add_triangle(sub.patch, outer_v[1], outer_v[2], center);
- }
-}
-
-void TriangleDice::dice(SubPatch& sub, EdgeFactors& ef)
-{
- /* todo: handle 2 1 1 resolution */
- int M = max(ef.tu, max(ef.tv, ef.tw));
-
- /* Due to the "slant" of the edges of a triangle compared to a quad, the internal
- * triangles end up smaller, causing over-tessellation. This is to correct for this
- * difference in area. Technically its only correct for equilateral triangles, but
- * its better than how it was.
- *
- * (2*cos(radians(30))/3)**0.5
- */
- float S = 0.7598356856515927f;
- M = max((int)ceil(S*M), 1);
-
- reserve(ef, M);
- add_grid(sub, ef, M);
-
- assert(vert_offset == params.mesh->verts.size());
-}
-
CCL_NAMESPACE_END
diff --git a/intern/cycles/subd/subd_dice.h b/intern/cycles/subd/subd_dice.h
index 85bd0ea28f0..3002ec780e8 100644
--- a/intern/cycles/subd/subd_dice.h
+++ b/intern/cycles/subd/subd_dice.h
@@ -33,8 +33,6 @@ class Patch;
struct SubdParams {
Mesh *mesh;
- int shader;
- bool smooth;
bool ptex;
int test_steps;
@@ -44,11 +42,9 @@ struct SubdParams {
Camera *camera;
Transform objecttoworld;
- SubdParams(Mesh *mesh_, int shader_, bool smooth_ = true, bool ptex_ = false)
+ SubdParams(Mesh *mesh_, bool ptex_ = false)
{
mesh = mesh_;
- shader = shader_;
- smooth = smooth_;
ptex = ptex_;
test_steps = 3;
@@ -136,46 +132,6 @@ public:
void dice(SubPatch& sub, EdgeFactors& ef);
};
-/* Triangle EdgeDice
- *
- * Edge tessellation factors and subpatch coordinates are as follows:
- *
- * Pw
- * /\
- * tv / \ tu
- * / \
- * / \
- * Pu -------- Pv
- * tw
- */
-
-class TriangleDice : public EdgeDice {
-public:
- struct SubPatch {
- Patch *patch;
-
- float2 Pu;
- float2 Pv;
- float2 Pw;
- };
-
- struct EdgeFactors {
- int tu;
- int tv;
- int tw;
- };
-
- explicit TriangleDice(const SubdParams& params);
-
- void reserve(EdgeFactors& ef, int M);
-
- float2 map_uv(SubPatch& sub, float2 uv);
- int add_vert(SubPatch& sub, float2 uv);
-
- void add_grid(SubPatch& sub, EdgeFactors& ef, int M);
- void dice(SubPatch& sub, EdgeFactors& ef);
-};
-
CCL_NAMESPACE_END
#endif /* __SUBD_DICE_H__ */
diff --git a/intern/cycles/subd/subd_mesh.cpp b/intern/cycles/subd/subd_mesh.cpp
deleted file mode 100644
index 56d7d2b2303..00000000000
--- a/intern/cycles/subd/subd_mesh.cpp
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- * Original code in the public domain -- castanyo@yahoo.es
- *
- * Modifications copyright (c) 2011, Blender Foundation.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-
-#include "subd_mesh.h"
-#include "subd_patch.h"
-#include "subd_split.h"
-
-#include "util_debug.h"
-#include "util_foreach.h"
-
-#ifdef WITH_OPENSUBDIV
-
-#include <osd/vertex.h>
-#include <osd/mesh.h>
-#include <osd/cpuComputeController.h>
-#include <osd/cpuVertexBuffer.h>
-#include <osd/cpuEvalLimitController.h>
-#include <osd/evalLimitContext.h>
-
-CCL_NAMESPACE_BEGIN
-
-/* typedefs */
-typedef OpenSubdiv::OsdVertex OsdVertex;
-typedef OpenSubdiv::FarMesh<OsdVertex> OsdFarMesh;
-typedef OpenSubdiv::FarMeshFactory<OsdVertex> OsdFarMeshFactory;
-typedef OpenSubdiv::HbrCatmarkSubdivision<OsdVertex> OsdHbrCatmarkSubdivision;
-typedef OpenSubdiv::HbrFace<OsdVertex> OsdHbrFace;
-typedef OpenSubdiv::HbrHalfedge<OsdVertex> OsdHbrHalfEdge;
-typedef OpenSubdiv::HbrMesh<OsdVertex> OsdHbrMesh;
-typedef OpenSubdiv::HbrVertex<OsdVertex> OsdHbrVertex;
-typedef OpenSubdiv::OsdCpuComputeContext OsdCpuComputeContext;
-typedef OpenSubdiv::OsdCpuComputeController OsdCpuComputeController;
-typedef OpenSubdiv::OsdCpuEvalLimitContext OsdCpuEvalLimitContext;
-typedef OpenSubdiv::OsdCpuEvalLimitController OsdCpuEvalLimitController;
-typedef OpenSubdiv::OsdCpuVertexBuffer OsdCpuVertexBuffer;
-typedef OpenSubdiv::OsdEvalCoords OsdEvalCoords;
-typedef OpenSubdiv::OsdVertexBufferDescriptor OsdVertexBufferDescriptor;
-
-/* OpenSubdiv Patch */
-
-class OpenSubdPatch : public Patch {
-public:
- int face_id;
-
- OpenSubdPatch(OsdFarMesh *farmesh, OsdCpuVertexBuffer *vbuf_base)
- {
- face_id = 0;
-
- /* create buffers for evaluation */
- vbuf_P = OsdCpuVertexBuffer::Create(3, 1);
- vbuf_dPdu = OsdCpuVertexBuffer::Create(3, 1);
- vbuf_dPdv = OsdCpuVertexBuffer::Create(3, 1);
-
- P = vbuf_P->BindCpuBuffer();
- dPdu = vbuf_dPdu->BindCpuBuffer();
- dPdv = vbuf_dPdv->BindCpuBuffer();
-
- /* setup evaluation context */
- OsdVertexBufferDescriptor in_desc(0, 3, 3), out_desc(0, 3, 3); /* offset, length, stride */
-
- evalctx = OsdCpuEvalLimitContext::Create(farmesh, false);
- evalctx->GetVertexData().Bind(in_desc, vbuf_base, out_desc, vbuf_P, vbuf_dPdu, vbuf_dPdv);
- }
-
- ~OpenSubdPatch()
- {
- evalctx->GetVertexData().Unbind();
-
- delete evalctx;
- delete vbuf_P;
- delete vbuf_dPdu;
- delete vbuf_dPdv;
- }
-
- void eval(float3 *P_, float3 *dPdu_, float3 *dPdv_, float u, float v)
- {
- OsdEvalCoords coords;
- coords.u = u;
- coords.v = v;
- coords.face = face_id;
-
- evalctrl.EvalLimitSample<OsdCpuVertexBuffer,OsdCpuVertexBuffer>(coords, evalctx, 0);
-
- *P_ = make_float3(P[0], P[1], P[2]);
- if(dPdu_) *dPdu_ = make_float3(dPdv[0], dPdv[1], dPdv[2]);
- if(dPdv_) *dPdv_ = make_float3(dPdu[0], dPdu[1], dPdu[2]);
-
- /* optimize: skip evaluating derivatives when not needed */
- /* todo: swapped derivatives, different winding convention? */
- }
-
- BoundBox bound()
- {
- /* not implemented */
- BoundBox bbox = BoundBox::empty;
- return bbox;
- }
-
- int ptex_face_id()
- {
- return face_id;
- }
-
-protected:
- OsdCpuEvalLimitController evalctrl;
- OsdCpuEvalLimitContext *evalctx;
- OsdCpuVertexBuffer *vbuf_P;
- OsdCpuVertexBuffer *vbuf_dPdu;
- OsdCpuVertexBuffer *vbuf_dPdv;
- float *P;
- float *dPdu;
- float *dPdv;
-};
-
-/* OpenSubdiv Mesh */
-
-OpenSubdMesh::OpenSubdMesh()
-{
- /* create osd mesh */
- static OsdHbrCatmarkSubdivision catmark;
- OsdHbrMesh *hbrmesh = new OsdHbrMesh(&catmark);
-
- /* initialize class */
- num_verts = 0;
- num_ptex_faces = 0;
- _hbrmesh = (void*)hbrmesh;
-}
-
-OpenSubdMesh::~OpenSubdMesh()
-{
- OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh;
-
- if(hbrmesh)
- delete hbrmesh;
-}
-
-void OpenSubdMesh::add_vert(const float3& co)
-{
- OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh;
-
- OsdVertex v;
- positions.push_back(co.x);
- positions.push_back(co.y);
- positions.push_back(co.z);
- hbrmesh->NewVertex(num_verts++, v);
-}
-
-void OpenSubdMesh::add_face(int v0, int v1, int v2)
-{
- int index[3] = {v0, v1, v2};
- return add_face(index, 3);
-}
-
-void OpenSubdMesh::add_face(int v0, int v1, int v2, int v3)
-{
- int index[4] = {v0, v1, v2, v3};
- add_face(index, 4);
-}
-
-void OpenSubdMesh::add_face(int *index, int num)
-{
- OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh;
-
-#ifndef NDEBUG
- /* sanity checks */
- for(int j = 0; j < num; j++) {
- OsdHbrVertex *origin = hbrmesh->GetVertex(index[j]);
- OsdHbrVertex *destination = hbrmesh->GetVertex(index[(j+1)%num]);
- OsdHbrHalfEdge *opposite = destination->GetEdge(origin);
-
- if(origin==NULL || destination==NULL)
- assert(!"An edge was specified that connected a nonexistent vertex\n");
-
- if(origin == destination)
- assert(!"An edge was specified that connected a vertex to itself\n");
-
- if(opposite && opposite->GetOpposite())
- assert(!"A non-manifold edge incident to more than 2 faces was found\n");
-
- if(origin->GetEdge(destination)) {
- assert(!"An edge connecting two vertices was specified more than once."
- "It's likely that an incident face was flipped\n");
- }
- }
-#endif
-
- OsdHbrFace *face = hbrmesh->NewFace(num, index, 0);
-
- /* this is required for limit eval patch table? */
- face->SetPtexIndex(num_ptex_faces);
-
- if(num == 4)
- num_ptex_faces++;
- else
- num_ptex_faces += num;
-}
-
-bool OpenSubdMesh::finish()
-{
- OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh;
-
- /* finish hbr mesh construction */
- hbrmesh->SetInterpolateBoundaryMethod(OsdHbrMesh::k_InterpolateBoundaryEdgeOnly);
- hbrmesh->Finish();
-
- return true;
-}
-
-void OpenSubdMesh::tessellate(DiagSplit *split)
-{
- if(num_ptex_faces == 0)
- return;
-
- const int level = 3;
- const bool requirefvar = false;
-
- /* convert HRB to FAR mesh */
- OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh;
-
- OsdFarMeshFactory meshFactory(hbrmesh, level, true);
- OsdFarMesh *farmesh = meshFactory.Create(requirefvar);
- int num_hbr_verts = hbrmesh->GetNumVertices();
-
- delete hbrmesh;
- hbrmesh = NULL;
- _hbrmesh = NULL;
-
- /* refine HBR mesh with vertex coordinates */
- OsdCpuComputeController *compute_controller = new OsdCpuComputeController();
- OsdCpuComputeContext *compute_context = OsdCpuComputeContext::Create(farmesh);
-
- OsdCpuVertexBuffer *vbuf_base = OsdCpuVertexBuffer::Create(3, num_hbr_verts);
- vbuf_base->UpdateData(&positions[0], 0, num_verts);
-
- compute_controller->Refine(compute_context, farmesh->GetKernelBatches(), vbuf_base);
- compute_controller->Synchronize();
-
- /* split & dice patches */
- OpenSubdPatch patch(farmesh, vbuf_base);
-
- for(int f = 0; f < num_ptex_faces; f++) {
- patch.face_id = f;
- split->split_quad(&patch);
- }
-
- /* clean up */
- delete farmesh;
- delete compute_controller;
- delete compute_context;
- delete vbuf_base;
-}
-
-CCL_NAMESPACE_END
-
-#else /* WITH_OPENSUBDIV */
-
-CCL_NAMESPACE_BEGIN
-
-/* Subd Vertex */
-
-class SubdVert
-{
-public:
- int id;
- float3 co;
-
- explicit SubdVert(int id_)
- {
- id = id_;
- co = make_float3(0.0f, 0.0f, 0.0f);
- }
-};
-
-/* Subd Face */
-
-class SubdFace
-{
-public:
- int id;
- int numverts;
- int verts[4];
-
- explicit SubdFace(int id_)
- {
- id = id_;
- numverts = 0;
- }
-};
-
-/* Subd Mesh */
-
-SubdMesh::SubdMesh()
-{
-}
-
-SubdMesh::~SubdMesh()
-{
- foreach(SubdVert *vertex, verts)
- delete vertex;
- foreach(SubdFace *face, faces)
- delete face;
-
- verts.clear();
- faces.clear();
-}
-
-SubdVert *SubdMesh::add_vert(const float3& co)
-{
- SubdVert *v = new SubdVert(verts.size());
- v->co = co;
- verts.push_back(v);
-
- return v;
-}
-
-SubdFace *SubdMesh::add_face(int v0, int v1, int v2)
-{
- int index[3] = {v0, v1, v2};
- return add_face(index, 3);
-}
-
-SubdFace *SubdMesh::add_face(int v0, int v1, int v2, int v3)
-{
- int index[4] = {v0, v1, v2, v3};
- return add_face(index, 4);
-}
-
-SubdFace *SubdMesh::add_face(int *index, int num)
-{
- /* skip ngons */
- if(num < 3 || num > 4)
- return NULL;
-
- SubdFace *f = new SubdFace(faces.size());
-
- for(int i = 0; i < num; i++)
- f->verts[i] = index[i];
-
- f->numverts = num;
- faces.push_back(f);
-
- return f;
-}
-
-bool SubdMesh::finish()
-{
- return true;
-}
-
-void SubdMesh::tessellate(DiagSplit *split)
-{
- int num_faces = faces.size();
-
- for(int f = 0; f < num_faces; f++) {
- SubdFace *face = faces[f];
- Patch *patch;
- float3 *hull;
-
- if(face->numverts == 3) {
- LinearTrianglePatch *lpatch = new LinearTrianglePatch();
- hull = lpatch->hull;
- patch = lpatch;
- }
- else if(face->numverts == 4) {
- LinearQuadPatch *lpatch = new LinearQuadPatch();
- hull = lpatch->hull;
- patch = lpatch;
- }
- else {
- assert(0); /* n-gons should have been split already */
- continue;
- }
-
- for(int i = 0; i < face->numverts; i++)
- hull[i] = verts[face->verts[i]]->co;
-
- if(face->numverts == 4)
- swap(hull[2], hull[3]);
-
- if(patch->is_triangle())
- split->split_triangle(patch);
- else
- split->split_quad(patch);
-
- delete patch;
- }
-}
-
-CCL_NAMESPACE_END
-
-#endif /* WITH_OPENSUBDIV */
-
diff --git a/intern/cycles/subd/subd_mesh.h b/intern/cycles/subd/subd_mesh.h
deleted file mode 100644
index f6aefc20318..00000000000
--- a/intern/cycles/subd/subd_mesh.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Original code in the public domain -- castanyo@yahoo.es
- *
- * Modifications copyright (c) 2011, Blender Foundation.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef __SUBD_MESH_H__
-#define __SUBD_MESH_H__
-
-#include "util_map.h"
-#include "util_types.h"
-#include "util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-#ifndef WITH_OPENSUBDIV
-class SubdVert;
-class SubdFace;
-#endif
-
-class DiagSplit;
-class Mesh;
-
-/* Subd Mesh with simple linear subdivision */
-
-class SubdMesh
-{
-public:
- SubdMesh();
- ~SubdMesh();
-
- SubdVert *add_vert(const float3& co);
-
- SubdFace *add_face(int v0, int v1, int v2);
- SubdFace *add_face(int v0, int v1, int v2, int v3);
- SubdFace *add_face(int *index, int num);
-
- bool finish();
- void tessellate(DiagSplit *split);
-
-protected:
-#ifdef WITH_OPENSUBDIV
- void *_hbrmesh;
- vector<float> positions;
- int num_verts, num_ptex_faces;
-#else
- vector<SubdVert*> verts;
- vector<SubdFace*> faces;
-#endif
-
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __SUBD_MESH_H__ */
-
diff --git a/intern/cycles/subd/subd_patch.cpp b/intern/cycles/subd/subd_patch.cpp
index 60a78016054..d3319c5ccf5 100644
--- a/intern/cycles/subd/subd_patch.cpp
+++ b/intern/cycles/subd/subd_patch.cpp
@@ -84,32 +84,6 @@ BoundBox LinearQuadPatch::bound()
return bbox;
}
-/* Linear Triangle Patch */
-
-void LinearTrianglePatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v)
-{
- *P = u*hull[0] + v*hull[1] + (1.0f - u - v)*hull[2];
-
- if(dPdu && dPdv) {
- *dPdu = hull[0] - hull[2];
- *dPdv = hull[1] - hull[2];
- }
-
- if(N) {
- *N = normalize(u*normals[0] + v*normals[1] + (1.0f - u - v)*normals[2]);
- }
-}
-
-BoundBox LinearTrianglePatch::bound()
-{
- BoundBox bbox = BoundBox::empty;
-
- for(int i = 0; i < 3; i++)
- bbox.grow(hull[i]);
-
- return bbox;
-}
-
/* Bicubic Patch */
void BicubicPatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v)
diff --git a/intern/cycles/subd/subd_patch.h b/intern/cycles/subd/subd_patch.h
index bfa04412c66..360c1abf27b 100644
--- a/intern/cycles/subd/subd_patch.h
+++ b/intern/cycles/subd/subd_patch.h
@@ -26,9 +26,11 @@ class Patch {
public:
virtual ~Patch() {}
virtual void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v) = 0;
- virtual bool is_triangle() { return false; }
virtual BoundBox bound() = 0;
virtual int ptex_face_id() { return -1; }
+
+ int patch_index;
+ int shader;
};
/* Linear Quad Patch */
@@ -39,19 +41,6 @@ public:
float3 normals[4];
void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v);
- bool is_triangle() { return false; }
- BoundBox bound();
-};
-
-/* Linear Triangle Patch */
-
-class LinearTrianglePatch : public Patch {
-public:
- float3 hull[3];
- float3 normals[3];
-
- void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v);
- bool is_triangle() { return true; }
BoundBox bound();
};
@@ -62,7 +51,6 @@ public:
float3 hull[16];
void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v);
- bool is_triangle() { return false; }
BoundBox bound();
};
diff --git a/intern/cycles/subd/subd_split.cpp b/intern/cycles/subd/subd_split.cpp
index c4af8cc8c43..3c91ad8ab0d 100644
--- a/intern/cycles/subd/subd_split.cpp
+++ b/intern/cycles/subd/subd_split.cpp
@@ -40,12 +40,6 @@ void DiagSplit::dispatch(QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef)
edgefactors_quad.push_back(ef);
}
-void DiagSplit::dispatch(TriangleDice::SubPatch& sub, TriangleDice::EdgeFactors& ef)
-{
- subpatches_triangle.push_back(sub);
- edgefactors_triangle.push_back(ef);
-}
-
float3 DiagSplit::to_world(Patch *patch, float2 uv)
{
float3 P;
@@ -112,34 +106,6 @@ void DiagSplit::partition_edge(Patch *patch, float2 *P, int *t0, int *t1, float2
}
}
-static float2 right_to_equilateral(float2 P)
-{
- static const float2 A = make_float2(1.0f, 0.5f);
- static const float2 B = make_float2(0.0f, sinf(M_PI_F/3.0f));
- return make_float2(dot(P, A), dot(P, B));
-}
-
-static void limit_edge_factors(const TriangleDice::SubPatch& sub, TriangleDice::EdgeFactors& ef, int max_t)
-{
- float2 Pu = sub.Pu;
- float2 Pv = sub.Pv;
- float2 Pw = sub.Pw;
-
- if(sub.patch->is_triangle()) {
- Pu = right_to_equilateral(Pu);
- Pv = right_to_equilateral(Pv);
- Pw = right_to_equilateral(Pw);
- }
-
- int tu = int(max_t * len(Pw - Pv));
- int tv = int(max_t * len(Pw - Pu));
- int tw = int(max_t * len(Pv - Pu));
-
- ef.tu = tu <= 1 ? 1 : min(ef.tu, tu);
- ef.tv = tv <= 1 ? 1 : min(ef.tv, tv);
- ef.tw = tw <= 1 ? 1 : min(ef.tw, tw);
-}
-
static void limit_edge_factors(const QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef, int max_t)
{
float2 P00 = sub.P00;
@@ -147,13 +113,6 @@ static void limit_edge_factors(const QuadDice::SubPatch& sub, QuadDice::EdgeFact
float2 P10 = sub.P10;
float2 P11 = sub.P11;
- if(sub.patch->is_triangle()) {
- P00 = right_to_equilateral(P00);
- P01 = right_to_equilateral(P01);
- P10 = right_to_equilateral(P10);
- P11 = right_to_equilateral(P11);
- }
-
int tu0 = int(max_t * len(P10 - P00));
int tu1 = int(max_t * len(P11 - P01));
int tv0 = int(max_t * len(P01 - P00));
@@ -165,84 +124,6 @@ static void limit_edge_factors(const QuadDice::SubPatch& sub, QuadDice::EdgeFact
ef.tv1 = tv1 <= 1 ? 1 : min(ef.tv1, tv1);
}
-void DiagSplit::split(TriangleDice::SubPatch& sub, TriangleDice::EdgeFactors& ef, int depth)
-{
- if(depth > 32) {
- /* We should never get here, but just in case end recursion safely. */
- ef.tu = 1;
- ef.tv = 1;
- ef.tw = 1;
-
- dispatch(sub, ef);
- return;
- }
-
- assert(ef.tu == T(sub.patch, sub.Pv, sub.Pw));
- assert(ef.tv == T(sub.patch, sub.Pw, sub.Pu));
- assert(ef.tw == T(sub.patch, sub.Pu, sub.Pv));
-
- int non_uniform_count = int(ef.tu == DSPLIT_NON_UNIFORM) +
- int(ef.tv == DSPLIT_NON_UNIFORM) +
- int(ef.tw == DSPLIT_NON_UNIFORM);
-
- switch(non_uniform_count) {
- case 1: {
- /* TODO(mai): one edge is non-uniform, split into two triangles */
- // fallthru
- }
- case 2: {
- /* TODO(mai): two edges are non-uniform, split into triangle and quad */
- // fallthru
- }
- case 3: {
- /* all three edges are non-uniform, split into three quads */
-
- /* partition edges */
- QuadDice::EdgeFactors ef0, ef1, ef2;
- float2 Pu, Pv, Pw, Pcenter;
-
- partition_edge(sub.patch, &Pu, &ef1.tv0, &ef2.tu0, sub.Pw, sub.Pv, ef.tu);
- partition_edge(sub.patch, &Pv, &ef0.tv0, &ef1.tu0, sub.Pu, sub.Pw, ef.tv);
- partition_edge(sub.patch, &Pw, &ef2.tv0, &ef0.tu0, sub.Pv, sub.Pu, ef.tw);
- Pcenter = (Pu + Pv + Pw) * (1.0f / 3.0f);
-
- /* split */
- int tsplit01 = T(sub.patch, Pv, Pcenter);
- int tsplit12 = T(sub.patch, Pu, Pcenter);
- int tsplit20 = T(sub.patch, Pw, Pcenter);
-
- ef0.tu1 = tsplit01;
- ef0.tv1 = tsplit20;
-
- ef1.tu1 = tsplit12;
- ef1.tv1 = tsplit01;
-
- ef2.tu1 = tsplit20;
- ef2.tv1 = tsplit12;
-
- /* create subpatches */
- QuadDice::SubPatch sub0 = {sub.patch, sub.Pu, Pw, Pv, Pcenter};
- QuadDice::SubPatch sub1 = {sub.patch, sub.Pw, Pv, Pu, Pcenter};
- QuadDice::SubPatch sub2 = {sub.patch, sub.Pv, Pu, Pw, Pcenter};
-
- limit_edge_factors(sub0, ef0, 1 << params.max_level);
- limit_edge_factors(sub1, ef1, 1 << params.max_level);
- limit_edge_factors(sub2, ef2, 1 << params.max_level);
-
- split(sub0, ef0, depth+1);
- split(sub1, ef1, depth+1);
- split(sub2, ef2, depth+1);
-
- break;
- }
- default: {
- /* all edges uniform, no splitting needed */
- dispatch(sub, ef);
- break;
- }
- }
-}
-
void DiagSplit::split(QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef, int depth)
{
if(depth > 32) {
@@ -259,6 +140,16 @@ void DiagSplit::split(QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef, int de
bool split_u = (ef.tu0 == DSPLIT_NON_UNIFORM || ef.tu1 == DSPLIT_NON_UNIFORM);
bool split_v = (ef.tv0 == DSPLIT_NON_UNIFORM || ef.tv1 == DSPLIT_NON_UNIFORM);
+ /* Split subpatches such that the ratio of T for opposite edges doesn't
+ * exceed 1.5, this reduces over tessellation for some patches
+ */
+ bool tmp_split_v = split_v;
+ if(!split_u && min(ef.tu0, ef.tu1) > 8 && min(ef.tu0, ef.tu1)*1.5f < max(ef.tu0, ef.tu1))
+ split_v = true;
+ if(!tmp_split_v && min(ef.tu0, ef.tu1) > 8 && min(ef.tv0, ef.tv1)*1.5f < max(ef.tv0, ef.tv1))
+ split_u = true;
+
+ /* alternate axis */
if(split_u && split_v) {
split_u = depth % 2;
}
@@ -324,69 +215,21 @@ void DiagSplit::split(QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef, int de
}
}
-void DiagSplit::split_triangle(Patch *patch)
-{
- TriangleDice::SubPatch sub_split;
- TriangleDice::EdgeFactors ef_split;
-
- sub_split.patch = patch;
- sub_split.Pu = make_float2(1.0f, 0.0f);
- sub_split.Pv = make_float2(0.0f, 1.0f);
- sub_split.Pw = make_float2(0.0f, 0.0f);
-
- ef_split.tu = T(patch, sub_split.Pv, sub_split.Pw);
- ef_split.tv = T(patch, sub_split.Pw, sub_split.Pu);
- ef_split.tw = T(patch, sub_split.Pu, sub_split.Pv);
-
- limit_edge_factors(sub_split, ef_split, 1 << params.max_level);
-
- split(sub_split, ef_split);
-
- TriangleDice dice(params);
-
- for(size_t i = 0; i < subpatches_triangle.size(); i++) {
- TriangleDice::SubPatch& sub = subpatches_triangle[i];
- TriangleDice::EdgeFactors& ef = edgefactors_triangle[i];
-
- ef.tu = max(ef.tu, 1);
- ef.tv = max(ef.tv, 1);
- ef.tw = max(ef.tw, 1);
-
- dice.dice(sub, ef);
- }
-
- subpatches_triangle.clear();
- edgefactors_triangle.clear();
-
- /* triangle might be split into quads so dice quad subpatches as well */
- QuadDice qdice(params);
-
- for(size_t i = 0; i < subpatches_quad.size(); i++) {
- QuadDice::SubPatch& sub = subpatches_quad[i];
- QuadDice::EdgeFactors& ef = edgefactors_quad[i];
-
- ef.tu0 = max(ef.tu0, 1);
- ef.tu1 = max(ef.tu1, 1);
- ef.tv0 = max(ef.tv0, 1);
- ef.tv1 = max(ef.tv1, 1);
-
- qdice.dice(sub, ef);
- }
-
- subpatches_quad.clear();
- edgefactors_quad.clear();
-}
-
-void DiagSplit::split_quad(Patch *patch)
+void DiagSplit::split_quad(Patch *patch, QuadDice::SubPatch *subpatch)
{
QuadDice::SubPatch sub_split;
QuadDice::EdgeFactors ef_split;
- sub_split.patch = patch;
- sub_split.P00 = make_float2(0.0f, 0.0f);
- sub_split.P10 = make_float2(1.0f, 0.0f);
- sub_split.P01 = make_float2(0.0f, 1.0f);
- sub_split.P11 = make_float2(1.0f, 1.0f);
+ if(subpatch) {
+ sub_split = *subpatch;
+ }
+ else {
+ sub_split.patch = patch;
+ sub_split.P00 = make_float2(0.0f, 0.0f);
+ sub_split.P10 = make_float2(1.0f, 0.0f);
+ sub_split.P01 = make_float2(0.0f, 1.0f);
+ sub_split.P11 = make_float2(1.0f, 1.0f);
+ }
ef_split.tu0 = T(patch, sub_split.P00, sub_split.P10);
ef_split.tu1 = T(patch, sub_split.P01, sub_split.P11);
diff --git a/intern/cycles/subd/subd_split.h b/intern/cycles/subd/subd_split.h
index bbe921f739c..a2f76dd2e03 100644
--- a/intern/cycles/subd/subd_split.h
+++ b/intern/cycles/subd/subd_split.h
@@ -38,8 +38,6 @@ class DiagSplit {
public:
vector<QuadDice::SubPatch> subpatches_quad;
vector<QuadDice::EdgeFactors> edgefactors_quad;
- vector<TriangleDice::SubPatch> subpatches_triangle;
- vector<TriangleDice::EdgeFactors> edgefactors_triangle;
SubdParams params;
@@ -53,11 +51,7 @@ public:
void dispatch(QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef);
void split(QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef, int depth=0);
- void dispatch(TriangleDice::SubPatch& sub, TriangleDice::EdgeFactors& ef);
- void split(TriangleDice::SubPatch& sub, TriangleDice::EdgeFactors& ef, int depth=0);
-
- void split_triangle(Patch *patch);
- void split_quad(Patch *patch);
+ void split_quad(Patch *patch, QuadDice::SubPatch *subpatch=NULL);
};
CCL_NAMESPACE_END