SubdivisionModifier.js 14 KB

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