/* * @author zz85 / http://twitter.com/blurspline / http://www.lab4games.net/zz85/blog * * Subdivision Geometry Modifier * using Catmull-Clark Subdivision Surfaces * for creating smooth geometry meshes * * Note: a modifier modifies vertices and faces of geometry, * so use THREE.GeometryUtils.clone() if orignal geoemtry needs to be retained * * Readings: * http://en.wikipedia.org/wiki/Catmull%E2%80%93Clark_subdivision_surface * 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 ) { this.subdivisions = (subdivisions === undefined ) ? 1 : subdivisions; // Settings this.useOldVertexColors = false; this.supportUVs = true; this.debug = false; }; //THREE.SubdivisionModifier.prototype = new THREE.Modifier(); THREE.SubdivisionModifier.prototype.constructor = THREE.SubdivisionModifier; // Applies the "modify" pattern THREE.SubdivisionModifier.prototype.modify = function ( geometry ) { var repeats = this.subdivisions; while ( repeats-- > 0 ) { this.smooth( geometry ); } }; // Performs an iteration of Catmull-Clark Subdivision THREE.SubdivisionModifier.prototype.smooth = function ( oldGeometry ) { //debug( 'running smooth' ); // New set of vertices, faces and uvs var newVertices = [], newFaces = [], newUVs = []; function v( x, y, z ) { newVertices.push( new THREE.Vector3( x, y, z ) ); } var scope = this; function debug() { if (scope.debug) console.log.apply(console, arguments); } function warn() { if (console) console.log.apply(console, arguments); } function f4( a, b, c, d, oldFace, orders, facei ) { // TODO move vertex selection over here! var newFace = new THREE.Face4( a, b, c, d, null, oldFace.color, oldFace.materialIndex ); if (scope.useOldVertexColors) { newFace.vertexColors = []; var color, tmpColor, order; for (var i=0;i<4;i++) { order = orders[i]; color = new THREE.Color(), color.setRGB(0,0,0); for (var j=0, jl=0; j face map for( i = 0, il = geometry.faces.length; i < il; i ++ ) { face = geometry.faces[ i ]; if ( face instanceof THREE.Face3 ) { hash = edge_hash( face.a, face.b ); mapEdgeHash( hash, i ); hash = edge_hash( face.b, face.c ); mapEdgeHash( hash, i ); hash = edge_hash( face.c, face.a ); mapEdgeHash( hash, i ); } else if ( face instanceof THREE.Face4 ) { hash = edge_hash( face.a, face.b ); mapEdgeHash( hash, i ); hash = edge_hash( face.b, face.c ); mapEdgeHash( hash, i ); hash = edge_hash( face.c, face.d ); mapEdgeHash( hash, i ); hash = edge_hash( face.d, face.a ); mapEdgeHash( hash, i ); } } // extract faces // var edges = []; // // var numOfEdges = 0; // for (i in edgeFaceMap) { // numOfEdges++; // // edge = edgeFaceMap[i]; // edges.push(edge); // // } //debug('edgeFaceMap', edgeFaceMap, 'geometry.edges',geometry.edges, 'numOfEdges', numOfEdges); return edgeFaceMap; } var originalPoints = oldGeometry.vertices; var originalFaces = oldGeometry.faces; var newPoints = originalPoints.concat(); // Vertices var facePoints = [], edgePoints = {}; var sharpEdges = {}, sharpVertices = [], sharpFaces = []; var uvForVertices = {}; // Stored in {vertex}:{old face} format var originalVerticesLength = originalPoints.length; function getUV(vertexNo, oldFaceNo) { var j,jl; var key = vertexNo+':'+oldFaceNo; var theUV = uvForVertices[key]; if (!theUV) { if (vertexNo>=originalVerticesLength && vertexNo < (originalVerticesLength + originalFaces.length)) { debug('face pt'); } else { debug('edge pt'); } warn('warning, UV not found for', key); return null; } return theUV; // Original faces -> Vertex Nos. // new Facepoint -> Vertex Nos. // edge Points } function addUV(vertexNo, oldFaceNo, value) { var key = vertexNo+':'+oldFaceNo; if (!(key in uvForVertices)) { uvForVertices[key] = value; } else { warn('dup vertexNo', vertexNo, 'oldFaceNo', oldFaceNo, 'value', value, 'key', key, uvForVertices[key]); } } // Step 1 // For each face, add a face point // Set each face point to be the centroid of all original points for the respective face. // debug(oldGeometry); var i, il, j, jl, face; // For Uvs var uvs = oldGeometry.faceVertexUvs[0]; var abcd = 'abcd', vertice; debug('originalFaces, uvs, originalVerticesLength', originalFaces.length, uvs.length, originalVerticesLength); if (scope.supportUVs) for (i=0, il = uvs.length; i Faces Index var edge, faceIndexA, faceIndexB, avg; // debug('edgeFaceMap', edgeFaceMap); var edgeCount = 0; var edgeVertex, edgeVertexA, edgeVertexB; //// var vertexEdgeMap = {}; // Gives edges connecting from each vertex var vertexFaceMap = {}; // Gives faces connecting from each vertex function addVertexEdgeMap(vertex, edge) { if (vertexEdgeMap[vertex]===undefined) { vertexEdgeMap[vertex] = []; } vertexEdgeMap[vertex].push(edge); } function addVertexFaceMap(vertex, face, edge) { if (vertexFaceMap[vertex]===undefined) { vertexFaceMap[vertex] = {}; } vertexFaceMap[vertex][face] = edge; // vertexFaceMap[vertex][face] = null; } // Prepares vertexEdgeMap and vertexFaceMap for (i in edgeFaceMap) { // This is for every edge edge = edgeFaceMap[i]; edgeVertex = i.split('_'); edgeVertexA = edgeVertex[0]; edgeVertexB = edgeVertex[1]; // Maps an edgeVertex to connecting edges addVertexEdgeMap(edgeVertexA, [edgeVertexA, edgeVertexB] ); addVertexEdgeMap(edgeVertexB, [edgeVertexA, edgeVertexB] ); for (j=0,jl=edge.length;j2) { // TODO } */ F.divideScalar(f); for (j=0; j