BufferSubdivisionModifier.js 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778
  1. /*
  2. * @author zz85 / http://twitter.com/blurspline / http://www.lab4games.net/zz85/blog
  3. * @author Matthew Adams / http://www.centerionware.com - added UV support and rewrote to use buffergeometry.
  4. *
  5. * Subdivision Geometry Modifier
  6. * using Loop Subdivision Scheme for Geometry / BufferGeometry
  7. *
  8. * References:
  9. * http://graphics.stanford.edu/~mdfisher/subdivision.html
  10. * http://www.holmes3d.net/graphics/subdivision/
  11. * http://www.cs.rutgers.edu/~decarlo/readings/subdiv-sg00c.pdf
  12. *
  13. * Known Issues:
  14. * - currently doesn't handle "Sharp Edges"
  15. * - no checks to prevent breaking when uv's don't exist.
  16. * - vertex colors are unsupported.
  17. * **DDS Images when using corrected uv's passed to subdivision modifier will have their uv's flipy'd within the correct uv set
  18. * **Either flipy the DDS image, or use shaders. Don't try correcting the uv's before passing into subdiv (eg: v=1-v).
  19. *
  20. * @input THREE.Geometry, or index'd THREE.BufferGeometry with faceUV's (Not vertex uv's)
  21. * @output non-indexed vertex points, uv's, normals.
  22. *
  23. */
  24. /*
  25. *
  26. * The TypedArrayHelper class is designed to assist managing typed arrays, and to allow the removal of all 'new Vector3, new Face3, new Vector2'.
  27. *
  28. * It will automatically resize them if trying to push a new element to an array that isn't long enough
  29. * It provides 'registers' that the units can be mapped to. This allows a small set of objects
  30. * (ex: vector3's, face3's, vector2's) to be allocated then used, to eliminate any need to rewrite all
  31. * the features those classes offer while not requiring some_huge_number to be allocated.
  32. * It should be moved into it's own file honestly, then included before the BufferSubdivisionModifier - maybe in three's core?
  33. *
  34. *
  35. * EX: new TypedArrayHelper(initial_size_in_elements, 3, THREE.Vector3, Float32Array, 3, ['x', 'y', 'z']); (the x,y,z comes from THREE.Vector3. It would be abc if it were a face3. etc etc)
  36. *
  37. */
  38. THREE.Face3.prototype.set = function (a, b, c) {
  39. this.a = a;
  40. this.b = b;
  41. this.c = c;
  42. }
  43. var TypedArrayHelper = function (size, registers, register_type, array_type, unit_size, accessors) {
  44. this.array_type = array_type;
  45. this.register_type = register_type;
  46. this.unit_size = unit_size;
  47. this.accessors = accessors;
  48. this.buffer = new array_type(size * unit_size);
  49. this.register = [];
  50. this.length = 0;
  51. this.real_length = size;
  52. this.available_registers = registers;
  53. for (var i = 0; i < registers; i++) { this.register.push(new register_type()); }
  54. }
  55. TypedArrayHelper.prototype = {
  56. constructor: TypedArrayHelper,
  57. index_to_register: function (index, register, isLoop) {
  58. var base = index * this.unit_size;
  59. if (register >= this.available_registers) {
  60. throw ("Nope nope nope, not enough registers!");
  61. }
  62. if (index > this.length) {
  63. throw ("Nope nope nope, index is out of range");
  64. }
  65. for (var i = 0; i < this.unit_size; i++)
  66. (this.register[register])[this.accessors[i]] = this.buffer[base + i];
  67. },
  68. resize: function (new_size) {
  69. if (new_size == 0) new_size = 8;
  70. if (new_size < this.length) {
  71. this.buffer = this.buffer.subarray(0, this.length * this.unit_size);
  72. } else {
  73. if (this.buffer.length < new_size * this.unit_size) {
  74. var nBuffer = new this.array_type(new_size * this.unit_size);
  75. nBuffer.set(this.buffer);
  76. this.buffer = nBuffer;
  77. this.real_length = new_size;
  78. } else {
  79. var nBuffer = new this.array_type(new_size * this.unit_size);
  80. nBuffer.set(this.buffer.subarray(0, this.length * this.unit_size));
  81. this.buffer = nBuffer;
  82. this.real_length = new_size;
  83. }
  84. }
  85. },
  86. from_existing: function (oldArray) {
  87. var new_size = oldArray.length;
  88. this.buffer = new this.array_type(new_size);//this.resize(oldArray.length);
  89. this.buffer.set(oldArray);//.slice(0, oldArray.length));
  90. this.length = oldArray.length / this.unit_size;
  91. this.real_length = this.length;
  92. },
  93. push_element: function (vector) {
  94. if (this.length + 1 > this.real_length) { this.resize(this.real_length * 2); }
  95. var bpos = this.length * this.unit_size;
  96. for (var i = 0; i < this.unit_size; i++) {
  97. this.buffer[bpos + i] = vector[this.accessors[i]];
  98. }
  99. this.length++;
  100. },
  101. trim_size: function () {
  102. if (this.length < this.real_length) this.resize(this.length);
  103. },
  104. each: function (function_pointer, xtra) {
  105. if (typeof this.loop_register == 'undefined') this.loop_register = new this.register_type();
  106. for (var i = 0; i < this.length; i++) {
  107. for (var j = 0; j < this.unit_size; j++)
  108. this.loop_register[this.accessors[j]] = this.buffer[i * this.unit_size + j];
  109. function_pointer(this.loop_register, i, xtra);
  110. }
  111. },
  112. push_array: function (vector) {
  113. if (this.length + 1 > this.real_length) { this.resize(this.real_length * 2); }
  114. var bpos = this.length * this.unit_size;
  115. for (var i = 0; i < this.unit_size; i++) {
  116. this.buffer[bpos + i] = vector[i];
  117. }
  118. this.length++;
  119. }
  120. }
  121. function convertGeometryToIndexedBuffer(geometry) {
  122. var BGeom = new THREE.BufferGeometry();
  123. // create a new typed array
  124. var vertArray = new TypedArrayHelper(geometry.vertices.length, 0, THREE.Vector3, Float32Array, 3, ['x', 'y', 'z']);
  125. var indexArray = new TypedArrayHelper(geometry.faces.length, 0, THREE.Face3, Uint32Array, 3, ['a', 'b', 'c']);
  126. var uvArray = new TypedArrayHelper(geometry.faceVertexUvs[0].length * 3 * 3, 0, THREE.Vector2, Float32Array, 2, ['x', 'y']);
  127. var i, il;
  128. for (i = 0, il = geometry.vertices.length; i < il; i++) vertArray.push_element(geometry.vertices[i]);
  129. for (i = 0, il = geometry.faces.length; i < il; i++) indexArray.push_element(geometry.faces[i]);
  130. for (i = 0, il = geometry.faceVertexUvs[0].length; i < il; i++) {
  131. uvArray.push_element(geometry.faceVertexUvs[0][i][0]);
  132. uvArray.push_element(geometry.faceVertexUvs[0][i][1]);
  133. uvArray.push_element(geometry.faceVertexUvs[0][i][2]);
  134. }
  135. indexArray.trim_size();
  136. vertArray.trim_size();
  137. uvArray.trim_size();
  138. BGeom.setIndex(new THREE.BufferAttribute(indexArray.buffer,3));
  139. BGeom.addAttribute('position', new THREE.BufferAttribute(vertArray.buffer, 3));
  140. BGeom.addAttribute('uv', new THREE.BufferAttribute(uvArray.buffer, 2));
  141. return BGeom;
  142. }
  143. function addNormal(old, newn) {
  144. // old.x += newn.x;
  145. // old.y += newn.y;
  146. // old.z += newn.z;
  147. ///*
  148. if (old.x == 0) old.x = newn.x;
  149. else old.x = (old.x + newn.x) / 2;
  150. if (old.y == 0) old.y = newn.y;
  151. else old.y = (old.y + newn.y) / 2;
  152. if (old.z == 0) old.z = newn.z;
  153. else old.z = (old.z + newn.z) / 2;
  154. // */
  155. }
  156. function findArea(a, b, c) {
  157. return Math.abs(((a.x * (b.y - c.y)) + (b.x * (c.y - a.y)) + (c.x * (a.y - b.y))) / 2.0);
  158. }
  159. function find_angle3d(A, B, C) {
  160. var AB = Math.sqrt(Math.pow(B.x - A.x, 2) + Math.pow(B.y - A.y, 2));
  161. var BC = Math.sqrt(Math.pow(B.x - C.x, 2) + Math.pow(B.y - C.y, 2));
  162. var AC = Math.sqrt(Math.pow(C.x - A.x, 2) + Math.pow(C.y - A.y, 2));
  163. return Math.acos((BC * BC + AB * AB - AC * AC) / (2 * BC * AB));
  164. }
  165. function find_angle2d(p1,p2) {
  166. return Math.atan2(p2.y - p1.y, p2.x - p1.x);
  167. }
  168. function compute_vertex_normals(geometry) {
  169. var ABC = ['a', 'b', 'c'];
  170. var XYZ = ['x', 'y', 'z'];
  171. var XY = ['x', 'y'];
  172. var oldVertices = new TypedArrayHelper(0, 5, THREE.Vector3, Float32Array, 3, XYZ);
  173. var oldFaces = new TypedArrayHelper(0, 3, THREE.Face3, Uint32Array, 3, ABC);
  174. oldVertices.from_existing(geometry.getAttribute('position').array);
  175. var newNormals = new TypedArrayHelper(oldVertices.length * 3, 4, THREE.Vector3, Float32Array, 3, XYZ);
  176. var newNormalFaces = new TypedArrayHelper(oldVertices.length, 1, function () { this.x = 0; }, Float32Array, 1, ['x']);
  177. newNormals.length = oldVertices.length;
  178. var a, b, c;
  179. oldFaces.from_existing(geometry.index.array);
  180. var j, jl;
  181. var k,l;
  182. var my_weight;
  183. var full_weights = [0.0,0.0,0.0];
  184. for (var i = 0, il = oldFaces.length; i < il; i++) {
  185. oldFaces.index_to_register(i, 0);
  186. oldVertices.index_to_register(oldFaces.register[0].a, 0);
  187. oldVertices.index_to_register(oldFaces.register[0].b, 1);
  188. oldVertices.index_to_register(oldFaces.register[0].c, 2);
  189. newNormals.register[0].subVectors(oldVertices.register[1], oldVertices.register[0]);
  190. newNormals.register[1].subVectors(oldVertices.register[2], oldVertices.register[1]);
  191. newNormals.register[0].cross(newNormals.register[1]);
  192. my_weight = Math.abs(newNormals.register[0].length());
  193. //my_weight = findArea(oldVertices.register[0], oldVertices.register[1], oldVertices.register[2]);
  194. newNormalFaces.buffer[oldFaces.register[0].a] += my_weight;
  195. newNormalFaces.buffer[oldFaces.register[0].b] += my_weight;
  196. newNormalFaces.buffer[oldFaces.register[0].c] += my_weight;
  197. }
  198. var tmpx;
  199. var tmpy;
  200. var tmpz;
  201. var t_len;
  202. for (var i = 0, il = oldFaces.length; i < il; i++) {
  203. oldFaces.index_to_register(i, 0);
  204. oldVertices.index_to_register(oldFaces.register[0].a, 0);
  205. oldVertices.index_to_register(oldFaces.register[0].b, 1);
  206. oldVertices.index_to_register(oldFaces.register[0].c, 2);
  207. newNormals.register[0].subVectors(oldVertices.register[1], oldVertices.register[0]);
  208. newNormals.register[1].subVectors(oldVertices.register[2], oldVertices.register[0]);
  209. /*
  210. // newNormals.register[0].cross(newNormals.register[1]);
  211. newNormals.register[3].copy(newNormals.register[0]);//(a, b, c);
  212. t_len = (newNormals.register[3].x + newNormals.register[3].y + newNormals.register[3].z);
  213. newNormals.register[3].x = newNormals.register[3].x / t_len;
  214. newNormals.register[3].y = newNormals.register[3].y / t_len;
  215. newNormals.register[3].z = newNormals.register[3].z / t_len;
  216. */
  217. newNormals.register[3].set(0,0,0);
  218. newNormals.register[3].x = (newNormals.register[0].y*newNormals.register[1].z )-(newNormals.register[0].z*newNormals.register[1].y);
  219. newNormals.register[3].y = (newNormals.register[0].z*newNormals.register[1].x )-(newNormals.register[0].x*newNormals.register[1].z);
  220. newNormals.register[3].z = (newNormals.register[0].x*newNormals.register[1].y )-(newNormals.register[0].y*newNormals.register[1].x);
  221. newNormals.register[0].cross(newNormals.register[1]);
  222. my_weight = Math.abs(newNormals.register[0].length() );
  223. // oldVertices.register[3].subVectors(oldVertices.register[2],oldVertices.register[0]);
  224. // oldVertices.register[4].subVectors(oldVertices.register[2],oldVertices.register[1]);
  225. // var angle = find_angle2d(oldVertices.register[3],oldVertices.register[4]);
  226. full_weights[0] = (my_weight / newNormalFaces.buffer[oldFaces.register[0].a]) ;
  227. full_weights[1] = (my_weight / newNormalFaces.buffer[oldFaces.register[0].b]) ;
  228. full_weights[2] = (my_weight / newNormalFaces.buffer[oldFaces.register[0].c]) ;
  229. tmpx = newNormals.register[3].x * full_weights[0];
  230. tmpy = newNormals.register[3].y * full_weights[0];
  231. tmpz = newNormals.register[3].z * full_weights[0];
  232. newNormals.buffer[ oldFaces.register[0].a * 3 ] += newNormals.register[3].x * full_weights[0];
  233. newNormals.buffer[(oldFaces.register[0].a * 3) + 1] += newNormals.register[3].y * full_weights[0];
  234. newNormals.buffer[(oldFaces.register[0].a * 3) + 2] += newNormals.register[3].z * full_weights[0];
  235. newNormals.buffer[ oldFaces.register[0].b * 3 ] += newNormals.register[3].x * full_weights[1];
  236. newNormals.buffer[(oldFaces.register[0].b * 3) + 1] += newNormals.register[3].y * full_weights[1];
  237. newNormals.buffer[(oldFaces.register[0].b * 3) + 2] += newNormals.register[3].z * full_weights[1];
  238. newNormals.buffer[ oldFaces.register[0].c * 3 ] += newNormals.register[3].x * full_weights[2];
  239. newNormals.buffer[(oldFaces.register[0].c * 3) + 1] += newNormals.register[3].y * full_weights[2];
  240. newNormals.buffer[(oldFaces.register[0].c * 3) + 2] += newNormals.register[3].z * full_weights[2];
  241. /*
  242. newNormals.index_to_register(oldFaces.register[0].a, 0);
  243. newNormals.index_to_register(oldFaces.register[0].b, 1);
  244. newNormals.index_to_register(oldFaces.register[0].c, 2);
  245. addNormal(newNormals.register[3], newNormals.register[0]);
  246. addNormal(newNormals.register[3], newNormals.register[1]);
  247. addNormal(newNormals.register[3], newNormals.register[2]);
  248. newNormals.buffer[oldFaces.register[0].a * 3] = newNormals.register[3].x;
  249. newNormals.buffer[(oldFaces.register[0].a * 3)+1] = newNormals.register[3].y;
  250. newNormals.buffer[(oldFaces.register[0].a * 3) + 2] = newNormals.register[3].z;
  251. newNormals.buffer[oldFaces.register[0].b * 3] = newNormals.register[3].x;
  252. newNormals.buffer[(oldFaces.register[0].b * 3) + 1] = newNormals.register[3].y;
  253. newNormals.buffer[(oldFaces.register[0].b * 3) + 2] = newNormals.register[3].z;
  254. newNormals.buffer[oldFaces.register[0].c * 3] = newNormals.register[3].x;
  255. newNormals.buffer[(oldFaces.register[0].c * 3) + 1] = newNormals.register[3].y;
  256. newNormals.buffer[(oldFaces.register[0].c * 3) + 2] = newNormals.register[3].z;
  257. */
  258. // newNormalFaces[oldFaces.register[0].a] += 1;
  259. // newNormalFaces[oldFaces.register[0].b] += 1;
  260. // newNormalFaces[oldFaces.register[0].c] += 1;
  261. }
  262. // for (var i = 0, il = newNormalFaces.length; i < i; i++) {
  263. // newNormals.buffer[(i * 3)] = newNormals.buffer[(i * 3)] / newNormalFaces.buffer[i];
  264. // newNormals.buffer[(i * 3)+1] = newNormals.buffer[(i * 3)+1] / newNormalFaces.buffer[i];
  265. // newNormals.buffer[(i * 3)+2] = newNormals.buffer[(i * 3)+2] / newNormalFaces.buffer[i];
  266. // }
  267. newNormals.trim_size();
  268. geometry.addAttribute('normal', new THREE.BufferAttribute(newNormals.buffer, 3));
  269. }
  270. function unIndexIndexedGeometry(geometry) {
  271. var ABC = ['a', 'b', 'c'];
  272. var XYZ = ['x', 'y', 'z'];
  273. var XY = ['x', 'y'];
  274. var oldVertices = new TypedArrayHelper(0, 3, THREE.Vector3, Float32Array, 3, XYZ);
  275. var oldFaces = new TypedArrayHelper(0, 3, THREE.Face3, Uint32Array, 3, ABC);
  276. var oldUvs = new TypedArrayHelper(0, 3, THREE.Vector2, Float32Array, 2, XY);
  277. var oldNormals = new TypedArrayHelper(0, 3, THREE.Vector3, Float32Array, 3, XYZ);
  278. oldVertices.from_existing(geometry.getAttribute('position').array);
  279. oldFaces.from_existing(geometry.index.array);
  280. oldUvs.from_existing(geometry.getAttribute('uv').array);
  281. // geometry.computeFaceNormals();
  282. // geometry.computeVertexNormals();
  283. compute_vertex_normals(geometry);
  284. oldNormals.from_existing(geometry.getAttribute('normal').array);
  285. var newVertices = new TypedArrayHelper(oldFaces.length * 3, 3, THREE.Vector3, Float32Array, 3, XYZ);
  286. var newNormals = new TypedArrayHelper(oldFaces.length * 3, 3, THREE.Vector3, Float32Array, 3, XYZ);
  287. var newUvs = new TypedArrayHelper(oldFaces.length * 3, 3, THREE.Vector2, Float32Array, 2, XY);
  288. var v, w;
  289. for (var i = 0, il = oldFaces.length; i < il; i++) {
  290. oldFaces.index_to_register(i, 0);
  291. oldVertices.index_to_register(oldFaces.register[0].a, 0);
  292. oldVertices.index_to_register(oldFaces.register[0].b, 1);
  293. oldVertices.index_to_register(oldFaces.register[0].c, 2);
  294. newVertices.push_element(oldVertices.register[0]);
  295. newVertices.push_element(oldVertices.register[1]);
  296. newVertices.push_element(oldVertices.register[2]);
  297. if (oldUvs.length != 0) {
  298. oldUvs.index_to_register((i * 3) + 0, 0);
  299. oldUvs.index_to_register((i * 3) + 1, 1);
  300. oldUvs.index_to_register((i * 3) + 2, 2);
  301. newUvs.push_element(oldUvs.register[0]);
  302. newUvs.push_element(oldUvs.register[1]);
  303. newUvs.push_element(oldUvs.register[2]);
  304. }
  305. oldNormals.index_to_register(oldFaces.register[0].a, 0);
  306. oldNormals.index_to_register(oldFaces.register[0].b, 1);
  307. oldNormals.index_to_register(oldFaces.register[0].c, 2);
  308. newNormals.push_element(oldNormals.register[0]);
  309. newNormals.push_element(oldNormals.register[1]);
  310. newNormals.push_element(oldNormals.register[2]);
  311. /* oldVertices.index_to_register(oldFaces.register[0].a, 0);
  312. oldVertices.index_to_register(oldFaces.register[0].b, 1);
  313. oldVertices.index_to_register(oldFaces.register[0].c, 2);
  314. newNormals.register[0].subVectors(oldVertices.register[1], oldVertices.register[0]);
  315. newNormals.register[1].subVectors(oldVertices.register[2], oldVertices.register[0]);
  316. v = newNormals.register[0];
  317. w = newNormals.register[1];
  318. newNormals.register[2].x = (v.y * w.z) - (v.z * w.y);
  319. newNormals.register[2].y = (v.z * w.x) - (v.x * w.z)
  320. newNormals.register[2].z = (v.x * w.y) - (v.y * w.x)
  321. newNormals.push_element(newNormals.register[2]);
  322. newNormals.push_element(newNormals.register[2]);
  323. newNormals.push_element(newNormals.register[2]);?*/
  324. }
  325. newVertices.trim_size();
  326. newUvs.trim_size();
  327. newNormals.trim_size();
  328. geometry.index = null;
  329. geometry.addAttribute('position', new THREE.BufferAttribute(newVertices.buffer, 3));
  330. geometry.addAttribute('normal', new THREE.BufferAttribute(newNormals.buffer, 3));
  331. if(newUvs.length != 0)
  332. geometry.addAttribute('uv', new THREE.BufferAttribute(newUvs.buffer, 2));
  333. // geometry.computeVertexNormals();
  334. return geometry;
  335. }
  336. THREE.BufferSubdivisionModifier = function (subdivisions) {
  337. this.subdivisions = (subdivisions === undefined) ? 1 : subdivisions;
  338. //this.subdivisions = 3;
  339. };
  340. // Applies the "modify" pattern
  341. THREE.BufferSubdivisionModifier.prototype.modify = function (geometry) {
  342. if (geometry instanceof THREE.Geometry) {
  343. geometry.mergeVertices();
  344. if (typeof (geometry.normals) == 'undefined') geometry.normals = [];
  345. var BGEom = convertGeometryToIndexedBuffer(geometry);
  346. geometry = BGEom;
  347. } else if( !(geometry instanceof THREE.BufferGeometry) ) console.log("Geometry is not an instance of THREE.BufferGeometry or THREE.Geometry");
  348. var repeats = this.subdivisions;
  349. while (repeats-- > 0) {
  350. this.smooth(geometry);
  351. }
  352. return unIndexIndexedGeometry(geometry); // it doesn't change what geometry points to in the function that calls this.. >_<. how annoying.
  353. };
  354. var edge_type = function (a, b) {
  355. this.a = a;
  356. this.b = b;
  357. this.faces = [];
  358. this.newEdge = null;
  359. };
  360. (function () {
  361. // Some constants
  362. var WARNINGS = ! true; // Set to true for development
  363. var ABC = ['a', 'b', 'c'];
  364. var XYZ = ['x', 'y', 'z'];
  365. var XY = ['x', 'y'];
  366. function getEdge(a, b, map) {
  367. var key = Math.min(a, b) + "_" + Math.max(a, b);
  368. return map[key];
  369. }
  370. function processEdge(a, b, vertices, map, face, metaVertices) {
  371. var vertexIndexA = Math.min(a, b);
  372. var vertexIndexB = Math.max(a, b);
  373. var key = vertexIndexA + "_" + vertexIndexB;
  374. var edge;
  375. if (key in map) {
  376. edge = map[key];
  377. } else {
  378. // var vertexA = vertices[vertexIndexA];
  379. // var vertexB = vertices[vertexIndexB];
  380. edge = new edge_type(vertexIndexA,vertexIndexB);
  381. map[key] = edge;
  382. }
  383. edge.faces.push(face);
  384. metaVertices[a].edges.push(edge);
  385. metaVertices[b].edges.push(edge);
  386. }
  387. function generateLookups(vertices, faces, metaVertices, edges) {
  388. var i, il, face, edge;
  389. for (i = 0, il = vertices.length; i < il; i++) {
  390. metaVertices[i] = { edges: [] };
  391. }
  392. for (i = 0, il = faces.length; i < il; i++) {
  393. faces.index_to_register(i, 0);
  394. face = faces.register[0]; // Faces is now a TypedArrayHelper class, not a face3.
  395. processEdge(face.a, face.b, vertices, edges, i, metaVertices);
  396. processEdge(face.b, face.c, vertices, edges, i, metaVertices);
  397. processEdge(face.c, face.a, vertices, edges, i, metaVertices);
  398. }
  399. }
  400. function newFace(newFaces, face) {
  401. newFaces.push_element(face);
  402. }
  403. function midpoint(a, b) {
  404. return (Math.abs(b - a) / 2) + Math.min(a, b);
  405. }
  406. function newUv(newUvs, a, b, c) {
  407. newUvs.push_element(a);
  408. newUvs.push_element(b);
  409. newUvs.push_element(c);
  410. }
  411. /////////////////////////////
  412. // Performs one iteration of Subdivision
  413. THREE.BufferSubdivisionModifier.prototype.smooth = function (geometry) {
  414. var oldVertices, oldFaces, oldUvs;
  415. var newVertices, newFaces, newUVs;
  416. var n, l, i, il, j, k;
  417. var metaVertices, sourceEdges;
  418. // new stuff.
  419. var sourceEdges;
  420. oldVertices = new TypedArrayHelper(0, 3, THREE.Vector3, Float32Array, 3, XYZ);
  421. oldFaces = new TypedArrayHelper(0, 3, THREE.Face3, Uint32Array, 3, ABC);
  422. oldUvs = new TypedArrayHelper(0, 3, THREE.Vector2, Float32Array, 2, XY);
  423. oldVertices.from_existing(geometry.getAttribute('position').array);
  424. oldFaces.from_existing(geometry.index.array);
  425. oldUvs.from_existing(geometry.getAttribute('uv').array);
  426. var doUvs = false;
  427. if (typeof (oldUvs) != 'undefined' && oldUvs.length != 0) doUvs = true;
  428. /******************************************************
  429. *
  430. * Step 0: Preprocess Geometry to Generate edges Lookup
  431. *
  432. *******************************************************/
  433. metaVertices = new Array(oldVertices.length);
  434. sourceEdges = {}; // Edge => { oldVertex1, oldVertex2, faces[] }
  435. generateLookups(oldVertices, oldFaces, metaVertices, sourceEdges);
  436. /******************************************************
  437. *
  438. * Step 1.
  439. * For each edge, create a new Edge Vertex,
  440. * then position it.
  441. *
  442. *******************************************************/
  443. newVertices = new TypedArrayHelper((geometry.getAttribute('position').array.length*2)/3, 2, THREE.Vector3, Float32Array, 3, XYZ);
  444. var other, currentEdge, newEdge, face;
  445. var edgeVertexWeight, adjacentVertexWeight, connectedFaces;
  446. var tmp = newVertices.register[1];
  447. for (i in sourceEdges) {
  448. currentEdge = sourceEdges[i];
  449. newEdge = newVertices.register[0];
  450. edgeVertexWeight = 3 / 8;
  451. adjacentVertexWeight = 1 / 8;
  452. connectedFaces = currentEdge.faces.length;
  453. // check how many linked faces. 2 should be correct.
  454. if (connectedFaces != 2) {
  455. // if length is not 2, handle condition
  456. edgeVertexWeight = 0.5;
  457. adjacentVertexWeight = 0;
  458. if (connectedFaces != 1) {
  459. if (WARNINGS) console.warn('Subdivision Modifier: Number of connected faces != 2, is: ', connectedFaces, currentEdge);
  460. }
  461. }
  462. oldVertices.index_to_register(currentEdge.a, 0);
  463. oldVertices.index_to_register(currentEdge.b, 1);
  464. newEdge.addVectors(oldVertices.register[0], oldVertices.register[1]).multiplyScalar(edgeVertexWeight);
  465. tmp.set(0, 0, 0);
  466. for (j = 0; j < connectedFaces; j++) {
  467. oldFaces.index_to_register(currentEdge.faces[j], 0);
  468. face = oldFaces.register[0];
  469. for (k = 0; k < 3; k++) {
  470. oldVertices.index_to_register(face[ABC[k]], 2);
  471. other = oldVertices.register[2];
  472. if (face[ABC[k]] !== currentEdge.a && face[ABC[k]] !== currentEdge.b) break;
  473. }
  474. tmp.add(other);
  475. }
  476. tmp.multiplyScalar(adjacentVertexWeight);
  477. newEdge.add(tmp);
  478. currentEdge.newEdge = newVertices.length;
  479. newVertices.push_element(newEdge);
  480. // console.log(currentEdge, newEdge);
  481. }
  482. var edgeLength = newVertices.length;
  483. /******************************************************
  484. *
  485. * Step 2.
  486. * Reposition each source vertices.
  487. *
  488. *******************************************************/
  489. var beta, sourceVertexWeight, connectingVertexWeight;
  490. var connectingEdge, connectingEdges, oldVertex, newSourceVertex;
  491. for (i = 0, il = oldVertices.length; i < il; i++) {
  492. oldVertices.index_to_register(i, 0, XYZ);
  493. oldVertex = oldVertices.register[0];
  494. // find all connecting edges (using lookupTable)
  495. connectingEdges = metaVertices[i].edges;
  496. n = connectingEdges.length;
  497. if (n == 3) {
  498. beta = 3 / 16;
  499. } else if (n > 3) {
  500. beta = 3 / (8 * n); // Warren's modified formula
  501. }
  502. // Loop's original beta formula
  503. // beta = 1 / n * ( 5/8 - Math.pow( 3/8 + 1/4 * Math.cos( 2 * Math. PI / n ), 2) );
  504. sourceVertexWeight = 1 - n * beta;
  505. connectingVertexWeight = beta;
  506. if (n <= 2) {
  507. // crease and boundary rules
  508. // console.warn('crease and boundary rules');
  509. if (n == 2) {
  510. if (WARNINGS) console.warn('2 connecting edges', connectingEdges);
  511. sourceVertexWeight = 3 / 4;
  512. connectingVertexWeight = 1 / 8;
  513. // sourceVertexWeight = 1;
  514. // connectingVertexWeight = 0;
  515. } else if (n == 1) {
  516. if (WARNINGS) console.warn('only 1 connecting edge');
  517. } else if (n == 0) {
  518. if (WARNINGS) console.warn('0 connecting edges');
  519. }
  520. }
  521. newSourceVertex = oldVertex.multiplyScalar(sourceVertexWeight);
  522. tmp.set(0, 0, 0);
  523. for (j = 0; j < n; j++) {
  524. connectingEdge = connectingEdges[j];
  525. other = connectingEdge.a !== i ? connectingEdge.a : connectingEdge.b;
  526. oldVertices.index_to_register(other, 1, XYZ);
  527. tmp.add(oldVertices.register[1]);
  528. }
  529. tmp.multiplyScalar(connectingVertexWeight);
  530. newSourceVertex.add(tmp);
  531. newVertices.push_element(newSourceVertex,XYZ);
  532. }
  533. /******************************************************
  534. *
  535. * Step 3.
  536. * Generate Faces between source vertecies
  537. * and edge vertices.
  538. *
  539. *******************************************************/
  540. var edge1, edge2, edge3;
  541. newFaces = new TypedArrayHelper((geometry.index.array.length*4) / 3, 1, THREE.Face3, Float32Array, 3, ABC);
  542. newUVs = new TypedArrayHelper((geometry.getAttribute('uv').array.length * 4) / 2, 3, THREE.Vector2, Float32Array, 2, XY);
  543. var x3 = newUVs.register[0];
  544. var x4 = newUVs.register[1];
  545. var x5 = newUVs.register[2];
  546. var tFace = newFaces.register[0];
  547. for (i = 0, il = oldFaces.length; i < il; i++) {
  548. oldFaces.index_to_register(i, 0);
  549. face = oldFaces.register[0];//oldFaces[i];
  550. // find the 3 new edges vertex of each old face
  551. // The new source verts are added after the new edge verts now..
  552. edge1 = getEdge(face.a, face.b, sourceEdges).newEdge;
  553. edge2 = getEdge(face.b, face.c, sourceEdges).newEdge;
  554. edge3 = getEdge(face.c, face.a, sourceEdges).newEdge;
  555. // create 4 faces.
  556. tFace.set(edge1, edge2, edge3);
  557. newFace(newFaces, tFace);
  558. tFace.set(face.a + edgeLength, edge1, edge3);
  559. newFace(newFaces, tFace);
  560. tFace.set(face.b + edgeLength,edge2,edge1);
  561. newFace(newFaces, tFace);
  562. tFace.set(face.c + edgeLength,edge3,edge2);
  563. newFace(newFaces, tFace);
  564. // create 4 new uv's
  565. /*
  566. 0___________________C___________________2
  567. \ /\ /
  568. \ / \ F4 /
  569. \ F2 / \ /
  570. \ / \ /
  571. \ / \ /
  572. \ / F1 \ /
  573. \/_______________________\/
  574. A \ / B
  575. \ F3 /
  576. \ /
  577. \ /
  578. \ /
  579. \ /
  580. \ /
  581. \ /
  582. \/
  583. 1
  584. Draw orders:
  585. F1: ABC x3,x4,x5
  586. F2: 0AC x0,x3,x5
  587. F3: 1BA x1,x4,x3
  588. F4: 2CB x2,x5,x4
  589. 0: x0
  590. 1: x1
  591. 2: x2
  592. A: x3
  593. B: x4
  594. C: x5
  595. */
  596. if (doUvs) {
  597. oldUvs.index_to_register(i * 3, 0);
  598. oldUvs.index_to_register((i * 3)+1, 1);
  599. oldUvs.index_to_register((i * 3)+2, 2);
  600. // uv = oldUvs[i];
  601. x0 = oldUvs.register[0];//uv[0];
  602. x1 = oldUvs.register[1];//uv[1];
  603. x2 = oldUvs.register[2];//uv[2];
  604. x3.set(midpoint(x0.x, x1.x), midpoint(x0.y, x1.y));
  605. x4.set(midpoint(x1.x, x2.x), midpoint(x1.y, x2.y));
  606. x5.set(midpoint(x0.x, x2.x), midpoint(x0.y, x2.y));
  607. newUv(newUVs, x3, x4, x5);
  608. newUv(newUVs, x0, x3, x5);
  609. newUv(newUVs, x1, x4, x3);
  610. newUv(newUVs, x2, x5, x4);
  611. }
  612. }
  613. // Overwrite old arrays
  614. //geometry.addAttribute('position', THREE.BufferAttribute(newVertices, 3).copy)
  615. newVertices.trim_size();
  616. newFaces.trim_size();
  617. newUVs.trim_size();
  618. geometry.addAttribute('position', new THREE.BufferAttribute(newVertices.buffer,3));
  619. geometry.setIndex(new THREE.BufferAttribute(newFaces.buffer,3));
  620. geometry.addAttribute('uv', new THREE.BufferAttribute(newUVs.buffer,2));
  621. /*
  622. geometry.vertices = newVertices;
  623. geometry.faces = newFaces;
  624. geometry.faceVertexUvs[0] = newUVs; */
  625. // console.log('done');
  626. };
  627. })();