[Bf-blender-cvs] [f0f60d7] master: OpenSubdiv: Initial work to support UV maps in textured OSD viewport

Sergey Sharybin noreply at git.blender.org
Wed Jul 20 14:40:57 CEST 2016


Commit: f0f60d775def20ff3a3699704b33c66712d50c6a
Author: Sergey Sharybin
Date:   Tue Jul 19 09:28:54 2016 +0200
Branches: master
https://developer.blender.org/rBf0f60d775def20ff3a3699704b33c66712d50c6a

OpenSubdiv: Initial work to support UV maps in textured OSD viewport

A bit work in progress, currently the following limitations:

- Texture shading only, Material shading will come later

- No UVs subdivision yet

- Always uses active UV and currently changing active UV will
  not properly update the viewport.

Well, need to start somewhere :)

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

M	intern/opensubdiv/opensubdiv_capi.cc
M	intern/opensubdiv/opensubdiv_capi.h
M	intern/opensubdiv/opensubdiv_converter.cc
M	intern/opensubdiv/opensubdiv_converter_capi.h
M	intern/opensubdiv/opensubdiv_gpu_capi.cc
M	intern/opensubdiv/opensubdiv_topology_refiner.h
M	source/blender/blenkernel/intern/CCGSubSurf.c
M	source/blender/blenkernel/intern/CCGSubSurf_intern.h
M	source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
M	source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c
M	source/blender/blenkernel/intern/subsurf_ccg.c
M	source/blender/gpu/intern/gpu_codegen.c

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

diff --git a/intern/opensubdiv/opensubdiv_capi.cc b/intern/opensubdiv/opensubdiv_capi.cc
index 0463982..e04b237 100644
--- a/intern/opensubdiv/opensubdiv_capi.cc
+++ b/intern/opensubdiv/opensubdiv_capi.cc
@@ -67,6 +67,7 @@
 
 #include <opensubdiv/osd/glPatchTable.h>
 #include <opensubdiv/far/stencilTable.h>
+#include <opensubdiv/far/primvarRefiner.h>
 
 #include "opensubdiv_intern.h"
 #include "opensubdiv_topology_refiner.h"
@@ -143,11 +144,69 @@ typedef Mesh<GLVertexBuffer,
              GLPatchTable> OsdGLSLComputeMesh;
 #endif
 
+namespace {
+
+struct FVarVertex {
+	float u, v;
+	void Clear() {
+		u = v = 0.0f;
+	}
+	void AddWithWeight(FVarVertex const & src, float weight) {
+		u += weight * src.u;
+		v += weight * src.v;
+	}
+};
+
+static void interpolate_fvar_data(OpenSubdiv::Far::TopologyRefiner& refiner,
+                                  const std::vector<float> uvs,
+                                  std::vector<float> &fvar_data) {
+	/* TODO(sergey): Support all FVar channels. */
+	const int channel = 0;
+	/* TODO(sergey): Make it somehow more generic way. */
+	const int fvar_width = 2;
+
+	int max_level = refiner.GetMaxLevel(),
+	    num_values_max = refiner.GetLevel(max_level).GetNumFVarValues(channel),
+	    num_values_total = refiner.GetNumFVarValuesTotal(channel);
+	if (num_values_total <= 0) {
+		return;
+	}
+	OpenSubdiv::Far::PrimvarRefiner primvarRefiner(refiner);
+	if (refiner.IsUniform()) {
+		/* For uniform we only keep the highest level of refinement. */
+		fvar_data.resize(num_values_max * fvar_width);
+		std::vector<FVarVertex> buffer(num_values_total - num_values_max);
+		FVarVertex *src = &buffer[0];
+		memcpy(src, &uvs[0], uvs.size() * sizeof(float));
+		/* Defer the last level to treat separately with its alternate
+		 * destination.
+		 */
+		for (int level = 1; level < max_level; ++level) {
+			FVarVertex *dst = src + refiner.GetLevel(level-1).GetNumFVarValues(channel);
+			primvarRefiner.InterpolateFaceVarying(level, src, dst, channel);
+			src = dst;
+		}
+		FVarVertex *dst = reinterpret_cast<FVarVertex *>(&fvar_data[0]);
+		primvarRefiner.InterpolateFaceVarying(max_level, src, dst, channel);
+	} else {
+		/* For adaptive we keep all levels. */
+		fvar_data.resize(num_values_total * fvar_width);
+		FVarVertex *src = reinterpret_cast<FVarVertex *>(&fvar_data[0]);
+		memcpy(src, &uvs[0], uvs.size() * sizeof(float));
+		for (int level = 1; level <= max_level; ++level) {
+			FVarVertex *dst = src + refiner.GetLevel(level-1).GetNumFVarValues(channel);
+			primvarRefiner.InterpolateFaceVarying(level, src, dst, channel);
+			src = dst;
+        }
+    }
+}
+
+}  // namespace
+
 struct OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner(
         OpenSubdiv_TopologyRefinerDescr *topology_refiner,
         int evaluator_type,
-        int level,
-        int /*subdivide_uvs*/)
+        int level)
 {
 	using OpenSubdiv::Far::TopologyRefiner;
 
@@ -213,11 +272,21 @@ struct OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner(
 	gl_mesh->descriptor = (OpenSubdiv_GLMeshDescr *) mesh;
 	gl_mesh->topology_refiner = topology_refiner;
 
+	if (refiner->GetNumFVarChannels() > 0) {
+		std::vector<float> fvar_data;
+		interpolate_fvar_data(*refiner, topology_refiner->uvs, fvar_data);
+		openSubdiv_osdGLAllocFVar(gl_mesh, &fvar_data[0]);
+	}
+	else {
+		gl_mesh->fvar_data = NULL;
+	}
+
 	return gl_mesh;
 }
 
 void openSubdiv_deleteOsdGLMesh(struct OpenSubdiv_GLMesh *gl_mesh)
 {
+	openSubdiv_osdGLDestroyFVar(gl_mesh);
 	switch (gl_mesh->evaluator_type) {
 #define CHECK_EVALUATOR_TYPE(type, class) \
 		case OPENSUBDIV_EVALUATOR_ ## type: \
diff --git a/intern/opensubdiv/opensubdiv_capi.h b/intern/opensubdiv/opensubdiv_capi.h
index b40505b..0410083 100644
--- a/intern/opensubdiv/opensubdiv_capi.h
+++ b/intern/opensubdiv/opensubdiv_capi.h
@@ -32,16 +32,19 @@ extern "C" {
 
 // Types declaration.
 struct OpenSubdiv_GLMesh;
+struct OpenSubdiv_GLMeshFVarData;
 struct OpenSubdiv_TopologyRefinerDescr;
 
 typedef struct OpenSubdiv_GLMesh OpenSubdiv_GLMesh;
 
 #ifdef __cplusplus
 struct OpenSubdiv_GLMeshDescr;
+
 typedef struct OpenSubdiv_GLMesh {
 	int evaluator_type;
 	OpenSubdiv_GLMeshDescr *descriptor;
 	OpenSubdiv_TopologyRefinerDescr *topology_refiner;
+	OpenSubdiv_GLMeshFVarData *fvar_data;
 } OpenSubdiv_GLMesh;
 #endif
 
@@ -66,8 +69,7 @@ enum {
 OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner(
         struct OpenSubdiv_TopologyRefinerDescr *topology_refiner,
         int evaluator_type,
-        int level,
-        int subdivide_uvs);
+        int level);
 
 void openSubdiv_deleteOsdGLMesh(OpenSubdiv_GLMesh *gl_mesh);
 unsigned int openSubdiv_getOsdGLMeshPatchIndexBuffer(
@@ -129,8 +131,7 @@ void openSubdiv_evaluateVarying(OpenSubdiv_EvaluatorDescr *evaluator_descr,
  *
  * TODO(sergey): Some of the stuff could be initialized once for all meshes.
  */
-void openSubdiv_osdGLMeshDisplayPrepare(int use_osd_glsl,
-                                        int active_uv_index);
+void openSubdiv_osdGLMeshDisplayPrepare(int use_osd_glsl);
 
 /* Draw specified patches. */
 void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh,
@@ -138,6 +139,10 @@ void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh,
                                  int start_patch,
                                  int num_patches);
 
+void openSubdiv_osdGLAllocFVar(OpenSubdiv_GLMesh *gl_mesh,
+                               const float *fvar_data);
+void openSubdiv_osdGLDestroyFVar(OpenSubdiv_GLMesh *gl_mesh);
+
 /* ** Utility functions ** */
 int openSubdiv_supportGPUDisplay(void);
 int openSubdiv_getAvailableEvaluators(void);
diff --git a/intern/opensubdiv/opensubdiv_converter.cc b/intern/opensubdiv/opensubdiv_converter.cc
index e718d6b..e6c8985 100644
--- a/intern/opensubdiv/opensubdiv_converter.cc
+++ b/intern/opensubdiv/opensubdiv_converter.cc
@@ -488,6 +488,39 @@ inline void TopologyRefinerFactory<OpenSubdiv_Converter>::reportInvalidTopology(
 	printf("OpenSubdiv Error: %s\n", msg);
 }
 
+template <>
+inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignFaceVaryingTopology(
+        TopologyRefiner& refiner,
+        const OpenSubdiv_Converter& conv)
+{
+	if (conv.get_num_uv_layers(&conv) <= 0) {
+		/* No UV maps, we can skip any face-varying data. */
+		return true;
+	}
+	/* Count overall number of UV data.
+	 * NOTE: We only do single UV layer here, and we don't "merge" loops
+	 * together as it is done in OpenSubdiv examples.x
+	 */
+	const int num_faces = getNumBaseFaces(refiner);
+	int num_uvs = 0;
+	for (int face = 0; face < num_faces; ++face) {
+		IndexArray face_verts = getBaseFaceVertices(refiner, face);
+		num_uvs += face_verts.size();
+	}
+	/* Fill in actual UV offsets. */
+	const int channel = createBaseFVarChannel(refiner, num_uvs);
+	for (int face = 0, offset = 0; face < num_faces; ++face) {
+		Far::IndexArray dst_face_uvs = getBaseFaceFVarValues(refiner,
+		                                                     face,
+		                                                     channel);
+		for (int corner = 0; corner < dst_face_uvs.size(); ++corner) {
+			dst_face_uvs[corner] = offset;
+			++offset;
+		}
+	}
+	return true;
+}
+
 }  /* namespace Far */
 }  /* namespace OPENSUBDIV_VERSION */
 }  /* namespace OpenSubdiv */
@@ -508,6 +541,33 @@ OpenSubdiv::Sdc::SchemeType get_capi_scheme_type(OpenSubdiv_SchemeType type)
 	return OpenSubdiv::Sdc::SCHEME_CATMARK;
 }
 
+static void import_fvar_data(OpenSubdiv_TopologyRefinerDescr *result,
+                             const OpenSubdiv_Converter& conv)
+{
+	const int num_layers = conv.get_num_uv_layers(&conv),
+	          num_faces = conv.get_num_faces(&conv);
+	/* Pre-allocate values in one go. */
+	int num_fvar_values = 0;
+	for (int layer = 0; layer < num_layers; ++layer) {
+		num_fvar_values = result->osd_refiner->GetNumFVarValuesTotal();
+	}
+	result->uvs.resize(num_fvar_values * 2);
+	/* Fill in all channels. */
+	for (int layer = 0, offset = 0; layer < num_layers; ++layer) {
+		for (int face = 0; face < num_faces; ++face) {
+			const int num_verts = conv.get_num_face_verts(&conv, face);
+			for (int vert = 0; vert < num_verts; ++vert) {
+				float uv[2];
+				conv.get_face_corner_uv(&conv, face, vert, uv);
+				result->uvs[offset++] = uv[0];
+				result->uvs[offset++] = uv[1];
+			}
+		}
+		/* TODO(sergey): Currently we only support first layer only. */
+		break;
+	}
+}
+
 }  /* namespace */
 
 struct OpenSubdiv_TopologyRefinerDescr *openSubdiv_createTopologyRefinerDescr(
@@ -536,6 +596,18 @@ struct OpenSubdiv_TopologyRefinerDescr *openSubdiv_createTopologyRefinerDescr(
 	        TopologyRefinerFactory<OpenSubdiv_Converter>::Create(
 	                *converter,
 	                topology_options);
+
+	if (result->osd_refiner->GetNumFVarChannels() > 0) {
+		/* Import face varrying data now since later we wouldn't have
+		 * access to the converter.
+		 *
+		 * TODO(sergey): This is so-called "for now", for until we'll
+		 * find better way to plug OSD to Blender or for until something
+		 * happens inside of OSD API.
+		 */
+		import_fvar_data(result, *converter);
+	}
+
 	return result;
 }
 
diff --git a/intern/opensubdiv/opensubdiv_converter_capi.h b/intern/opensubdiv/opensubdiv_converter_capi.h
index 1f09fa0..47c8dab 100644
--- a/intern/opensubdiv/opensubdiv_converter_capi.h
+++ b/intern/opensubdiv/opensubdiv_converter_capi.h
@@ -83,6 +83,14 @@ typedef struct OpenSubdiv_Converter {
 	                       int vert,
 	                       int *vert_faces);
 
+	/* Face-varying data. */
+
+	int (*get_num_uv_layers)(const OpenSubdiv_Converter *converter);
+	void (*get_face_corner_uv)(const OpenSubdiv_Converter *converter,
+	                           int face,
+	                           int corner,
+	                           float r_uv[2]);
+
 	void (*free_user_data)(const OpenSubdiv_Converter *converter);
 	void *user_data;
 } OpenSubdiv_Converter;
diff --git a/intern/opensubdiv/opensubdiv_gpu_capi.cc b/intern/opensubdiv/opensubdiv_gpu_capi.cc
index 63cf390..84984e8 100644
--- a/intern/opensubdiv/opensubdiv_gpu_capi.cc
+++ b/intern/opensubdiv/opensubdiv_gpu_capi.cc
@@ -42,6 +42,10 @@
 #include <opensubdiv/osd/cpuGLVertexBuffer.h>
 #include <o

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list