TessellateModifier.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. import {
  2. BufferGeometry,
  3. Color,
  4. Float32BufferAttribute,
  5. Vector2,
  6. Vector3
  7. } from 'three';
  8. /**
  9. * This class can be used to modify a geometry by breaking its edges if they
  10. * are longer than maximum length.
  11. *
  12. * ```js
  13. * const modifier = new TessellateModifier( 8, 6 );
  14. * geometry = modifier.modify( geometry );
  15. * ```
  16. */
  17. class TessellateModifier {
  18. /**
  19. * Constructs a new Tessellate modifier.
  20. *
  21. * @param {number} [maxEdgeLength=0.1] - The maximum edge length.
  22. * @param {number} [maxIterations=6] - The number of iterations.
  23. */
  24. constructor( maxEdgeLength = 0.1, maxIterations = 6 ) {
  25. /**
  26. * The maximum edge length.
  27. *
  28. * @type {number}
  29. * @default 0.1
  30. */
  31. this.maxEdgeLength = maxEdgeLength;
  32. /**
  33. * The maximum edge length.
  34. *
  35. * @type {number}
  36. * @default 0.1
  37. */
  38. this.maxIterations = maxIterations;
  39. }
  40. /**
  41. * Returns a new, modified version of the given geometry by applying a tesselation.
  42. * Please note that the resulting geometry is always non-indexed.
  43. *
  44. * @param {BufferGeometry} geometry - The geometry to modify.
  45. * @return {BufferGeometry} A new, modified geometry.
  46. */
  47. modify( geometry ) {
  48. if ( geometry.index !== null ) {
  49. geometry = geometry.toNonIndexed();
  50. }
  51. //
  52. const maxIterations = this.maxIterations;
  53. const maxEdgeLengthSquared = this.maxEdgeLength * this.maxEdgeLength;
  54. const va = new Vector3();
  55. const vb = new Vector3();
  56. const vc = new Vector3();
  57. const vm = new Vector3();
  58. const vs = [ va, vb, vc, vm ];
  59. const na = new Vector3();
  60. const nb = new Vector3();
  61. const nc = new Vector3();
  62. const nm = new Vector3();
  63. const ns = [ na, nb, nc, nm ];
  64. const ca = new Color();
  65. const cb = new Color();
  66. const cc = new Color();
  67. const cm = new Color();
  68. const cs = [ ca, cb, cc, cm ];
  69. const ua = new Vector2();
  70. const ub = new Vector2();
  71. const uc = new Vector2();
  72. const um = new Vector2();
  73. const us = [ ua, ub, uc, um ];
  74. const u2a = new Vector2();
  75. const u2b = new Vector2();
  76. const u2c = new Vector2();
  77. const u2m = new Vector2();
  78. const u2s = [ u2a, u2b, u2c, u2m ];
  79. const attributes = geometry.attributes;
  80. const hasNormals = attributes.normal !== undefined;
  81. const hasColors = attributes.color !== undefined;
  82. const hasUVs = attributes.uv !== undefined;
  83. const hasUV1s = attributes.uv1 !== undefined;
  84. let positions = attributes.position.array;
  85. let normals = hasNormals ? attributes.normal.array : null;
  86. let colors = hasColors ? attributes.color.array : null;
  87. let uvs = hasUVs ? attributes.uv.array : null;
  88. let uv1s = hasUV1s ? attributes.uv1.array : null;
  89. let positions2 = positions;
  90. let normals2 = normals;
  91. let colors2 = colors;
  92. let uvs2 = uvs;
  93. let uv1s2 = uv1s;
  94. let iteration = 0;
  95. let tessellating = true;
  96. function addTriangle( a, b, c ) {
  97. const v1 = vs[ a ];
  98. const v2 = vs[ b ];
  99. const v3 = vs[ c ];
  100. positions2.push( v1.x, v1.y, v1.z );
  101. positions2.push( v2.x, v2.y, v2.z );
  102. positions2.push( v3.x, v3.y, v3.z );
  103. if ( hasNormals ) {
  104. const n1 = ns[ a ];
  105. const n2 = ns[ b ];
  106. const n3 = ns[ c ];
  107. normals2.push( n1.x, n1.y, n1.z );
  108. normals2.push( n2.x, n2.y, n2.z );
  109. normals2.push( n3.x, n3.y, n3.z );
  110. }
  111. if ( hasColors ) {
  112. const c1 = cs[ a ];
  113. const c2 = cs[ b ];
  114. const c3 = cs[ c ];
  115. colors2.push( c1.r, c1.g, c1.b );
  116. colors2.push( c2.r, c2.g, c2.b );
  117. colors2.push( c3.r, c3.g, c3.b );
  118. }
  119. if ( hasUVs ) {
  120. const u1 = us[ a ];
  121. const u2 = us[ b ];
  122. const u3 = us[ c ];
  123. uvs2.push( u1.x, u1.y );
  124. uvs2.push( u2.x, u2.y );
  125. uvs2.push( u3.x, u3.y );
  126. }
  127. if ( hasUV1s ) {
  128. const u21 = u2s[ a ];
  129. const u22 = u2s[ b ];
  130. const u23 = u2s[ c ];
  131. uv1s2.push( u21.x, u21.y );
  132. uv1s2.push( u22.x, u22.y );
  133. uv1s2.push( u23.x, u23.y );
  134. }
  135. }
  136. while ( tessellating && iteration < maxIterations ) {
  137. iteration ++;
  138. tessellating = false;
  139. positions = positions2;
  140. positions2 = [];
  141. if ( hasNormals ) {
  142. normals = normals2;
  143. normals2 = [];
  144. }
  145. if ( hasColors ) {
  146. colors = colors2;
  147. colors2 = [];
  148. }
  149. if ( hasUVs ) {
  150. uvs = uvs2;
  151. uvs2 = [];
  152. }
  153. if ( hasUV1s ) {
  154. uv1s = uv1s2;
  155. uv1s2 = [];
  156. }
  157. for ( let i = 0, i2 = 0, il = positions.length; i < il; i += 9, i2 += 6 ) {
  158. va.fromArray( positions, i + 0 );
  159. vb.fromArray( positions, i + 3 );
  160. vc.fromArray( positions, i + 6 );
  161. if ( hasNormals ) {
  162. na.fromArray( normals, i + 0 );
  163. nb.fromArray( normals, i + 3 );
  164. nc.fromArray( normals, i + 6 );
  165. }
  166. if ( hasColors ) {
  167. ca.fromArray( colors, i + 0 );
  168. cb.fromArray( colors, i + 3 );
  169. cc.fromArray( colors, i + 6 );
  170. }
  171. if ( hasUVs ) {
  172. ua.fromArray( uvs, i2 + 0 );
  173. ub.fromArray( uvs, i2 + 2 );
  174. uc.fromArray( uvs, i2 + 4 );
  175. }
  176. if ( hasUV1s ) {
  177. u2a.fromArray( uv1s, i2 + 0 );
  178. u2b.fromArray( uv1s, i2 + 2 );
  179. u2c.fromArray( uv1s, i2 + 4 );
  180. }
  181. const dab = va.distanceToSquared( vb );
  182. const dbc = vb.distanceToSquared( vc );
  183. const dac = va.distanceToSquared( vc );
  184. if ( dab > maxEdgeLengthSquared || dbc > maxEdgeLengthSquared || dac > maxEdgeLengthSquared ) {
  185. tessellating = true;
  186. if ( dab >= dbc && dab >= dac ) {
  187. vm.lerpVectors( va, vb, 0.5 );
  188. if ( hasNormals ) nm.lerpVectors( na, nb, 0.5 );
  189. if ( hasColors ) cm.lerpColors( ca, cb, 0.5 );
  190. if ( hasUVs ) um.lerpVectors( ua, ub, 0.5 );
  191. if ( hasUV1s ) u2m.lerpVectors( u2a, u2b, 0.5 );
  192. addTriangle( 0, 3, 2 );
  193. addTriangle( 3, 1, 2 );
  194. } else if ( dbc >= dab && dbc >= dac ) {
  195. vm.lerpVectors( vb, vc, 0.5 );
  196. if ( hasNormals ) nm.lerpVectors( nb, nc, 0.5 );
  197. if ( hasColors ) cm.lerpColors( cb, cc, 0.5 );
  198. if ( hasUVs ) um.lerpVectors( ub, uc, 0.5 );
  199. if ( hasUV1s ) u2m.lerpVectors( u2b, u2c, 0.5 );
  200. addTriangle( 0, 1, 3 );
  201. addTriangle( 3, 2, 0 );
  202. } else {
  203. vm.lerpVectors( va, vc, 0.5 );
  204. if ( hasNormals ) nm.lerpVectors( na, nc, 0.5 );
  205. if ( hasColors ) cm.lerpColors( ca, cc, 0.5 );
  206. if ( hasUVs ) um.lerpVectors( ua, uc, 0.5 );
  207. if ( hasUV1s ) u2m.lerpVectors( u2a, u2c, 0.5 );
  208. addTriangle( 0, 1, 3 );
  209. addTriangle( 3, 1, 2 );
  210. }
  211. } else {
  212. addTriangle( 0, 1, 2 );
  213. }
  214. }
  215. }
  216. const geometry2 = new BufferGeometry();
  217. geometry2.setAttribute( 'position', new Float32BufferAttribute( positions2, 3 ) );
  218. if ( hasNormals ) {
  219. geometry2.setAttribute( 'normal', new Float32BufferAttribute( normals2, 3 ) );
  220. }
  221. if ( hasColors ) {
  222. geometry2.setAttribute( 'color', new Float32BufferAttribute( colors2, 3 ) );
  223. }
  224. if ( hasUVs ) {
  225. geometry2.setAttribute( 'uv', new Float32BufferAttribute( uvs2, 2 ) );
  226. }
  227. if ( hasUV1s ) {
  228. geometry2.setAttribute( 'uv1', new Float32BufferAttribute( uv1s2, 2 ) );
  229. }
  230. return geometry2;
  231. }
  232. }
  233. export { TessellateModifier };
粤ICP备19079148号