Browse Source

Fixed sharp corners for Subdivision Modifier

zz85 14 years ago
parent
commit
522fa70a22
1 changed files with 129 additions and 57 deletions
  1. 129 57
      src/extras/modifiers/SubdivisionModifier.js

+ 129 - 57
src/extras/modifiers/SubdivisionModifier.js

@@ -11,6 +11,15 @@
  *	Readings: 
  *	Readings: 
  *		http://en.wikipedia.org/wiki/Catmull%E2%80%93Clark_subdivision_surface
  *		http://en.wikipedia.org/wiki/Catmull%E2%80%93Clark_subdivision_surface
  *		http://www.rorydriscoll.com/2008/08/01/catmull-clark-subdivision-the-basics/
  *		http://www.rorydriscoll.com/2008/08/01/catmull-clark-subdivision-the-basics/
+ *		http://xrt.wikidot.com/blog:31
+ *		"Subdivision Surfaces in Character Animation"
+ *
+ *	Supports:
+ *		Closed and Open geometries.
+ *
+ *	TODO: 
+ *		crease vertex and "semi-sharp" features
+ *		selective subdivision
  */
  */
 
 
 THREE.SubdivisionModifier = function( subdivisions ) {
 THREE.SubdivisionModifier = function( subdivisions ) {
@@ -186,6 +195,8 @@ THREE.SubdivisionModifier.prototype.smooth = function ( oldGeometry ) {
 		
 		
 	var facePoints = [], edgePoints = {};
 	var facePoints = [], edgePoints = {};
 	
 	
+	var sharpEdges = {}, sharpVertices = [], sharpFaces = [];
+	
 	var uvForVertices = [];
 	var uvForVertices = [];
 	
 	
 	// Step 1
 	// Step 1
@@ -253,6 +264,80 @@ THREE.SubdivisionModifier.prototype.smooth = function ( oldGeometry ) {
 	var edgeCount = 0;
 	var edgeCount = 0;
 	var originalVerticesLength = originalPoints.length;
 	var originalVerticesLength = originalPoints.length;
 	var edgeVertex, edgeVertexA, edgeVertexB;
 	var edgeVertex, edgeVertexA, edgeVertexB;
+	
+	////
+	
+	var vertexEdgeMap = {};
+	var vertexFaceMap = {};
+	
+	var addVertexEdgeMap = function(vertex, edge) {
+		if (vertexEdgeMap[vertex]===undefined) {
+			vertexEdgeMap[vertex] = [];
+		}
+		
+		vertexEdgeMap[vertex].push(edge);
+	};
+	
+	var addVertexFaceMap = function(vertex, face, edge) {
+		if (vertexFaceMap[vertex]===undefined) {
+			vertexFaceMap[vertex] = {};
+		}
+		
+		//vertexFaceMap[vertex][face] = edge;
+		vertexFaceMap[vertex][face] = null;
+	};
+	
+	// Prepares vertexEdgeMap and vertexFaceMap
+	for (i in vfMap) { // This is for every edge
+		edge = vfMap[i];
+		
+		edgeVertex = i.split('_');
+		edgeVertexA = edgeVertex[0];
+		edgeVertexB = edgeVertex[1];
+		
+		// Maps an edgeVertex to connecting edges
+		addVertexEdgeMap(edgeVertexA, [edgeVertexA, edgeVertexB] );
+		addVertexEdgeMap(edgeVertexB, [edgeVertexA, edgeVertexB] );
+		
+		
+		// faceIndexA = edge[0]; // face index a
+		// faceIndexB = edge[1]; // face index b
+		// 
+		// // Add connecting faces for edge
+		// addVertexFaceMap(edgeVertexA, faceIndexA);
+		// addVertexFaceMap(edgeVertexB, faceIndexA);
+		// 
+		// 
+		// if (faceIndexB) {
+		// 	addVertexFaceMap(edgeVertexA, faceIndexB);
+		// 	addVertexFaceMap(edgeVertexB, faceIndexB);
+		// } else {
+		// 	addVertexFaceMap(edgeVertexA, faceIndexA);
+		// 	addVertexFaceMap(edgeVertexB, faceIndexA);
+		// }
+		
+		for (j=0,jl=edge.length;j<jl;j++) {
+			face = edge[j];
+			
+			addVertexFaceMap(edgeVertexA, face, i);
+			addVertexFaceMap(edgeVertexB, face, i);
+		}
+		
+		if (edge.length < 2) {
+			// edge is "sharp";
+			sharpEdges[i] = true;
+			sharpVertices[edgeVertexA] = true;
+			sharpVertices[edgeVertexB] = true;
+			
+		}
+		
+	}
+	
+	
+	
+	//console.log('vertexEdgeMap',vertexEdgeMap, 'vertexFaceMap', vertexFaceMap);
+	
+	
 	for (i in vfMap) {
 	for (i in vfMap) {
 		edge = vfMap[i];
 		edge = vfMap[i];
 		
 		
@@ -268,14 +353,17 @@ THREE.SubdivisionModifier.prototype.smooth = function ( oldGeometry ) {
 		
 		
 		//console.log(i, faceIndexB,facePoints[faceIndexB]);
 		//console.log(i, faceIndexB,facePoints[faceIndexB]);
 		
 		
-		if (edge.length!=2) {
+		if (sharpEdges[i]) {
 			//console.log('warning, ', i, 'edge has only 1 connecting face', edge);
 			//console.log('warning, ', i, 'edge has only 1 connecting face', edge);
 			
 			
+			// For a sharp edge, average the edge end points.
 			avg.addSelf(originalPoints[edgeVertexA].position);
 			avg.addSelf(originalPoints[edgeVertexA].position);
 			avg.addSelf(originalPoints[edgeVertexB].position);
 			avg.addSelf(originalPoints[edgeVertexB].position);
 			
 			
 			avg.multiplyScalar(0.5);
 			avg.multiplyScalar(0.5);
 			
 			
+			sharpVertices[newPoints.length] = true;
+			
 		} else {
 		} else {
 		
 		
 			avg.addSelf(facePoints[faceIndexA]);
 			avg.addSelf(facePoints[faceIndexA]);
@@ -289,6 +377,7 @@ THREE.SubdivisionModifier.prototype.smooth = function ( oldGeometry ) {
 		}
 		}
 		
 		
 		edgePoints[i] = originalVerticesLength + originalFaces.length + edgeCount;
 		edgePoints[i] = originalVerticesLength + originalFaces.length + edgeCount;
+		//console.log(edgePoints[i], newPoints.length);
 		
 		
 		newPoints.push( new THREE.Vertex(avg) );
 		newPoints.push( new THREE.Vertex(avg) );
 	
 	
@@ -318,6 +407,14 @@ THREE.SubdivisionModifier.prototype.smooth = function ( oldGeometry ) {
 	
 	
 	var hashAB, hashBC, hashCD, hashDA, hashCA;
 	var hashAB, hashBC, hashCD, hashDA, hashCA;
 	
 	
+	var abc123 = ['123', '12', '2', '23'];
+	var bca123 = ['123', '23', '3', '31'];
+	var cab123 = ['123', '31', '1', '12'];
+	var abc1234 = ['1234', '12', '2', '23'];
+	var bcd1234 = ['1234', '23', '3', '34'];
+	var cda1234 = ['1234', '34', '4', '41'];
+	var dab1234 = ['1234', '41', '1', '12'];
+	
 	
 	
 	for (i=0, il = facePoints.length; i<il ;i++) { // for every face
 	for (i=0, il = facePoints.length; i<il ;i++) { // for every face
 		facePt = facePoints[i];
 		facePt = facePoints[i];
@@ -332,9 +429,9 @@ THREE.SubdivisionModifier.prototype.smooth = function ( oldGeometry ) {
 			hashBC = edge_hash( face.b, face.c );
 			hashBC = edge_hash( face.b, face.c );
 			hashCA = edge_hash( face.c, face.a );
 			hashCA = edge_hash( face.c, face.a );
 			
 			
-			f4( currentVerticeIndex, edgePoints[hashAB], face.b, edgePoints[hashBC], face, ['123', '12', '2', '23'] );
-			f4( currentVerticeIndex, edgePoints[hashBC], face.c, edgePoints[hashCA], face, ['123', '23', '3', '31'] );
-			f4( currentVerticeIndex, edgePoints[hashCA], face.a, edgePoints[hashAB], face, ['123', '31', '1', '12'] );
+			f4( currentVerticeIndex, edgePoints[hashAB], face.b, edgePoints[hashBC], face, abc123 );
+			f4( currentVerticeIndex, edgePoints[hashBC], face.c, edgePoints[hashCA], face, bca123 );
+			f4( currentVerticeIndex, edgePoints[hashCA], face.a, edgePoints[hashAB], face, cab123 );
 			
 			
 		} else if ( face instanceof THREE.Face4 ) {
 		} else if ( face instanceof THREE.Face4 ) {
 			// create 4 face4s
 			// create 4 face4s
@@ -344,10 +441,10 @@ THREE.SubdivisionModifier.prototype.smooth = function ( oldGeometry ) {
 			hashCD = edge_hash( face.c, face.d );
 			hashCD = edge_hash( face.c, face.d );
 			hashDA = edge_hash( face.d, face.a );
 			hashDA = edge_hash( face.d, face.a );
 			
 			
-			f4( currentVerticeIndex, edgePoints[hashAB], face.b, edgePoints[hashBC], face, ['1234', '12', '2', '23']  );
-			f4( currentVerticeIndex, edgePoints[hashBC], face.c, edgePoints[hashCD], face, ['1234', '23', '3', '34']  );
-			f4( currentVerticeIndex, edgePoints[hashCD], face.d, edgePoints[hashDA], face, ['1234', '34', '4', '41']  );
-			f4( currentVerticeIndex, edgePoints[hashDA], face.a, edgePoints[hashAB], face, ['1234', '41', '1', '12']  );
+			f4( currentVerticeIndex, edgePoints[hashAB], face.b, edgePoints[hashBC], face, abc1234 );
+			f4( currentVerticeIndex, edgePoints[hashBC], face.c, edgePoints[hashCD], face, bcd1234 );
+			f4( currentVerticeIndex, edgePoints[hashCD], face.d, edgePoints[hashDA], face, cda1234 );
+			f4( currentVerticeIndex, edgePoints[hashDA], face.a, edgePoints[hashAB], face, dab1234  );
 
 
 				
 				
 		} else {
 		} else {
@@ -367,53 +464,7 @@ THREE.SubdivisionModifier.prototype.smooth = function ( oldGeometry ) {
 	//		and take the average R of all n edge midpoints for edges touching P, 
 	//		and take the average R of all n edge midpoints for edges touching P, 
 	//		where each edge midpoint is the average of its two endpoint vertices. 
 	//		where each edge midpoint is the average of its two endpoint vertices. 
 	//	Move each original point to the point
 	//	Move each original point to the point
-	
-	
-	
-	var vertexEdgeMap = {};
-	var vertexFaceMap = {};
-	
-	var addVertexEdgeMap = function(vertex, edge) {
-		if (vertexEdgeMap[vertex]===undefined) {
-			vertexEdgeMap[vertex] = [];
-		}
-		
-		vertexEdgeMap[vertex].push(edge);
-	};
-	
-	var addVertexFaceMap = function(vertex, face) {
-		if (vertexFaceMap[vertex]===undefined) {
-			vertexFaceMap[vertex] = {};
-		}
-		
-		vertexFaceMap[vertex][face] = null;
-	};
-	
-	// Prepares vertexEdgeMap and vertexFaceMap
-	for (i in vfMap) { // This is for every edge
-		edge = vfMap[i];
-		
-		edgeVertex = i.split('_');
-		edgeVertexA = edgeVertex[0];
-		edgeVertexB = edgeVertex[1];
-		
-		addVertexEdgeMap(edgeVertexA, [edgeVertexA, edgeVertexB] );
-		addVertexEdgeMap(edgeVertexB, [edgeVertexA, edgeVertexB] );
-		
-		faceIndexA = edge[0]; // face index a
-		faceIndexB = edge[1]; // face index b
-		
-		addVertexFaceMap(edgeVertexA, faceIndexA);
-		if (faceIndexB) addVertexFaceMap(edgeVertexA, faceIndexB);
-		else addVertexFaceMap(edgeVertexA, faceIndexA);
-		
-		addVertexFaceMap(edgeVertexB, faceIndexA);
-		if (faceIndexB) addVertexFaceMap(edgeVertexB, faceIndexB);
-		else addVertexFaceMap(edgeVertexB, faceIndexA);
-		
-	}
-	
-	//console.log('vertexEdgeMap',vertexEdgeMap, 'vertexFaceMap', vertexFaceMap);
+
 	
 	
 	var F = new THREE.Vector3();
 	var F = new THREE.Vector3();
 	var R = new THREE.Vector3();
 	var R = new THREE.Vector3();
@@ -430,15 +481,36 @@ THREE.SubdivisionModifier.prototype.smooth = function ( oldGeometry ) {
 		
 		
 		var f =0;
 		var f =0;
 		for (j in vertexFaceMap[i]) {
 		for (j in vertexFaceMap[i]) {
-			
 			F.addSelf(facePoints[j]);
 			F.addSelf(facePoints[j]);
 			f++;
 			f++;
 		}
 		}
 		
 		
-		F.divideScalar(f);
+		var sharpEdgeCount = 0;
 		
 		
 		n = vertexEdgeMap[i].length;
 		n = vertexEdgeMap[i].length;
 		
 		
+		for (j=0;j<n;j++) {
+			if (
+				sharpEdges[
+					edge_hash(vertexEdgeMap[i][j][0],vertexEdgeMap[i][j][1])
+				]) {
+					sharpEdgeCount++;
+				}
+		}
+		
+		if ( sharpEdgeCount==2 ) {
+			continue;
+			// Do not move vertex if there's 2 connecting sharp edges.
+		}
+		
+		if (sharpEdgeCount>2) {
+			
+		}
+		
+		F.divideScalar(f);
+		
+		
+		
 		for (j=0; j<n;j++) {
 		for (j=0; j<n;j++) {
 			edge = vertexEdgeMap[i][j];
 			edge = vertexEdgeMap[i][j];
 			var midPt = originalPoints[edge[0]].position.clone().addSelf(originalPoints[edge[1]].position).divideScalar(2);
 			var midPt = originalPoints[edge[0]].position.clone().addSelf(originalPoints[edge[1]].position).divideScalar(2);