[Bf-blender-cvs] [c78414c] temp-cycles-microdisplacement: Add basic OpenSubDiv support

Mai Lavelle noreply at git.blender.org
Tue Apr 12 18:45:49 CEST 2016


Commit: c78414cefaa208a65184362736b783c37e7a6f5f
Author: Mai Lavelle
Date:   Sun Jan 31 22:03:00 2016 -0500
Branches: temp-cycles-microdisplacement
https://developer.blender.org/rBc78414cefaa208a65184362736b783c37e7a6f5f

Add basic OpenSubDiv support

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

M	intern/cycles/blender/blender_mesh.cpp
M	intern/cycles/render/CMakeLists.txt
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 b075bfb..410d520 100644
--- a/intern/cycles/blender/blender_mesh.cpp
+++ b/intern/cycles/blender/blender_mesh.cpp
@@ -677,6 +677,7 @@ static void create_subd_mesh(Scene *scene,
                              bool preview)
 {
 	Mesh *basemesh = new Mesh();
+	basemesh->subdivision_type = (Mesh::SubdivisionType)RNA_enum_get(cmesh, "subdivision_type");
 	create_mesh(scene, basemesh, b_mesh, used_shaders, true);
 
 	SubdParams sdparams(mesh, used_shaders[0], true, false);
diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt
index ab0e571..1783c8c 100644
--- a/intern/cycles/render/CMakeLists.txt
+++ b/intern/cycles/render/CMakeLists.txt
@@ -12,6 +12,7 @@ set(INC
 
 set(INC_SYS
 	${GLEW_INCLUDE_DIR}
+	${OPENSUBDIV_INCLUDE_DIR}
 )
 
 set(SRC
diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp
index aa862d1..2a059a0 100644
--- a/intern/cycles/render/mesh.cpp
+++ b/intern/cycles/render/mesh.cpp
@@ -85,6 +85,7 @@ Mesh::Mesh()
 	motion_steps = 3;
 	use_motion_blur = false;
 
+	subdivision_type = SUBDIVISION_NONE;
 	displacement_scale = 1.0f;
 
 	bvh = NULL;
@@ -100,11 +101,14 @@ Mesh::Mesh()
 
 	has_volume = false;
 	has_surface_bssrdf = false;
+
+	osd_data = NULL;
 }
 
 Mesh::~Mesh()
 {
 	delete bvh;
+	free_osd_data();
 }
 
 void Mesh::reserve(int numverts, int numtris, int numcurves, int numcurvekeys, int numpatches)
@@ -140,6 +144,7 @@ void Mesh::clear()
 	curves.clear();
 
 	patches.clear();
+	free_osd_data();
 
 	attributes.clear();
 	curve_attributes.clear();
diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h
index 188fedd..89233fe 100644
--- a/intern/cycles/render/mesh.h
+++ b/intern/cycles/render/mesh.h
@@ -40,6 +40,7 @@ class Progress;
 class Scene;
 class SceneParams;
 class AttributeRequest;
+class MeshOsdData;
 
 /* Mesh */
 
@@ -103,6 +104,14 @@ public:
 		DISPLACE_NUM_METHODS,
 	};
 
+	enum SubdivisionType {
+		SUBDIVISION_NONE,
+		SUBDIVISION_LINEAR,
+		SUBDIVISION_CATMALL_CLARK,
+	};
+
+	SubdivisionType subdivision_type;
+
 	ustring name;
 
 	/* Mesh Data */
@@ -128,6 +137,7 @@ public:
 
 	vector<Patch> patches;
 	vector<SubPatch> subpatches;
+	MeshOsdData* osd_data;
 
 	vector<uint> used_shaders;
 	AttributeSet attributes;
@@ -198,6 +208,9 @@ public:
 	/* Check if the mesh should be treated as instanced. */
 	bool is_instanced() const;
 
+	void update_osd();
+	void free_osd_data();
+
 	void dice_subpatch(int p, SubdParams& params);
 	void tessellate(DiagSplit *split);
 };
diff --git a/intern/cycles/render/mesh_subdivision.cpp b/intern/cycles/render/mesh_subdivision.cpp
index 4409682..6c650f8 100644
--- a/intern/cycles/render/mesh_subdivision.cpp
+++ b/intern/cycles/render/mesh_subdivision.cpp
@@ -14,6 +14,13 @@
  * limitations under the License.
  */
 
+
+#include <opensubdiv/far/topologyDescriptor.h>
+#include <opensubdiv/far/primvarRefiner.h>
+#include <opensubdiv/far/patchTableFactory.h>
+#include <opensubdiv/far/patchMap.h>
+#include <opensubdiv/far/ptexIndices.h>
+
 #include "bvh.h"
 #include "bvh_build.h"
 
@@ -38,8 +45,206 @@
 #include "../subd/subd_split.h"
 #include "../subd/subd_patch.h"
 
+using namespace OpenSubdiv;
+
 CCL_NAMESPACE_BEGIN
 
+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;
+	}
+};
+
+struct MeshOsdData {
+	Far::PatchTable* patch_table;
+	Far::PatchMap* patch_map;
+	Far::PtexIndices* ptex_indices;
+	vector<OsdVertex> verts;
+
+	vector<int> num_verts_per_face;
+	vector<int> face_verts;
+};
+
+void Mesh::free_osd_data()
+{
+	if(!osd_data)
+		return;
+
+	delete osd_data->patch_table;
+	delete osd_data->patch_map;
+	delete osd_data->ptex_indices;
+
+	delete osd_data;
+	osd_data = NULL;
+}
+
+void Mesh::update_osd()
+{
+	assert(!osd_data);
+
+	if(subdivision_type != Mesh::SUBDIVISION_CATMALL_CLARK)
+		return;
+
+	osd_data = new MeshOsdData;
+
+	Sdc::SchemeType type = Sdc::SCHEME_CATMARK;
+
+	Sdc::Options options;
+	options.SetVtxBoundaryInterpolation(Sdc::Options::VTX_BOUNDARY_EDGE_ONLY);
+
+	Far::TopologyDescriptor desc;
+	desc.numVertices = verts.size();
+	desc.numFaces = patches.size();
+
+	size_t num_face_verts = 0;
+	osd_data->num_verts_per_face.resize(patches.size());
+
+	for(int i = 0; i < patches.size(); i++) {
+		osd_data->num_verts_per_face[i] = patches[i].is_quad() ? 4 : 3;
+		num_face_verts += osd_data->num_verts_per_face[i];
+	}
+
+	desc.numVertsPerFace = &osd_data->num_verts_per_face[0];
+
+	osd_data->face_verts.resize(num_face_verts);
+
+	int* fv = &osd_data->face_verts[0];
+	for(int i = 0; i < patches.size(); i++) {
+		Patch& patch = patches[i];
+
+		if(patch.is_quad()) {
+			*fv++ = patch.v[0];
+			*fv++ = patch.v[1];
+			*fv++ = patch.v[2];
+			*fv++ = patch.v[3];
+		}
+		else {
+			*fv++ = patch.v[0];
+			*fv++ = patch.v[1];
+			*fv++ = patch.v[2];
+		}
+	}
+
+	desc.vertIndicesPerFace = &osd_data->face_verts[0];
+
+	Far::TopologyRefiner* refiner = Far::TopologyRefinerFactory<Far::TopologyDescriptor>::Create(
+		desc, Far::TopologyRefinerFactory<Far::TopologyDescriptor>::Options(type, options));
+
+	int max_isolation = 10;
+	refiner->RefineAdaptive(Far::TopologyRefiner::AdaptiveOptions(max_isolation));
+
+	Far::PatchTableFactory::Options patch_options;
+	patch_options.endCapType = Far::PatchTableFactory::Options::ENDCAP_GREGORY_BASIS;
+
+	osd_data->patch_table = Far::PatchTableFactory::Create(*refiner, patch_options);
+
+	int num_refiner_verts = refiner->GetNumVerticesTotal();
+	int num_local_points = osd_data->patch_table->GetNumLocalPoints();
+
+	osd_data->verts.resize(num_refiner_verts + num_local_points);
+	for(int i = 0; i < verts.size(); i++) {
+		osd_data->verts[i].v = verts[i];
+	}
+
+	OsdVertex* src = &osd_data->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;
+	}
+
+	osd_data->patch_table->ComputeLocalPointValues(&osd_data->verts[0], &osd_data->verts[num_refiner_verts]);
+
+	osd_data->patch_map = new Far::PatchMap(*osd_data->patch_table);
+	osd_data->ptex_indices = new Far::PtexIndices(*refiner);
+}
+
+struct OsdPatch : Patch {
+	Mesh* mesh;
+	int patch;
+
+	void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v)
+	{
+		int patch_ = patch;
+		patch_uv_to_ptex_uv(patch_, u, v);
+
+		const Far::PatchTable::PatchHandle* handle = mesh->osd_data->patch_map->FindPatch(patch_, u, v);
+		assert(handle);
+
+		float p_weights[20], du_weights[20], dv_weights[20];
+		mesh->osd_data->patch_table->EvaluateBasis(*handle, u, v, p_weights, du_weights, dv_weights);
+
+		Far::ConstIndexArray cv = mesh->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 = mesh->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));
+	}
+
+	void patch_uv_to_ptex_uv(int& patch, float& u, float& v)
+	{
+		bool is_quad = mesh->patches[patch].is_quad();
+		patch = mesh->osd_data->ptex_indices->GetFaceId(patch);
+
+		if(!is_quad) {
+			float w = 1.0f - u - v;
+
+			int quad = util_max_axis(make_float3(u, v, w));
+			patch += quad;
+
+			float u_, v_;
+
+			switch(quad) {
+				case 0: { u_ = v; v_ = w; break; }
+				case 1: { u_ = w; v_ = u; break; }
+				case 2: { u_ = u; v_ = v; break; }
+				default: assert(0);
+			}
+
+			u_ *= 2.0f;
+			v_ *= 2.0f;
+
+			float s = sqrtf(u_*u_ + v_*v_ - 2.0f*u_*v_ - 6.0f*u_ - 6.0f*v_ + 9.0f);
+
+			u = u_ - v_ + s - 3.0f;
+			if(fabsf(u) > 0.000001f)
+				u = clamp(3.0f*(u_ + v_ + s - 3.0f)/u, 0.0f, 1.0f);
+			else
+				u = u_;
+
+			v = v_ - u_ + s - 3.0f;
+			if(fabsf(v) > 0.000001f)
+				v = clamp(3.0f*(v_ + u_ + s - 3.0f)/v, 0.0f, 1.0f);
+			else
+				v = v_;
+		}
+	}
+
+	bool is_triangle() { return !mesh->patches[patch].is_quad(); }
+	BoundBox bound() { return BoundBox::empty; }
+};
+
 static float3 patch_normal(Mesh* mesh, int patch) {
 	Mesh::Patch& t = mesh->patches[patch];
 
@@ -63,50 +268,56 @@ void Mesh::dice_subpatch(int subpatch_id, SubdParams& params)
 
 	params.shader = patches[subpatches[p].patch].shader;
 
+	OsdPatch osd_patch;
 	LinearQuadPatch quad_patch;
 	LinearTrianglePatch tri_patch;
 	ccl::Patch* subd_patch;
 
-	//Attribute *attr_vF = attributes.find(ATTR_STD_FACE_NORMAL);
-	//float3 *vF = attr_vF->data_float3();
+	if(subdivision_type == SUBDIVISION_CATMALL_CLARK) {
+		osd_patch.mesh = this;
+		osd_patch.patch = subpatches[subpatch_id].patch;
 
-	Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL);
-	float3 *vN = attr_vN->data_float3();
-
-	if(patch.is_quad()) {
-		for(int i = 0; i < 4; i++) {
-			quad_patch.hull[i] = verts[patch.v[i]];
-		}
+		subd_patch = &osd_patch;
+	}
+	else {
+		Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL);
+		float3 *vN = attr_vN->data_float3();
 
-		if(patch.smooth) {
-			for(int i = 0; i < 4; i++)
-				quad_patch.normals[i] = vN[patch.v[i]];
-		}
-		else {
-			for(int i = 0; i < 4; i++)
-				quad_patch.normals[i] = patch_normal(this, subpatch.patch);
-		}
+		if(patch.is_quad()) {
+			for(int i = 0; i < 4; i++) {
+				quad_patch.hull[i] = verts[patch.v[i]];
+			}
 
-		swap(quad_patch.hull[2], quad_patch.hull[3]);
-		swap(quad_patch.normals[2], quad_patch.normals[3]);
+			if(patch.smooth) {
+				for(int i = 0; i < 4; i++)
+					quad_patch.normals[i] = vN[patch.v[i]];
+			}
+			else {
+				for(int i = 0; i < 4; i++)
+					quad_patch.normals[i] = patch_normal(this, subpatch.patch);
+			}
 
-		subd_patch = &quad_patch;
-	}
-	else {
-		for(int i = 0; i < 3; i++) {
-			tri_patch.hull[i] = verts[patch.v[i]];
-		}
+			swap(quad_patch.hull[2], quad_patch.hull[3]);
+			swap(quad_patch.normals[2], quad_patch.normals[3]);
 
-		if(patch.smooth) {
-			for(int i = 0; i < 3; i++)
-				tri_

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list