SubdivisionModifier.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. /*
  2. * @author zz85 / http://twitter.com/blurspline / http://www.lab4games.net/zz85/blog
  3. *
  4. * Subdivision Geometry Modifier
  5. * using Catmull-Clark Subdivision Surfaces
  6. * for creating smooth geometry meshes
  7. *
  8. * Note: a modifier modifies vertices and faces of geometry,
  9. * so use THREE.GeometryUtils.clone() if orignal geoemtry needs to be retained
  10. *
  11. * Readings:
  12. * http://en.wikipedia.org/wiki/Catmull%E2%80%93Clark_subdivision_surface
  13. * http://www.rorydriscoll.com/2008/08/01/catmull-clark-subdivision-the-basics/
  14. * http://xrt.wikidot.com/blog:31
  15. * "Subdivision Surfaces in Character Animation"
  16. *
  17. * Supports:
  18. * Closed and Open geometries.
  19. *
  20. * TODO:
  21. * crease vertex and "semi-sharp" features
  22. * selective subdivision
  23. */
  24. THREE.SubdivisionModifier = function( subdivisions ) {
  25. this.subdivisions = (subdivisions === undefined ) ? 1 : subdivisions;
  26. // Settings
  27. this.useOldVertexColors = false;
  28. this.supportUVs = true;
  29. };
  30. //THREE.SubdivisionModifier.prototype = new THREE.Modifier();
  31. THREE.SubdivisionModifier.prototype.constructor = THREE.SubdivisionModifier;
  32. // Applies the "modify" pattern
  33. THREE.SubdivisionModifier.prototype.modify = function ( geometry ) {
  34. var repeats = this.subdivisions;
  35. while ( repeats-- > 0 ) {
  36. this.smooth( geometry );
  37. }
  38. };
  39. // Performs an iteration of Catmull-Clark Subdivision
  40. THREE.SubdivisionModifier.prototype.smooth = function ( oldGeometry ) {
  41. //console.log( 'running smooth' );
  42. // New set of vertices, faces and uvs
  43. var newVertices = [], newFaces = [], newUVs = [];
  44. function v( x, y, z ) {
  45. newVertices.push( new THREE.Vertex( new THREE.Vector3( x, y, z ) ) );
  46. }
  47. var scope = this;
  48. function f4( a, b, c, d, oldFace, orders, facei ) {
  49. // TODO move vertex selection over here!
  50. var newFace = new THREE.Face4( a, b, c, d, null, oldFace.color, oldFace.material );
  51. if (scope.useOldVertexColors) {
  52. newFace.vertexColors = [];
  53. var color, tmpColor, order;
  54. for (var i=0;i<4;i++) {
  55. order = orders[i];
  56. color = new THREE.Color(),
  57. color.setRGB(0,0,0);
  58. for (var j=0, jl=0; j<order.length;j++) {
  59. tmpColor = oldFace.vertexColors[order[j]-1];
  60. color.r += tmpColor.r;
  61. color.g += tmpColor.g;
  62. color.b += tmpColor.b;
  63. }
  64. color.r /= order.length;
  65. color.g /= order.length;
  66. color.b /= order.length;
  67. newFace.vertexColors[i] = color;
  68. }
  69. }
  70. newFaces.push( newFace );
  71. if (scope.supportUVs) {
  72. newUVs.push( [
  73. getUV(a, ''),
  74. getUV(b, facei),
  75. getUV(c, facei),
  76. getUV(d, facei)
  77. ] );
  78. // if (!uvForVertices[a]) console.log('a', a+':'+facei);
  79. // if (!uvForVertices[b+':'+facei]) console.log('b', b+':'+facei);
  80. // if (!uvForVertices[c+':'+facei]) console.log('c', c+':'+facei);
  81. // if (!uvForVertices[d+':'+facei]) console.log('d', d+':'+facei);
  82. }
  83. }
  84. function edge_hash( a, b ) {
  85. return Math.min( a, b ) + "_" + Math.max( a, b );
  86. }
  87. function computeEdgeFaces( geometry ) {
  88. function addToMap( map, hash, i ) {
  89. if ( map[ hash ] === undefined ) {
  90. map[ hash ] = [];
  91. }
  92. map[ hash ].push( i );
  93. }
  94. var i, il, v1, v2, j, k,
  95. face, faceIndices, faceIndex,
  96. edge,
  97. hash,
  98. vfMap = {};
  99. // construct vertex -> face map
  100. for( i = 0, il = geometry.faces.length; i < il; i ++ ) {
  101. face = geometry.faces[ i ];
  102. if ( face instanceof THREE.Face3 ) {
  103. hash = edge_hash( face.a, face.b );
  104. addToMap( vfMap, hash, i );
  105. hash = edge_hash( face.b, face.c );
  106. addToMap( vfMap, hash, i );
  107. hash = edge_hash( face.c, face.a );
  108. addToMap( vfMap, hash, i );
  109. } else if ( face instanceof THREE.Face4 ) {
  110. hash = edge_hash( face.a, face.b );
  111. addToMap( vfMap, hash, i );
  112. hash = edge_hash( face.b, face.c );
  113. addToMap( vfMap, hash, i );
  114. hash = edge_hash( face.c, face.d );
  115. addToMap( vfMap, hash, i );
  116. hash = edge_hash( face.d, face.a );
  117. addToMap( vfMap, hash, i );
  118. }
  119. }
  120. // extract faces
  121. // var edges = [];
  122. //
  123. // var numOfEdges = 0;
  124. // for (i in vfMap) {
  125. // numOfEdges++;
  126. //
  127. // edge = vfMap[i];
  128. // edges.push(edge);
  129. //
  130. // }
  131. //console.log('vfMap', vfMap, 'geometry.edges',geometry.edges, 'numOfEdges', numOfEdges);
  132. return vfMap;
  133. };
  134. var originalPoints = oldGeometry.vertices;
  135. var originalFaces = oldGeometry.faces;
  136. var newPoints = originalPoints.concat(); // Vertices
  137. var facePoints = [], edgePoints = {};
  138. var sharpEdges = {}, sharpVertices = [], sharpFaces = [];
  139. var uvForVertices = {}; // Stored in {vertex}:{old face} format
  140. var originalVerticesLength = originalPoints.length;
  141. function getUV(vertexNo, oldFaceNo) {
  142. var key = vertexNo+':'+oldFaceNo;
  143. var theUV = uvForVertices[key];
  144. if (!theUV) {
  145. console.log('warnning, UV not found for', key);
  146. }
  147. return theUV;
  148. // Original faces -> Vertex Nos.
  149. // new Facepoint -> Vertex Nos.
  150. // edge Points
  151. }
  152. function addUV(vertexNo, oldFaceNo, value) {
  153. var key = vertexNo+':'+oldFaceNo;
  154. if (!(key in uvForVertices)) {
  155. uvForVertices[key] = value;
  156. } else {
  157. console.log('dup vertexNo', vertexNo, 'oldFaceNo', oldFaceNo, 'value', value, 'key', key, uvForVertices[key]);
  158. }
  159. }
  160. // Step 1
  161. // For each face, add a face point
  162. // Set each face point to be the centroid of all original points for the respective face.
  163. console.log(oldGeometry);
  164. var i, il, j, jl, face;
  165. // For Uvs
  166. var uvs = oldGeometry.faceVertexUvs[0];
  167. var abcd = 'abcd', vertice;
  168. console.log('originalFaces, uvs, originalVerticesLength', originalFaces.length, uvs.length, originalVerticesLength);
  169. for (i=0, il = uvs.length; i<il; i++ ) {
  170. for (j=0,jl=uvs[i].length;j<jl;j++) {
  171. vertice = originalFaces[i][abcd.charAt(j)];
  172. addUV(vertice, i, uvs[i][j]);
  173. }
  174. }
  175. var uvCount = 0;
  176. for (var u in uvForVertices) {
  177. // console.log(u);
  178. uvCount++;
  179. }
  180. if (!uvCount) {
  181. scope.supportUVs = false;
  182. console.log('no uvs');
  183. }
  184. console.log('--- Original Faces + Vertices UVs completed', uvForVertices, 'vs', uvs.length);
  185. var avgUv ;
  186. for (i=0, il = originalFaces.length; i<il ;i++) {
  187. face = originalFaces[i];
  188. facePoints.push(face.centroid);
  189. newPoints.push( new THREE.Vertex(face.centroid) );
  190. if (!scope.supportUVs) continue;
  191. // Prepare subdivided uv
  192. avgUv = new THREE.UV();
  193. if ( face instanceof THREE.Face3 ) {
  194. avgUv.u = getUV(face.a, i).u + getUV(face.b, i).u + getUV(face.c, i).u;
  195. avgUv.v = getUV(face.a, i).v + getUV(face.b, i).v + getUV(face.c, i).v;
  196. avgUv.u /= 3;
  197. avgUv.v /= 3;
  198. } else if ( face instanceof THREE.Face4 ) {
  199. avgUv.u = getUV(face.a,i).u + getUV(face.b, i).u + getUV(face.c, i).u + getUV(face.d, i).u;
  200. avgUv.v = getUV(face.a,i).v + getUV(face.b, i).v + getUV(face.c, i).v + getUV(face.d, i).v;
  201. avgUv.u /= 4;
  202. avgUv.v /= 4;
  203. }
  204. addUV(originalVerticesLength + i, '', avgUv);
  205. }
  206. console.log('-- added UVs for new Faces', uvForVertices);
  207. // Step 2
  208. // For each edge, add an edge point.
  209. // Set each edge point to be the average of the two neighbouring face points and its two original endpoints.
  210. var vfMap = computeEdgeFaces ( oldGeometry ); // Vertex Face Map
  211. var edge, faceIndexA, faceIndexB, avg;
  212. //console.log('vfMap', vfMap);
  213. var edgeCount = 0;
  214. var edgeVertex, edgeVertexA, edgeVertexB;
  215. ////
  216. var vertexEdgeMap = {}; // Gives edges connecting to each vertex
  217. var vertexFaceMap = {}; // Gives faces connecting to each vertex
  218. var addVertexEdgeMap = function(vertex, edge) {
  219. if (vertexEdgeMap[vertex]===undefined) {
  220. vertexEdgeMap[vertex] = [];
  221. }
  222. vertexEdgeMap[vertex].push(edge);
  223. };
  224. var addVertexFaceMap = function(vertex, face, edge) {
  225. if (vertexFaceMap[vertex]===undefined) {
  226. vertexFaceMap[vertex] = {};
  227. }
  228. //vertexFaceMap[vertex][face] = edge;
  229. vertexFaceMap[vertex][face] = null;
  230. };
  231. // Prepares vertexEdgeMap and vertexFaceMap
  232. for (i in vfMap) { // This is for every edge
  233. edge = vfMap[i];
  234. edgeVertex = i.split('_');
  235. edgeVertexA = edgeVertex[0];
  236. edgeVertexB = edgeVertex[1];
  237. // Maps an edgeVertex to connecting edges
  238. addVertexEdgeMap(edgeVertexA, [edgeVertexA, edgeVertexB] );
  239. addVertexEdgeMap(edgeVertexB, [edgeVertexA, edgeVertexB] );
  240. // faceIndexA = edge[0]; // face index a
  241. // faceIndexB = edge[1]; // face index b
  242. //
  243. // // Add connecting faces for edge
  244. // addVertexFaceMap(edgeVertexA, faceIndexA);
  245. // addVertexFaceMap(edgeVertexB, faceIndexA);
  246. //
  247. //
  248. // if (faceIndexB) {
  249. // addVertexFaceMap(edgeVertexA, faceIndexB);
  250. // addVertexFaceMap(edgeVertexB, faceIndexB);
  251. // } else {
  252. // addVertexFaceMap(edgeVertexA, faceIndexA);
  253. // addVertexFaceMap(edgeVertexB, faceIndexA);
  254. // }
  255. for (j=0,jl=edge.length;j<jl;j++) {
  256. face = edge[j];
  257. addVertexFaceMap(edgeVertexA, face, i);
  258. addVertexFaceMap(edgeVertexB, face, i);
  259. }
  260. if (edge.length < 2) {
  261. // edge is "sharp";
  262. sharpEdges[i] = true;
  263. sharpVertices[edgeVertexA] = true;
  264. sharpVertices[edgeVertexB] = true;
  265. }
  266. }
  267. console.log('vertexEdgeMap',vertexEdgeMap, 'vertexFaceMap', vertexFaceMap);
  268. for (i in vfMap) {
  269. edge = vfMap[i];
  270. faceIndexA = edge[0]; // face index a
  271. faceIndexB = edge[1]; // face index b
  272. edgeVertex = i.split('_');
  273. edgeVertexA = edgeVertex[0];
  274. edgeVertexB = edgeVertex[1];
  275. avg = new THREE.Vector3();
  276. //console.log(i, faceIndexB,facePoints[faceIndexB]);
  277. if (sharpEdges[i]) {
  278. //console.log('warning, ', i, 'edge has only 1 connecting face', edge);
  279. // For a sharp edge, average the edge end points.
  280. avg.addSelf(originalPoints[edgeVertexA].position);
  281. avg.addSelf(originalPoints[edgeVertexB].position);
  282. avg.multiplyScalar(0.5);
  283. sharpVertices[newPoints.length] = true;
  284. } else {
  285. avg.addSelf(facePoints[faceIndexA]);
  286. avg.addSelf(facePoints[faceIndexB]);
  287. avg.addSelf(originalPoints[edgeVertexA].position);
  288. avg.addSelf(originalPoints[edgeVertexB].position);
  289. avg.multiplyScalar(0.25);
  290. }
  291. edgePoints[i] = originalVerticesLength + originalFaces.length + edgeCount;
  292. newPoints.push( new THREE.Vertex(avg) );
  293. edgeCount ++;
  294. if (!scope.supportUVs) {
  295. continue;
  296. }
  297. // console.log('faceIndexAB', faceIndexA, faceIndexB, sharpEdges[i]);
  298. // Prepare subdivided uv
  299. avgUv = new THREE.UV();
  300. avgUv.u = getUV(edgeVertexA, faceIndexA).u + getUV(edgeVertexB, faceIndexA).u;
  301. avgUv.v = getUV(edgeVertexA, faceIndexA).v + getUV(edgeVertexB, faceIndexA).v;
  302. avgUv.u /= 2;
  303. avgUv.v /= 2;
  304. addUV(edgePoints[i], faceIndexA, avgUv);
  305. avgUv = new THREE.UV();
  306. avgUv.u = getUV(edgeVertexA, faceIndexB).u + getUV(edgeVertexB, faceIndexB).u;
  307. avgUv.v = getUV(edgeVertexA, faceIndexB).v + getUV(edgeVertexB, faceIndexB).v;
  308. avgUv.u /= 2;
  309. avgUv.v /= 2;
  310. addUV(edgePoints[i], faceIndexB, avgUv);
  311. }
  312. console.log('--- step 2 done');
  313. // Step 3
  314. // For each face point, add an edge for every edge of the face,
  315. // connecting the face point to each edge point for the face.
  316. var facePt, currentVerticeIndex;
  317. var hashAB, hashBC, hashCD, hashDA, hashCA;
  318. var abc123 = ['123', '12', '2', '23'];
  319. var bca123 = ['123', '23', '3', '31'];
  320. var cab123 = ['123', '31', '1', '12'];
  321. var abc1234 = ['1234', '12', '2', '23'];
  322. var bcd1234 = ['1234', '23', '3', '34'];
  323. var cda1234 = ['1234', '34', '4', '41'];
  324. var dab1234 = ['1234', '41', '1', '12'];
  325. for (i=0, il = facePoints.length; i<il ;i++) { // for every face
  326. facePt = facePoints[i];
  327. face = originalFaces[i];
  328. currentVerticeIndex = originalVerticesLength+ i;
  329. if ( face instanceof THREE.Face3 ) {
  330. // create 3 face4s
  331. hashAB = edge_hash( face.a, face.b );
  332. hashBC = edge_hash( face.b, face.c );
  333. hashCA = edge_hash( face.c, face.a );
  334. f4( currentVerticeIndex, edgePoints[hashAB], face.b, edgePoints[hashBC], face, abc123, i );
  335. f4( currentVerticeIndex, edgePoints[hashBC], face.c, edgePoints[hashCA], face, bca123, i );
  336. f4( currentVerticeIndex, edgePoints[hashCA], face.a, edgePoints[hashAB], face, cab123, i );
  337. } else if ( face instanceof THREE.Face4 ) {
  338. // create 4 face4s
  339. hashAB = edge_hash( face.a, face.b );
  340. hashBC = edge_hash( face.b, face.c );
  341. hashCD = edge_hash( face.c, face.d );
  342. hashDA = edge_hash( face.d, face.a );
  343. f4( currentVerticeIndex, edgePoints[hashAB], face.b, edgePoints[hashBC], face, abc1234, i );
  344. f4( currentVerticeIndex, edgePoints[hashBC], face.c, edgePoints[hashCD], face, bcd1234, i );
  345. f4( currentVerticeIndex, edgePoints[hashCD], face.d, edgePoints[hashDA], face, cda1234, i );
  346. f4( currentVerticeIndex, edgePoints[hashDA], face.a, edgePoints[hashAB], face, dab1234, i );
  347. } else {
  348. console.log('face should be a face!', face);
  349. }
  350. }
  351. newVertices = newPoints;
  352. // console.log('original ', oldGeometry.vertices.length, oldGeometry.faces.length );
  353. // console.log('new points', newPoints.length, 'faces', newFaces.length );
  354. // Step 4
  355. // For each original point P,
  356. // take the average F of all n face points for faces touching P,
  357. // and take the average R of all n edge midpoints for edges touching P,
  358. // where each edge midpoint is the average of its two endpoint vertices.
  359. // Move each original point to the point
  360. var F = new THREE.Vector3();
  361. var R = new THREE.Vector3();
  362. var n;
  363. for (i=0, il = originalPoints.length; i<il; i++) {
  364. // (F + 2R + (n-3)P) / n
  365. if (vertexEdgeMap[i]===undefined) continue;
  366. F.set(0,0,0);
  367. R.set(0,0,0);
  368. var newPos = new THREE.Vector3(0,0,0);
  369. var f =0;
  370. for (j in vertexFaceMap[i]) {
  371. F.addSelf(facePoints[j]);
  372. f++;
  373. }
  374. var sharpEdgeCount = 0;
  375. n = vertexEdgeMap[i].length;
  376. for (j=0;j<n;j++) {
  377. if (
  378. sharpEdges[
  379. edge_hash(vertexEdgeMap[i][j][0],vertexEdgeMap[i][j][1])
  380. ]) {
  381. sharpEdgeCount++;
  382. }
  383. }
  384. if ( sharpEdgeCount==2 ) {
  385. continue;
  386. // Do not move vertex if there's 2 connecting sharp edges.
  387. }
  388. /*
  389. if (sharpEdgeCount>2) {
  390. // TODO
  391. }
  392. */
  393. F.divideScalar(f);
  394. for (j=0; j<n;j++) {
  395. edge = vertexEdgeMap[i][j];
  396. var midPt = originalPoints[edge[0]].position.clone().addSelf(originalPoints[edge[1]].position).divideScalar(2);
  397. R.addSelf(midPt);
  398. // R.addSelf(originalPoints[edge[0]].position);
  399. // R.addSelf(originalPoints[edge[1]].position);
  400. }
  401. R.divideScalar(n)
  402. newPos.addSelf(originalPoints[i].position);
  403. newPos.multiplyScalar(n - 3);
  404. newPos.addSelf(F);
  405. newPos.addSelf(R.multiplyScalar(2));
  406. newPos.divideScalar(n);
  407. newVertices[i].position = newPos;
  408. }
  409. var newGeometry = oldGeometry; // Let's pretend the old geometry is now new :P
  410. newGeometry.vertices = newVertices;
  411. newGeometry.faces = newFaces;
  412. newGeometry.faceVertexUvs[ 0 ] = newUVs;
  413. delete newGeometry.__tmpVertices; // makes __tmpVertices undefined :P
  414. newGeometry.computeCentroids();
  415. newGeometry.computeFaceNormals();
  416. newGeometry.computeVertexNormals();
  417. };