Commit: 7e7eaf46eddde0d1509dd645f2972db3383c7e67
Author: Mai Lavelle
Date:   Sat Jun 25 09:35:07 2016 -0400
Branches: temp-cycles-microdisplacement
https://developer.blender.org/rB7e7eaf46eddde0d1509dd645f2972db3383c7e67

Initial OpenSubdiv support

Catmull-Clark subdivision option is now functional. Creases and uv subdivision
will be implemented later.

===================================================================

M       intern/cycles/blender/blender_mesh.cpp
M       intern/cycles/render/mesh.cpp
M       intern/cycles/render/mesh.h
M       intern/cycles/render/mesh_subdivision.cpp

===================================================================

diff --git a/intern/cycles/blender/blender_mesh.cpp 
b/intern/cycles/blender/blender_mesh.cpp
index 2fcbf91..4bf0b3a 100644
--- a/intern/cycles/blender/blender_mesh.cpp
+++ b/intern/cycles/blender/blender_mesh.cpp
@@ -769,6 +769,7 @@ static void create_subd_mesh(Scene *scene,
                              float dicing_rate,
                              int max_subdivisions)
 {
+       mesh->subdivision_type = (Mesh::SubdivisionType)RNA_enum_get(cmesh, 
"subdivision_type");
        create_mesh(scene, mesh, b_mesh, used_shaders, true);
 
        SubdParams sdparams(mesh, 0, true, false);
diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp
index 074e887..0cb5d76 100644
--- a/intern/cycles/render/mesh.cpp
+++ b/intern/cycles/render/mesh.cpp
@@ -143,6 +143,8 @@ Mesh::Mesh()
        has_surface_bssrdf = false;
 
        num_ngons = 0;
+
+       subdivision_type = SUBDIVISION_NONE;
 }
 
 Mesh::~Mesh()
diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h
index 735afa6..0e721c4 100644
--- a/intern/cycles/render/mesh.h
+++ b/intern/cycles/render/mesh.h
@@ -111,6 +111,14 @@ public:
                DISPLACE_NUM_METHODS,
        };
 
+       enum SubdivisionType {
+               SUBDIVISION_NONE,
+               SUBDIVISION_LINEAR,
+               SUBDIVISION_CATMULL_CLARK,
+       };
+
+       SubdivisionType subdivision_type;
+
        /* Mesh Data */
        enum GeometryFlags {
                GEOMETRY_NONE      = 0,
diff --git a/intern/cycles/render/mesh_subdivision.cpp 
b/intern/cycles/render/mesh_subdivision.cpp
index 43c36c7..31d19bc 100644
--- a/intern/cycles/render/mesh_subdivision.cpp
+++ b/intern/cycles/render/mesh_subdivision.cpp
@@ -24,8 +24,206 @@
 
 CCL_NAMESPACE_BEGIN
 
+#ifdef WITH_OPENSUBDIV
+
+CCL_NAMESPACE_END
+
+#include <opensubdiv/far/topologyRefinerFactory.h>
+#include <opensubdiv/far/primvarRefiner.h>
+#include <opensubdiv/far/patchTableFactory.h>
+#include <opensubdiv/far/patchMap.h>
+
+/* specializations of TopologyRefinerFactory for ccl::Mesh */
+
+namespace OpenSubdiv::OPENSUBDIV_VERSION::Far {
+       template<>
+       bool 
TopologyRefinerFactory<ccl::Mesh>::resizeComponentTopology(TopologyRefiner& 
refiner, ccl::Mesh const& mesh)
+       {
+               setNumBaseVertices(refiner, mesh.verts.size());
+               setNumBaseFaces(refiner, mesh.subd_faces.size());
+
+               ccl::Mesh::SubdFace* face = &mesh.subd_faces[0];
+
+               for(int i = 0; i < mesh.subd_faces.size(); i++, face++) {
+                       setNumBaseFaceVertices(refiner, i, face->num_corners);
+               }
+
+               return true;
+       }
+
+       template<>
+       bool 
TopologyRefinerFactory<ccl::Mesh>::assignComponentTopology(TopologyRefiner& 
refiner, ccl::Mesh const& mesh)
+       {
+               ccl::Mesh::SubdFace* face = &mesh.subd_faces[0];
+
+               for(int i = 0; i < mesh.subd_faces.size(); i++, face++) {
+                       IndexArray face_verts = getBaseFaceVertices(refiner, i);
+
+                       int* corner = 
&mesh.subd_face_corners[face->start_corner];
+
+                       for(int j = 0; j < face->num_corners; j++, corner++) {
+                               face_verts[j] = *corner;
+                       }
+               }
+
+               return true;
+       }
+
+       template<>
+       bool 
TopologyRefinerFactory<ccl::Mesh>::assignComponentTags(TopologyRefiner& 
/*refiner*/, ccl::Mesh const& /*mesh*/)
+       {
+               return true;
+       }
+
+       template<>
+       bool 
TopologyRefinerFactory<ccl::Mesh>::assignFaceVaryingTopology(TopologyRefiner& 
/*refiner*/, ccl::Mesh const& /*mesh*/)
+       {
+               return true;
+       }
+
+       template<>
+       void 
TopologyRefinerFactory<ccl::Mesh>::reportInvalidTopology(TopologyError 
/*err_code*/,
+               char const */*msg*/, ccl::Mesh const& /*mesh*/)
+       {
+       }
+}
+
+CCL_NAMESPACE_BEGIN
+
+using namespace OpenSubdiv;
+
+/* struct that implements OpenSubdiv's vertex interface */
+
+struct OsdVertex {
+       float3 v;
+
+       OsdVertex() {}
+
+       void Clear(void* = 0) {
+               v = make_float3(0.0f, 0.0f, 0.0f);
+       }
+
+       void AddWithWeight(OsdVertex const& src, float weight) {
+               v += src.v * weight;
+       }
+};
+
+/* class for holding OpenSubdiv data used during tessellation */
+
+class OsdData {
+       Mesh* mesh;
+       vector<OsdVertex> verts;
+       Far::PatchTable* patch_table;
+       Far::PatchMap* patch_map;
+
+public:
+       OsdData() : mesh(NULL), patch_table(NULL), patch_map(NULL) {}
+
+       ~OsdData()
+       {
+               delete patch_table;
+               delete patch_map;
+       }
+
+       void build_from_mesh(Mesh* mesh_)
+       {
+               mesh = mesh_;
+
+               /* type and options */
+               Sdc::SchemeType type = Sdc::SCHEME_CATMARK;
+
+               Sdc::Options options;
+               
options.SetVtxBoundaryInterpolation(Sdc::Options::VTX_BOUNDARY_EDGE_ONLY);
+
+               /* create refiner */
+               Far::TopologyRefiner* refiner = 
Far::TopologyRefinerFactory<Mesh>::Create(*mesh,
+                               
Far::TopologyRefinerFactory<Mesh>::Options(type, options));
+
+               /* adaptive refinement */
+               int max_isolation = 10;
+               
refiner->RefineAdaptive(Far::TopologyRefiner::AdaptiveOptions(max_isolation));
+
+               /* create patch table */
+               Far::PatchTableFactory::Options patch_options;
+               patch_options.endCapType = 
Far::PatchTableFactory::Options::ENDCAP_GREGORY_BASIS;
+
+               patch_table = Far::PatchTableFactory::Create(*refiner, 
patch_options);
+
+               /* interpolate verts */
+               int num_refiner_verts = refiner->GetNumVerticesTotal();
+               int num_local_points = patch_table->GetNumLocalPoints();
+
+               verts.resize(num_refiner_verts + num_local_points);
+               for(int i = 0; i < mesh->verts.size(); i++) {
+                       verts[i].v = mesh->verts[i];
+               }
+
+               OsdVertex* src = &verts[0];
+               for(int i = 0; i < refiner->GetMaxLevel(); i++) {
+                       OsdVertex* dest = src + 
refiner->GetLevel(i).GetNumVertices();
+                       Far::PrimvarRefiner(*refiner).Interpolate(i+1, src, 
dest);
+                       src = dest;
+               }
+
+               patch_table->ComputeLocalPointValues(&verts[0], 
&verts[num_refiner_verts]);
+
+               /* create patch map */
+               patch_map = new Far::PatchMap(*patch_table);
+       }
+
+       friend struct OsdPatch;
+};
+
+/* ccl::Patch implementation that uses OpenSubdiv for eval */
+
+struct OsdPatch : Patch {
+       OsdData* osd_data;
+
+       OsdPatch(OsdData* data) : osd_data(data) {}
+
+       void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, 
float v)
+       {
+               const Far::PatchTable::PatchHandle* handle = 
osd_data->patch_map->FindPatch(patch_index, u, v);
+               assert(handle);
+
+               float p_weights[20], du_weights[20], dv_weights[20];
+               osd_data->patch_table->EvaluateBasis(*handle, u, v, p_weights, 
du_weights, dv_weights);
+
+               Far::ConstIndexArray cv = 
osd_data->patch_table->GetPatchVertices(*handle);
+
+               float3 du, dv;
+               if(P) *P = make_float3(0.0f, 0.0f, 0.0f);
+               du = make_float3(0.0f, 0.0f, 0.0f);
+               dv = make_float3(0.0f, 0.0f, 0.0f);
+
+               for(int i = 0; i < cv.size(); i++) {
+                       float3 p = osd_data->verts[cv[i]].v;
+
+                       if(P) *P += p * p_weights[i];
+                       du += p * du_weights[i];
+                       dv += p * dv_weights[i];
+               }
+
+               if(dPdu) *dPdu = du;
+               if(dPdv) *dPdv = dv;
+               if(N) *N = normalize(cross(du, dv));
+       }
+
+       BoundBox bound() { return BoundBox::empty; }
+};
+
+#endif
+
 void Mesh::tessellate(DiagSplit *split)
 {
+#ifdef WITH_OPENSUBDIV
+       OsdData osd_data;
+
+       if(subdivision_type == SUBDIVISION_CATMULL_CLARK) {
+               osd_data.build_from_mesh(this);
+       }
+#endif
+
        int num_faces = subd_faces.size();
 
        Attribute *attr_vN = subd_attributes.find(ATTR_STD_VERTEX_NORMAL);
@@ -36,104 +234,131 @@ void Mesh::tessellate(DiagSplit *split)
 
                if(face.is_quad()) {
                        /* quad */
-                       LinearQuadPatch patch;
-                       float3 *hull = patch.hull;
-                       float3 *normals = patch.normals;
+                       QuadDice::SubPatch subpatch;
 
-                       patch.patch_index = face.ptex_offset;
+                       LinearQuadPatch quad_patch;
+#ifdef WITH_OPENSUBDIV
+                       OsdPatch osd_patch(&osd_data);
 
-                       for(int i = 0; i < 4; i++) {
-                               hull[i] = 
verts[subd_face_corners[face.start_corner+i]];
+                       if(subdivision_type == SUBDIVISION_CATMULL_CLARK) {
+                               osd_patch.patch_index = face.ptex_offset;
+
+                               subpatch.patch = &osd_patch;
                        }
+                       else
+#endif
+                       {
+                               float3 *hull = quad_patch.hull;
+                               float3 *normals = quad_patch.normals;
+
+                               quad_patch.patch_index = face.ptex_offset;
 
-                       if(face.smooth) {
                                for(int i = 0; i < 4; i++) {
-                                       normals[i] = 
vN[subd_face_corners[face.start_corner+i]];
+                                       hull[i] = 
verts[subd_face_corners[face.start_corner+i]];
                                }
-                       }
-                       else {
-                               float3 N = face.normal(this);
-                               for(int i = 0; i < 4; i++) {
-                                       normals[i] = N;
+
+                               if(face.smooth) {
+                                       for(int i = 0; i < 4; i++) {
+                                               normals[i] = 
vN[subd_face_corners[face.start_corner+i]];
+                                       }
                                }
-                       }
+                               else {
+                                       float3 N = face.normal(this);
+                                       for(int i = 0; i < 4; i++) {
+                                               normals[i] = N;
+                                       }
+                               }
+
+                               swap(hull[2], hull[3]);
+                               swap(normals[2], normals[3]);
 
-                       swap(hull[2], hull[3]);
-                       swap(normals[2], normals[3]);
+                               subpatch.patch = &quad_patch;
+                       }
 
                        /* Quad faces need to be split at least once to line up 
with split ngons, we do this
                         * here in this manner because if we do it later edge 
factors may end up slightly off.
                         */
-                       QuadDice::SubPatch subpatch;
-                       subpatch.patch = &patch;
-
                        subpatch.P00 = make_float2(0.0f, 0.0f);
                        subpatch.P10 = make_float2(0.5f, 0.0f);
                        subpatch.P01 = make_float2(0.0f, 0.5f);
                        subpatch.P11 = make_float2(0.5f, 0.5f);
-                       split->split_quad(&patch, &subpatch);
+                       split->split_quad(subpatch.patch, &subpatch);
 
                        subpatch.P00 = make_float2(0.5f, 0.0f);
                        subpatch.P10 = make_float2(1.0f, 0.0f);
                        subpatch.P01 = make_float2(0.5f, 0.5f);
                        subpatch.P11 = make_float2(1.0f, 0.5f);
-                       split->split_quad(&patch, &subpatch);
+                       split->split_quad(subpatch.patch, &subpatch);
 
                        subpatch.P00 = make_float2(0.0f, 0.5f);
                        subpatch.P10 = make_float2(0.5f, 0.5f);
                        subpatch.P01 = make_float2(0.0f, 1.0f);
                        subpatch.P11 = make_float2(0.5f, 1.0f);
-                       split->split_quad(&patch, &subpatch);
+                       split->split_quad(subpatch.patch, &subpatch);
 
                        subpatch.P00 = make_float2(0.5f, 0.5f);
                        subpatch.P10 = make_float2(1.0f, 0.5f);
                        subpatch.P01 = make_float2(0.5f, 1.0f);
                        subpatch.P11 = make_float2(1.0f, 1.0f);
-                       split->split_quad(&patch, &subpatch);
+                       split->split_quad(subpatch.patch, &subpatch);
                }
                else {
                        /* ngon */
-                       float3 center_vert = make_float3(0.0f, 0.0f, 0.0f);
-                       float3 center_normal = make_float3(0.0f, 0.0f, 0.0f);
+#ifdef WITH_OPENSUBDIV
+                       if(subdivision_type == SUBDIVISION_CATMULL_CLARK) {
+                               OsdPatch patch(&osd_data);
 
-                       float inv_num_corners = 1.0f/float(face.num_corners);
-                       for(int corner = 0; corner < face.num_corners; 
corner++) {
-                               center_vert += 
verts[subd_face_corners[face.start_corner + corner]] * inv_num_corners;

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
https://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to