diff options
author | Mai Lavelle <mai.lavelle@gmail.com> | 2016-07-17 02:42:28 +0300 |
---|---|---|
committer | Mai Lavelle <mai.lavelle@gmail.com> | 2016-07-29 10:36:30 +0300 |
commit | c96ae81160ad1a943fafaca44a7d5e97c2d7a0d7 (patch) | |
tree | 83905d5a6bf2583f44d9dcf90410b5a0c024822c /intern/cycles/subd | |
parent | f74645578c9dd38c2543d1211b779a019363b04f (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.txt | 2 | ||||
-rw-r--r-- | intern/cycles/subd/subd_dice.cpp | 166 | ||||
-rw-r--r-- | intern/cycles/subd/subd_dice.h | 46 | ||||
-rw-r--r-- | intern/cycles/subd/subd_mesh.cpp | 419 | ||||
-rw-r--r-- | intern/cycles/subd/subd_mesh.h | 78 | ||||
-rw-r--r-- | intern/cycles/subd/subd_patch.cpp | 26 | ||||
-rw-r--r-- | intern/cycles/subd/subd_patch.h | 18 | ||||
-rw-r--r-- | intern/cycles/subd/subd_split.cpp | 199 | ||||
-rw-r--r-- | intern/cycles/subd/subd_split.h | 8 |
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 |