[Bf-blender-cvs] [7e7eaf4] temp-cycles-microdisplacement: Initial OpenSubdiv support

Mai Lavelle noreply at git.blender.org
Sat Jun 25 15:51:19 CEST 2016


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. @@




More information about the Bf-blender-cvs mailing list