[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [12422] branches/qdune/blender/extern/ qdune: Support for creases in the subdivsion mesh code has been activated.

Alfredo de Greef eeshlo at yahoo.com
Mon Oct 29 03:26:17 CET 2007


Revision: 12422
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=12422
Author:   eeshlo
Date:     2007-10-29 03:26:17 +0100 (Mon, 29 Oct 2007)

Log Message:
-----------
Support for creases in the subdivsion mesh code has been activated.
While already coded more than a year ago, it was never used.
Fortunately it actually works...
Also added support for semi-sharp creases, which is another quick
inspired hack, but sofar it seems to work reasonably well.
It probably needs some tweaking to make it produce results similar
to Blender though, so it probably will be recoded at some point.
This is not yet usable from Blender, but for the standalone version
of QDune I added another example ribfile, see 'creasetest.rib' in
the ribs/ directory.

Modified Paths:
--------------
    branches/qdune/blender/extern/qdune/primitives/CCSubdivision.cpp
    branches/qdune/blender/extern/qdune/primitives/CCSubdivision.h
    branches/qdune/blender/extern/qdune/ribparse/RIB_parser.cpp
    branches/qdune/blender/extern/qdune/ribparse/ribInterface.cpp

Added Paths:
-----------
    branches/qdune/blender/extern/qdune/ribs/creasetest.rib

Modified: branches/qdune/blender/extern/qdune/primitives/CCSubdivision.cpp
===================================================================
--- branches/qdune/blender/extern/qdune/primitives/CCSubdivision.cpp	2007-10-28 22:27:07 UTC (rev 12421)
+++ branches/qdune/blender/extern/qdune/primitives/CCSubdivision.cpp	2007-10-29 02:26:17 UTC (rev 12422)
@@ -4,6 +4,9 @@
 ///
 /// Unlike most renderman compliant renderers, it also supports non-manifolds, just as Blender does.
 /// This does probably make it more complex than needed though (no nice half/winged-edge datastructures).
+/// (NOTE: the 'interpolateboundary' tag, unlike required by the RISpec,
+///        does *not* mark boundary edges as sharp, they are still subdivided.
+///        This is again needed so that results are the same as in Blender.)
 ///
 /// The general process is as follows:
 /// Initially the mesh will go through possibly two global direct subdivision iterations.
@@ -22,9 +25,13 @@
 /// there is no choice left but to dice them by explicit subdivision...
 /// hopefully this won't happen too often, since it is very slow...
 ///
-/// Support for creases is rudimentary, only perfectly sharp creases currently.
-/// However, while this code is almost more than a year old now, I never got around to even actually testing it...
-/// Well, it worked in the python script prototype anyway...
+/// Update: Added support for the crease tag (support for creases was already coded but not 'activated' yet).
+///         Also added support for semi-sharp creases by reducing the sharpness level by half each subdivision iteration.
+///         Though yet another quick hack, it seems to work reasonably well sofar.
+///         Unless the sharpness parameter is high enough that the crease will persist thoughout the subdiv process.
+///         This can cause significant patch cracks (not grids, it is really seems to be along the patch border).
+///         Maybe fix this by always setting sharpness to 0 for the final patch subdivision? TODO
+///         Of course, this is not really directly Blender compatible this way..
 ///
 /// It is all too much code, clumsy, slow and messy, but it works...
 /// A prime candidate for a complete rewrite, that's for sure...
@@ -45,7 +52,7 @@
 /// UPDATE: This does in fact work. While it does in quite a few cases considerably speed up everything and uses less memory too,
 ///         (suzgallery.rib almost twice as fast), this is unfortunately not always so, in other cases slightly more memory is used and rendering is a bit slower too.
 ///         So more work is needed to make this a possible good alternative method. TODO
-///         For now the code is disabled, to test this alternate method, uncomment line 84
+///         For now the code is disabled, to test this alternate method, uncomment the '#define SKIP_GLOBAL_SUBDIVISION' line below,
 ///
 /// If creases exist, then currently there is no other choice yet but to make it an explicit patch.
 /// This could however be optimized for the case that the patch is manifold,
@@ -99,7 +106,7 @@
 {\
 	unsigned int _idx1=_i1, _idx2=_i2;\
 	if (_idx1 > _idx2) SWAP(_idx1, _idx2);\
-	int e_idx = *edge_id.find(_idx1 + (uint64)_num_verts*_idx2);\
+	unsigned int e_idx = *edge_id.find(_idx1 + (uint64)_num_verts*_idx2);\
 	ccFace* f = &_face_list[_fc_idx];\
 	f->edges.push_back(e_idx);\
 	E = &_edge_list[e_idx];\
@@ -195,13 +202,6 @@
 		}
 	}
 
-	// check tags, only "interpolateboundary" flag for now
-	intpolBD = false;
-	if (ntags) {
-		if (!strcmp(tags[0], "interpolateboundary"))
-			intpolBD = true;
-	}
-
 	// init faces, and set face pointers in vert_list
 	int lv = 0;
 	face_list.resize(num_faces);
@@ -229,10 +229,41 @@
 		for (unsigned int vi=0; vi<nv; ++vi)
 			SET_EDGE(edge_list, fcverts[vi], fcverts[(vi+1) % nv], vert_list, face_list, vert_list.size(), fi);
 	}
-	// delete array pointers in edge_verts
+
+	// edges done, now can check tags for creases
+	// check tags, only "interpolateboundary" flag for now
+	intpolBD = false;
+	int ac = 0, fidx = 0, lastevi = 0;
+	if (ntags) {
+		for (int i=0; i<ntags; ++i) {
+			if (!strcmp(tags[i], "interpolateboundary"))
+				intpolBD = true;
+			if (!strcmp(tags[i], "crease")) {
+				const int numi = nargs[ac]; //, numf = nargs[ac+1];
+				for (int evi=lastevi; evi<(lastevi + numi - 1); ++evi) {
+					unsigned int idx1 = intargs[evi], idx2 = intargs[evi+1];
+					if (idx1 > idx2) SWAP(idx1, idx2);
+					unsigned int* e_idx = edge_id.find(idx1 + (uint64)num_verts*idx2);
+					if (e_idx == NULL)
+						printf("[ERROR] crease edge with incorrect vertex index? skipping...\n");
+					else if (floatargs[fidx] >= 1.f) {	// sharpness must be at least 1 to be considered a (semi) crease edge
+						ccEdge& edge = edge_list[*e_idx];
+						edge.flags |= SD_CREASE;
+						edge.sharpness = (unsigned short)floatargs[fidx];
+					}
+				}
+				lastevi += numi;
+				ac += 2;
+				fidx++;
+			}
+		}
+	}
+
+	// delete array pointers in edge_verts and set edge boundary flags
 	edge_verts.clear_delete();
 	setBoundaryFlags(edge_list);
 
+	// process any primitive variables
 	Primitive::initPrimVars(n, tokens, parms, num_faces, num_verts, num_verts, sum_faceverts);
 
 	// if we have s/t coords, set for each face.
@@ -558,12 +589,16 @@
 	unsigned int face_st = orig_numverts;
 	unsigned int edge_st = face_st + num_faces;
 
-	// set crease flag of new edge vertices
+	// set crease flag and sharpness of new edge vertices
 	// (needed for crease flag propagation in edge_list rebuild below)
 	int v_idx = edge_st;
-	for (EdgeIter e=edge_list.begin(); e!=edge_list.end(); ++e)
-		if (e->flags & SD_CREASE)
-			vert_list[v_idx++].flags |= SD_CREASE;
+	for (EdgeIter e=edge_list.begin(); e!=edge_list.end(); ++e, ++v_idx)
+		if ((e->flags & SD_CREASE) and (e->sharpness > 1)) {
+			vert_list[v_idx].flags |= SD_CREASE;
+			// As a quick hack for semisharp creases (which happens to work reasonably well), reduce the sharpness level by half.
+			// this assumes that rebuildLists() is always called after a subdivision and not at any other time
+			vert_list[v_idx].sharpness = e->sharpness >> 1;
+		}
 
 	// vertex index remap, only used if building from patch or 'interpolateboundary' tag not set
 	hashtable_t<int, int> vidx_rm;
@@ -758,9 +793,9 @@
 			SET_EDGE(edge_list, idx3, idx4, vert_list, face_list, num_verts, nfi);  ed3 = E;
 			SET_EDGE(edge_list, idx4, idx1, vert_list, face_list, num_verts, nfi);
 			nfi++;
-			// pass on the crease flags, new edge verts have the crease flag set temporarily above
-			if (vert_list[idx2].flags & SD_CREASE) ed2->flags |= SD_CREASE;
-			if (vert_list[idx4].flags & SD_CREASE) ed3->flags |= SD_CREASE;
+			// pass on the crease flags and sharpness value, new edge verts have the crease flag/sharpness value set temporarily above
+			if (vert_list[idx2].flags & SD_CREASE) { ed2->flags |= SD_CREASE;  ed2->sharpness = vert_list[idx2].sharpness; }
+			if (vert_list[idx4].flags & SD_CREASE) { ed3->flags |= SD_CREASE;  ed3->sharpness = vert_list[idx4].sharpness; }
 		}
 	}
 	setBoundaryFlags(edge_list);
@@ -1795,7 +1830,8 @@
 		ccEdge* E;
 		const unsigned int i1 = *new_idx.find(e->v1), i2 = *new_idx.find(e->v2);
 		SET_EDGE(patch_edges, i1, i2, patch_verts, patch_faces, num_patch_verts, 0);
-		E->flags = e->flags;  // copy flags
+		E->flags = e->flags;  // copy flags & sharpness value
+		E->sharpness = e->sharpness;
 	}
 	// ring edges
 	for (unsigned int fi=0; fi<ring.size(); ++fi) {
@@ -1805,7 +1841,8 @@
 			ccEdge* E;
 			const unsigned int i1 = *new_idx.find(e->v1), i2 = *new_idx.find(e->v2), fi1 = fi + 1;
 			SET_EDGE(patch_edges, i1, i2, patch_verts, patch_faces, num_patch_verts, fi1);
-			E->flags = e->flags;  // copy flags
+			E->flags = e->flags;  // copy flags & sharpness value
+			E->sharpness = e->sharpness;
 		}
 	}
 
@@ -2389,7 +2426,7 @@
 {
 	// u & v *have* to be clamped to 0-1 range, otherwise will crash (out of range in LUT)
 	// update: u & v now can be 0 due to eval. modification, see below
-	double u = CLAMP((double)uf, 0.0, 1.0), v = CLAMP((double)vf, 0.0, 1.0);
+	double u = CLAMP((double)uf, 1e-5, 1.0), v = CLAMP((double)vf, 1e-5, 1.0);
 	bool eop = ((u == 0.0) && (v == 0.0));
 	// determine in which domain omega_nk the parameter lies
 	//const int n = int(floor(MIN2(-log2(u), -log2(v))) + 1); // can be replaced by integer log2(1/x) (roundup)

Modified: branches/qdune/blender/extern/qdune/primitives/CCSubdivision.h
===================================================================
--- branches/qdune/blender/extern/qdune/primitives/CCSubdivision.h	2007-10-28 22:27:07 UTC (rev 12421)
+++ branches/qdune/blender/extern/qdune/primitives/CCSubdivision.h	2007-10-29 02:26:17 UTC (rev 12422)
@@ -20,19 +20,20 @@
                  SD_CREASE_EQ_BOUND = 16, SD_SUPPORTVERTEX = 32,
                  SD_ALLQUAD = 64, SD_ONE_EOV = 128,	// these only used for the skip-global-subdivision alternate method
                  SD_NOTSET = 256};
-typedef int sdFlags;
+typedef short sdFlags;
 
 struct ccEdge;
 struct ccFace;
 struct ccVert
 {
 	ccVert() : flags(SD_UNDEFINED) {}
-	ccVert(const ccVert& cv) : co(cv.co), edges(cv.edges), faces(cv.faces), flags(cv.flags) {}
+	ccVert(const ccVert& cv) : co(cv.co), edges(cv.edges), faces(cv.faces), sharpness(cv.sharpness), flags(cv.flags) {}
 	ccVert& operator=(const ccVert& cv)
 	{
 		co = cv.co;
 		edges = cv.edges;
 		faces = cv.faces;
+		sharpness = cv.sharpness;
 		flags = cv.flags;
 		return *this;
 	}
@@ -41,24 +42,27 @@
 	// face references
 	// (not strictly necessary, can get from edges, uses slightly less memory too, but makes things simpler)
 	array_t<ccFace*> faces;
+	unsigned short sharpness;	// only needed to pass on to edge, see code
 	sdFlags flags;
 };
 
 struct ccEdge
 {
-	ccEdge() : v1(NULL), v2(NULL), new_vert(NULL), flags(SD_UNDEFINED) {}
-	ccEdge(const ccEdge& ce) : v1(ce.v1), v2(ce.v2), new_vert(ce.new_vert), faces(ce.faces), flags(ce.flags) {}
+	ccEdge() : v1(NULL), v2(NULL), new_vert(NULL), sharpness(0), flags(SD_UNDEFINED) {}
+	ccEdge(const ccEdge& ce) : v1(ce.v1), v2(ce.v2), new_vert(ce.new_vert), faces(ce.faces), sharpness(ce.sharpness), flags(ce.flags) {}
 	ccEdge& operator=(const ccEdge& ce)
 	{
 		v1 = ce.v1;
 		v2 = ce.v2;
 		new_vert = ce.new_vert;
 		faces = ce.faces;
+		sharpness = ce.sharpness;
 		flags = ce.flags;
 		return *this;
 	}
 	ccVert *v1, *v2, *new_vert; // edge vertex references
 	array_t<ccFace*> faces;

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list