EdgeSplitModifier.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. THREE.EdgeSplitModifier = function () {
  2. const A = new THREE.Vector3();
  3. const B = new THREE.Vector3();
  4. const C = new THREE.Vector3();
  5. let positions, normals;
  6. let indexes;
  7. let pointToIndexMap, splitIndexes;
  8. function computeNormals() {
  9. normals = new Float32Array( indexes.length * 3 );
  10. for ( let i = 0; i < indexes.length; i += 3 ) {
  11. let index = indexes[ i ];
  12. A.set(
  13. positions[ 3 * index ],
  14. positions[ 3 * index + 1 ],
  15. positions[ 3 * index + 2 ] );
  16. index = indexes[ i + 1 ];
  17. B.set(
  18. positions[ 3 * index ],
  19. positions[ 3 * index + 1 ],
  20. positions[ 3 * index + 2 ] );
  21. index = indexes[ i + 2 ];
  22. C.set(
  23. positions[ 3 * index ],
  24. positions[ 3 * index + 1 ],
  25. positions[ 3 * index + 2 ] );
  26. C.sub( B );
  27. A.sub( B );
  28. const normal = C.cross( A ).normalize();
  29. for ( let j = 0; j < 3; j ++ ) {
  30. normals[ 3 * ( i + j ) ] = normal.x;
  31. normals[ 3 * ( i + j ) + 1 ] = normal.y;
  32. normals[ 3 * ( i + j ) + 2 ] = normal.z;
  33. }
  34. }
  35. }
  36. function mapPositionsToIndexes() {
  37. pointToIndexMap = Array( positions.length / 3 );
  38. for ( let i = 0; i < indexes.length; i ++ ) {
  39. const index = indexes[ i ];
  40. if ( pointToIndexMap[ index ] == null )
  41. pointToIndexMap[ index ] = [];
  42. pointToIndexMap[ index ].push( i );
  43. }
  44. }
  45. function edgeSplitToGroups( indexes, cutOff, firstIndex ) {
  46. A.set( normals[ 3 * firstIndex ], normals[ 3 * firstIndex + 1 ], normals[ 3 * firstIndex + 2 ] )
  47. .normalize();
  48. const result = {
  49. splitGroup: [],
  50. currentGroup: [ firstIndex ]
  51. };
  52. for ( const j of indexes ) {
  53. if ( j !== firstIndex ) {
  54. B.set( normals[ 3 * j ], normals[ 3 * j + 1 ], normals[ 3 * j + 2 ] )
  55. .normalize();
  56. if ( B.dot( A ) < cutOff )
  57. result.splitGroup.push( j );
  58. else
  59. result.currentGroup.push( j );
  60. }
  61. }
  62. return result;
  63. }
  64. function edgeSplit( indexes, cutOff, original = null ) {
  65. if ( indexes.length === 0 )
  66. return;
  67. const groupResults = [];
  68. for ( const index of indexes )
  69. groupResults.push( edgeSplitToGroups( indexes, cutOff, index ) );
  70. let result = groupResults[ 0 ];
  71. for ( const groupResult of groupResults )
  72. if ( groupResult.currentGroup.length > result.currentGroup.length )
  73. result = groupResult;
  74. if ( original != null )
  75. splitIndexes.push( {
  76. original: original,
  77. indexes: result.currentGroup
  78. } );
  79. if ( result.splitGroup.length )
  80. edgeSplit( result.splitGroup, cutOff, original || result.currentGroup[ 0 ] );
  81. }
  82. this.modify = function ( geometry, cutOffAngle ) {
  83. if ( ! geometry.isBufferGeometry ) {
  84. geometry = new THREE.BufferGeometry().fromGeometry( geometry );
  85. }
  86. if ( geometry.index == null )
  87. geometry = THREE.BufferGeometryUtils.mergeVertices( geometry );
  88. indexes = geometry.index.array;
  89. positions = geometry.getAttribute( "position" ).array;
  90. computeNormals();
  91. mapPositionsToIndexes();
  92. splitIndexes = [];
  93. for ( const vertexIndexes of pointToIndexMap )
  94. edgeSplit( vertexIndexes, Math.cos( cutOffAngle ) - 0.001 );
  95. const newPositions = new Float32Array( positions.length + 3 * splitIndexes.length );
  96. newPositions.set( positions );
  97. const offset = positions.length;
  98. const newIndexes = new Uint32Array( indexes.length );
  99. newIndexes.set( indexes );
  100. for ( let i = 0; i < splitIndexes.length; i ++ ) {
  101. const split = splitIndexes[ i ];
  102. const index = indexes[ split.original ];
  103. newPositions[ offset + 3 * i ] = positions[ 3 * index ];
  104. newPositions[ offset + 3 * i + 1 ] = positions[ 3 * index + 1 ];
  105. newPositions[ offset + 3 * i + 2 ] = positions[ 3 * index + 2 ];
  106. for ( const j of split.indexes )
  107. newIndexes[ j ] = offset / 3 + i;
  108. }
  109. geometry = new THREE.BufferGeometry();
  110. geometry.setAttribute( 'position', new THREE.BufferAttribute( newPositions, 3, true ) );
  111. geometry.setIndex( new THREE.BufferAttribute( newIndexes, 1 ) );
  112. return geometry;
  113. };
  114. };