BufferGeometryUtils.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834
  1. ( function () {
  2. function computeTangents( geometry ) {
  3. geometry.computeTangents();
  4. console.warn( 'THREE.BufferGeometryUtils: .computeTangents() has been removed. Use THREE.BufferGeometry.computeTangents() instead.' );
  5. }
  6. /**
  7. * @param {Array<BufferGeometry>} geometries
  8. * @param {Boolean} useGroups
  9. * @return {BufferGeometry}
  10. */
  11. function mergeBufferGeometries( geometries, useGroups = false ) {
  12. const isIndexed = geometries[ 0 ].index !== null;
  13. const attributesUsed = new Set( Object.keys( geometries[ 0 ].attributes ) );
  14. const morphAttributesUsed = new Set( Object.keys( geometries[ 0 ].morphAttributes ) );
  15. const attributes = {};
  16. const morphAttributes = {};
  17. const morphTargetsRelative = geometries[ 0 ].morphTargetsRelative;
  18. const mergedGeometry = new THREE.BufferGeometry();
  19. let offset = 0;
  20. for ( let i = 0; i < geometries.length; ++ i ) {
  21. const geometry = geometries[ i ];
  22. let attributesCount = 0; // ensure that all geometries are indexed, or none
  23. if ( isIndexed !== ( geometry.index !== null ) ) {
  24. console.error( 'THREE.BufferGeometryUtils: .mergeBufferGeometries() failed with geometry at index ' + i + '. All geometries must have compatible attributes; make sure index attribute exists among all geometries, or in none of them.' );
  25. return null;
  26. } // gather attributes, exit early if they're different
  27. for ( const name in geometry.attributes ) {
  28. if ( ! attributesUsed.has( name ) ) {
  29. console.error( 'THREE.BufferGeometryUtils: .mergeBufferGeometries() failed with geometry at index ' + i + '. All geometries must have compatible attributes; make sure "' + name + '" attribute exists among all geometries, or in none of them.' );
  30. return null;
  31. }
  32. if ( attributes[ name ] === undefined ) attributes[ name ] = [];
  33. attributes[ name ].push( geometry.attributes[ name ] );
  34. attributesCount ++;
  35. } // ensure geometries have the same number of attributes
  36. if ( attributesCount !== attributesUsed.size ) {
  37. console.error( 'THREE.BufferGeometryUtils: .mergeBufferGeometries() failed with geometry at index ' + i + '. Make sure all geometries have the same number of attributes.' );
  38. return null;
  39. } // gather morph attributes, exit early if they're different
  40. if ( morphTargetsRelative !== geometry.morphTargetsRelative ) {
  41. console.error( 'THREE.BufferGeometryUtils: .mergeBufferGeometries() failed with geometry at index ' + i + '. .morphTargetsRelative must be consistent throughout all geometries.' );
  42. return null;
  43. }
  44. for ( const name in geometry.morphAttributes ) {
  45. if ( ! morphAttributesUsed.has( name ) ) {
  46. console.error( 'THREE.BufferGeometryUtils: .mergeBufferGeometries() failed with geometry at index ' + i + '. .morphAttributes must be consistent throughout all geometries.' );
  47. return null;
  48. }
  49. if ( morphAttributes[ name ] === undefined ) morphAttributes[ name ] = [];
  50. morphAttributes[ name ].push( geometry.morphAttributes[ name ] );
  51. } // gather .userData
  52. mergedGeometry.userData.mergedUserData = mergedGeometry.userData.mergedUserData || [];
  53. mergedGeometry.userData.mergedUserData.push( geometry.userData );
  54. if ( useGroups ) {
  55. let count;
  56. if ( isIndexed ) {
  57. count = geometry.index.count;
  58. } else if ( geometry.attributes.position !== undefined ) {
  59. count = geometry.attributes.position.count;
  60. } else {
  61. console.error( 'THREE.BufferGeometryUtils: .mergeBufferGeometries() failed with geometry at index ' + i + '. The geometry must have either an index or a position attribute' );
  62. return null;
  63. }
  64. mergedGeometry.addGroup( offset, count, i );
  65. offset += count;
  66. }
  67. } // merge indices
  68. if ( isIndexed ) {
  69. let indexOffset = 0;
  70. const mergedIndex = [];
  71. for ( let i = 0; i < geometries.length; ++ i ) {
  72. const index = geometries[ i ].index;
  73. for ( let j = 0; j < index.count; ++ j ) {
  74. mergedIndex.push( index.getX( j ) + indexOffset );
  75. }
  76. indexOffset += geometries[ i ].attributes.position.count;
  77. }
  78. mergedGeometry.setIndex( mergedIndex );
  79. } // merge attributes
  80. for ( const name in attributes ) {
  81. const mergedAttribute = mergeBufferAttributes( attributes[ name ] );
  82. if ( ! mergedAttribute ) {
  83. console.error( 'THREE.BufferGeometryUtils: .mergeBufferGeometries() failed while trying to merge the ' + name + ' attribute.' );
  84. return null;
  85. }
  86. mergedGeometry.setAttribute( name, mergedAttribute );
  87. } // merge morph attributes
  88. for ( const name in morphAttributes ) {
  89. const numMorphTargets = morphAttributes[ name ][ 0 ].length;
  90. if ( numMorphTargets === 0 ) break;
  91. mergedGeometry.morphAttributes = mergedGeometry.morphAttributes || {};
  92. mergedGeometry.morphAttributes[ name ] = [];
  93. for ( let i = 0; i < numMorphTargets; ++ i ) {
  94. const morphAttributesToMerge = [];
  95. for ( let j = 0; j < morphAttributes[ name ].length; ++ j ) {
  96. morphAttributesToMerge.push( morphAttributes[ name ][ j ][ i ] );
  97. }
  98. const mergedMorphAttribute = mergeBufferAttributes( morphAttributesToMerge );
  99. if ( ! mergedMorphAttribute ) {
  100. console.error( 'THREE.BufferGeometryUtils: .mergeBufferGeometries() failed while trying to merge the ' + name + ' morphAttribute.' );
  101. return null;
  102. }
  103. mergedGeometry.morphAttributes[ name ].push( mergedMorphAttribute );
  104. }
  105. }
  106. return mergedGeometry;
  107. }
  108. /**
  109. * @param {Array<BufferAttribute>} attributes
  110. * @return {BufferAttribute}
  111. */
  112. function mergeBufferAttributes( attributes ) {
  113. let TypedArray;
  114. let itemSize;
  115. let normalized;
  116. let arrayLength = 0;
  117. for ( let i = 0; i < attributes.length; ++ i ) {
  118. const attribute = attributes[ i ];
  119. if ( attribute.isInterleavedBufferAttribute ) {
  120. console.error( 'THREE.BufferGeometryUtils: .mergeBufferAttributes() failed. InterleavedBufferAttributes are not supported.' );
  121. return null;
  122. }
  123. if ( TypedArray === undefined ) TypedArray = attribute.array.constructor;
  124. if ( TypedArray !== attribute.array.constructor ) {
  125. console.error( 'THREE.BufferGeometryUtils: .mergeBufferAttributes() failed. THREE.BufferAttribute.array must be of consistent array types across matching attributes.' );
  126. return null;
  127. }
  128. if ( itemSize === undefined ) itemSize = attribute.itemSize;
  129. if ( itemSize !== attribute.itemSize ) {
  130. console.error( 'THREE.BufferGeometryUtils: .mergeBufferAttributes() failed. THREE.BufferAttribute.itemSize must be consistent across matching attributes.' );
  131. return null;
  132. }
  133. if ( normalized === undefined ) normalized = attribute.normalized;
  134. if ( normalized !== attribute.normalized ) {
  135. console.error( 'THREE.BufferGeometryUtils: .mergeBufferAttributes() failed. THREE.BufferAttribute.normalized must be consistent across matching attributes.' );
  136. return null;
  137. }
  138. arrayLength += attribute.array.length;
  139. }
  140. const array = new TypedArray( arrayLength );
  141. let offset = 0;
  142. for ( let i = 0; i < attributes.length; ++ i ) {
  143. array.set( attributes[ i ].array, offset );
  144. offset += attributes[ i ].array.length;
  145. }
  146. return new THREE.BufferAttribute( array, itemSize, normalized );
  147. }
  148. /**
  149. * @param {Array<BufferAttribute>} attributes
  150. * @return {Array<InterleavedBufferAttribute>}
  151. */
  152. function interleaveAttributes( attributes ) {
  153. // Interleaves the provided attributes into an THREE.InterleavedBuffer and returns
  154. // a set of InterleavedBufferAttributes for each attribute
  155. let TypedArray;
  156. let arrayLength = 0;
  157. let stride = 0; // calculate the the length and type of the interleavedBuffer
  158. for ( let i = 0, l = attributes.length; i < l; ++ i ) {
  159. const attribute = attributes[ i ];
  160. if ( TypedArray === undefined ) TypedArray = attribute.array.constructor;
  161. if ( TypedArray !== attribute.array.constructor ) {
  162. console.error( 'AttributeBuffers of different types cannot be interleaved' );
  163. return null;
  164. }
  165. arrayLength += attribute.array.length;
  166. stride += attribute.itemSize;
  167. } // Create the set of buffer attributes
  168. const interleavedBuffer = new THREE.InterleavedBuffer( new TypedArray( arrayLength ), stride );
  169. let offset = 0;
  170. const res = [];
  171. const getters = [ 'getX', 'getY', 'getZ', 'getW' ];
  172. const setters = [ 'setX', 'setY', 'setZ', 'setW' ];
  173. for ( let j = 0, l = attributes.length; j < l; j ++ ) {
  174. const attribute = attributes[ j ];
  175. const itemSize = attribute.itemSize;
  176. const count = attribute.count;
  177. const iba = new THREE.InterleavedBufferAttribute( interleavedBuffer, itemSize, offset, attribute.normalized );
  178. res.push( iba );
  179. offset += itemSize; // Move the data for each attribute into the new interleavedBuffer
  180. // at the appropriate offset
  181. for ( let c = 0; c < count; c ++ ) {
  182. for ( let k = 0; k < itemSize; k ++ ) {
  183. iba[ setters[ k ] ]( c, attribute[ getters[ k ] ]( c ) );
  184. }
  185. }
  186. }
  187. return res;
  188. }
  189. /**
  190. * @param {Array<BufferGeometry>} geometry
  191. * @return {number}
  192. */
  193. function estimateBytesUsed( geometry ) {
  194. // Return the estimated memory used by this geometry in bytes
  195. // Calculate using itemSize, count, and BYTES_PER_ELEMENT to account
  196. // for InterleavedBufferAttributes.
  197. let mem = 0;
  198. for ( const name in geometry.attributes ) {
  199. const attr = geometry.getAttribute( name );
  200. mem += attr.count * attr.itemSize * attr.array.BYTES_PER_ELEMENT;
  201. }
  202. const indices = geometry.getIndex();
  203. mem += indices ? indices.count * indices.itemSize * indices.array.BYTES_PER_ELEMENT : 0;
  204. return mem;
  205. }
  206. /**
  207. * @param {BufferGeometry} geometry
  208. * @param {number} tolerance
  209. * @return {BufferGeometry>}
  210. */
  211. function mergeVertices( geometry, tolerance = 1e-4 ) {
  212. tolerance = Math.max( tolerance, Number.EPSILON ); // Generate an index buffer if the geometry doesn't have one, or optimize it
  213. // if it's already available.
  214. const hashToIndex = {};
  215. const indices = geometry.getIndex();
  216. const positions = geometry.getAttribute( 'position' );
  217. const vertexCount = indices ? indices.count : positions.count; // next value for triangle indices
  218. let nextIndex = 0; // attributes and new attribute arrays
  219. const attributeNames = Object.keys( geometry.attributes );
  220. const attrArrays = {};
  221. const morphAttrsArrays = {};
  222. const newIndices = [];
  223. const getters = [ 'getX', 'getY', 'getZ', 'getW' ]; // initialize the arrays
  224. for ( let i = 0, l = attributeNames.length; i < l; i ++ ) {
  225. const name = attributeNames[ i ];
  226. attrArrays[ name ] = [];
  227. const morphAttr = geometry.morphAttributes[ name ];
  228. if ( morphAttr ) {
  229. morphAttrsArrays[ name ] = new Array( morphAttr.length ).fill().map( () => [] );
  230. }
  231. } // convert the error tolerance to an amount of decimal places to truncate to
  232. const decimalShift = Math.log10( 1 / tolerance );
  233. const shiftMultiplier = Math.pow( 10, decimalShift );
  234. for ( let i = 0; i < vertexCount; i ++ ) {
  235. const index = indices ? indices.getX( i ) : i; // Generate a hash for the vertex attributes at the current index 'i'
  236. let hash = '';
  237. for ( let j = 0, l = attributeNames.length; j < l; j ++ ) {
  238. const name = attributeNames[ j ];
  239. const attribute = geometry.getAttribute( name );
  240. const itemSize = attribute.itemSize;
  241. for ( let k = 0; k < itemSize; k ++ ) {
  242. // double tilde truncates the decimal value
  243. hash += `${~ ~ ( attribute[ getters[ k ] ]( index ) * shiftMultiplier )},`;
  244. }
  245. } // Add another reference to the vertex if it's already
  246. // used by another index
  247. if ( hash in hashToIndex ) {
  248. newIndices.push( hashToIndex[ hash ] );
  249. } else {
  250. // copy data to the new index in the attribute arrays
  251. for ( let j = 0, l = attributeNames.length; j < l; j ++ ) {
  252. const name = attributeNames[ j ];
  253. const attribute = geometry.getAttribute( name );
  254. const morphAttr = geometry.morphAttributes[ name ];
  255. const itemSize = attribute.itemSize;
  256. const newarray = attrArrays[ name ];
  257. const newMorphArrays = morphAttrsArrays[ name ];
  258. for ( let k = 0; k < itemSize; k ++ ) {
  259. const getterFunc = getters[ k ];
  260. newarray.push( attribute[ getterFunc ]( index ) );
  261. if ( morphAttr ) {
  262. for ( let m = 0, ml = morphAttr.length; m < ml; m ++ ) {
  263. newMorphArrays[ m ].push( morphAttr[ m ][ getterFunc ]( index ) );
  264. }
  265. }
  266. }
  267. }
  268. hashToIndex[ hash ] = nextIndex;
  269. newIndices.push( nextIndex );
  270. nextIndex ++;
  271. }
  272. } // Generate typed arrays from new attribute arrays and update
  273. // the attributeBuffers
  274. const result = geometry.clone();
  275. for ( let i = 0, l = attributeNames.length; i < l; i ++ ) {
  276. const name = attributeNames[ i ];
  277. const oldAttribute = geometry.getAttribute( name );
  278. const buffer = new oldAttribute.array.constructor( attrArrays[ name ] );
  279. const attribute = new THREE.BufferAttribute( buffer, oldAttribute.itemSize, oldAttribute.normalized );
  280. result.setAttribute( name, attribute ); // Update the attribute arrays
  281. if ( name in morphAttrsArrays ) {
  282. for ( let j = 0; j < morphAttrsArrays[ name ].length; j ++ ) {
  283. const oldMorphAttribute = geometry.morphAttributes[ name ][ j ];
  284. const buffer = new oldMorphAttribute.array.constructor( morphAttrsArrays[ name ][ j ] );
  285. const morphAttribute = new THREE.BufferAttribute( buffer, oldMorphAttribute.itemSize, oldMorphAttribute.normalized );
  286. result.morphAttributes[ name ][ j ] = morphAttribute;
  287. }
  288. }
  289. } // indices
  290. result.setIndex( newIndices );
  291. return result;
  292. }
  293. /**
  294. * @param {BufferGeometry} geometry
  295. * @param {number} drawMode
  296. * @return {BufferGeometry>}
  297. */
  298. function toTrianglesDrawMode( geometry, drawMode ) {
  299. if ( drawMode === THREE.TrianglesDrawMode ) {
  300. console.warn( 'THREE.BufferGeometryUtils.toTrianglesDrawMode(): Geometry already defined as triangles.' );
  301. return geometry;
  302. }
  303. if ( drawMode === THREE.TriangleFanDrawMode || drawMode === THREE.TriangleStripDrawMode ) {
  304. let index = geometry.getIndex(); // generate index if not present
  305. if ( index === null ) {
  306. const indices = [];
  307. const position = geometry.getAttribute( 'position' );
  308. if ( position !== undefined ) {
  309. for ( let i = 0; i < position.count; i ++ ) {
  310. indices.push( i );
  311. }
  312. geometry.setIndex( indices );
  313. index = geometry.getIndex();
  314. } else {
  315. console.error( 'THREE.BufferGeometryUtils.toTrianglesDrawMode(): Undefined position attribute. Processing not possible.' );
  316. return geometry;
  317. }
  318. } //
  319. const numberOfTriangles = index.count - 2;
  320. const newIndices = [];
  321. if ( drawMode === THREE.TriangleFanDrawMode ) {
  322. // gl.TRIANGLE_FAN
  323. for ( let i = 1; i <= numberOfTriangles; i ++ ) {
  324. newIndices.push( index.getX( 0 ) );
  325. newIndices.push( index.getX( i ) );
  326. newIndices.push( index.getX( i + 1 ) );
  327. }
  328. } else {
  329. // gl.TRIANGLE_STRIP
  330. for ( let i = 0; i < numberOfTriangles; i ++ ) {
  331. if ( i % 2 === 0 ) {
  332. newIndices.push( index.getX( i ) );
  333. newIndices.push( index.getX( i + 1 ) );
  334. newIndices.push( index.getX( i + 2 ) );
  335. } else {
  336. newIndices.push( index.getX( i + 2 ) );
  337. newIndices.push( index.getX( i + 1 ) );
  338. newIndices.push( index.getX( i ) );
  339. }
  340. }
  341. }
  342. if ( newIndices.length / 3 !== numberOfTriangles ) {
  343. console.error( 'THREE.BufferGeometryUtils.toTrianglesDrawMode(): Unable to generate correct amount of triangles.' );
  344. } // build final geometry
  345. const newGeometry = geometry.clone();
  346. newGeometry.setIndex( newIndices );
  347. newGeometry.clearGroups();
  348. return newGeometry;
  349. } else {
  350. console.error( 'THREE.BufferGeometryUtils.toTrianglesDrawMode(): Unknown draw mode:', drawMode );
  351. return geometry;
  352. }
  353. }
  354. /**
  355. * Calculates the morphed attributes of a morphed/skinned THREE.BufferGeometry.
  356. * Helpful for Raytracing or Decals.
  357. * @param {Mesh | Line | Points} object An instance of Mesh, Line or Points.
  358. * @return {Object} An Object with original position/normal attributes and morphed ones.
  359. */
  360. function computeMorphedAttributes( object ) {
  361. if ( object.geometry.isBufferGeometry !== true ) {
  362. console.error( 'THREE.BufferGeometryUtils: Geometry is not of type THREE.BufferGeometry.' );
  363. return null;
  364. }
  365. const _vA = new THREE.Vector3();
  366. const _vB = new THREE.Vector3();
  367. const _vC = new THREE.Vector3();
  368. const _tempA = new THREE.Vector3();
  369. const _tempB = new THREE.Vector3();
  370. const _tempC = new THREE.Vector3();
  371. const _morphA = new THREE.Vector3();
  372. const _morphB = new THREE.Vector3();
  373. const _morphC = new THREE.Vector3();
  374. function _calculateMorphedAttributeData( object, material, attribute, morphAttribute, morphTargetsRelative, a, b, c, modifiedAttributeArray ) {
  375. _vA.fromBufferAttribute( attribute, a );
  376. _vB.fromBufferAttribute( attribute, b );
  377. _vC.fromBufferAttribute( attribute, c );
  378. const morphInfluences = object.morphTargetInfluences;
  379. if ( material.morphTargets && morphAttribute && morphInfluences ) {
  380. _morphA.set( 0, 0, 0 );
  381. _morphB.set( 0, 0, 0 );
  382. _morphC.set( 0, 0, 0 );
  383. for ( let i = 0, il = morphAttribute.length; i < il; i ++ ) {
  384. const influence = morphInfluences[ i ];
  385. const morph = morphAttribute[ i ];
  386. if ( influence === 0 ) continue;
  387. _tempA.fromBufferAttribute( morph, a );
  388. _tempB.fromBufferAttribute( morph, b );
  389. _tempC.fromBufferAttribute( morph, c );
  390. if ( morphTargetsRelative ) {
  391. _morphA.addScaledVector( _tempA, influence );
  392. _morphB.addScaledVector( _tempB, influence );
  393. _morphC.addScaledVector( _tempC, influence );
  394. } else {
  395. _morphA.addScaledVector( _tempA.sub( _vA ), influence );
  396. _morphB.addScaledVector( _tempB.sub( _vB ), influence );
  397. _morphC.addScaledVector( _tempC.sub( _vC ), influence );
  398. }
  399. }
  400. _vA.add( _morphA );
  401. _vB.add( _morphB );
  402. _vC.add( _morphC );
  403. }
  404. if ( object.isSkinnedMesh ) {
  405. object.boneTransform( a, _vA );
  406. object.boneTransform( b, _vB );
  407. object.boneTransform( c, _vC );
  408. }
  409. modifiedAttributeArray[ a * 3 + 0 ] = _vA.x;
  410. modifiedAttributeArray[ a * 3 + 1 ] = _vA.y;
  411. modifiedAttributeArray[ a * 3 + 2 ] = _vA.z;
  412. modifiedAttributeArray[ b * 3 + 0 ] = _vB.x;
  413. modifiedAttributeArray[ b * 3 + 1 ] = _vB.y;
  414. modifiedAttributeArray[ b * 3 + 2 ] = _vB.z;
  415. modifiedAttributeArray[ c * 3 + 0 ] = _vC.x;
  416. modifiedAttributeArray[ c * 3 + 1 ] = _vC.y;
  417. modifiedAttributeArray[ c * 3 + 2 ] = _vC.z;
  418. }
  419. const geometry = object.geometry;
  420. const material = object.material;
  421. let a, b, c;
  422. const index = geometry.index;
  423. const positionAttribute = geometry.attributes.position;
  424. const morphPosition = geometry.morphAttributes.position;
  425. const morphTargetsRelative = geometry.morphTargetsRelative;
  426. const normalAttribute = geometry.attributes.normal;
  427. const morphNormal = geometry.morphAttributes.position;
  428. const groups = geometry.groups;
  429. const drawRange = geometry.drawRange;
  430. let i, j, il, jl;
  431. let group, groupMaterial;
  432. let start, end;
  433. const modifiedPosition = new Float32Array( positionAttribute.count * positionAttribute.itemSize );
  434. const modifiedNormal = new Float32Array( normalAttribute.count * normalAttribute.itemSize );
  435. if ( index !== null ) {
  436. // indexed buffer geometry
  437. if ( Array.isArray( material ) ) {
  438. for ( i = 0, il = groups.length; i < il; i ++ ) {
  439. group = groups[ i ];
  440. groupMaterial = material[ group.materialIndex ];
  441. start = Math.max( group.start, drawRange.start );
  442. end = Math.min( group.start + group.count, drawRange.start + drawRange.count );
  443. for ( j = start, jl = end; j < jl; j += 3 ) {
  444. a = index.getX( j );
  445. b = index.getX( j + 1 );
  446. c = index.getX( j + 2 );
  447. _calculateMorphedAttributeData( object, groupMaterial, positionAttribute, morphPosition, morphTargetsRelative, a, b, c, modifiedPosition );
  448. _calculateMorphedAttributeData( object, groupMaterial, normalAttribute, morphNormal, morphTargetsRelative, a, b, c, modifiedNormal );
  449. }
  450. }
  451. } else {
  452. start = Math.max( 0, drawRange.start );
  453. end = Math.min( index.count, drawRange.start + drawRange.count );
  454. for ( i = start, il = end; i < il; i += 3 ) {
  455. a = index.getX( i );
  456. b = index.getX( i + 1 );
  457. c = index.getX( i + 2 );
  458. _calculateMorphedAttributeData( object, material, positionAttribute, morphPosition, morphTargetsRelative, a, b, c, modifiedPosition );
  459. _calculateMorphedAttributeData( object, material, normalAttribute, morphNormal, morphTargetsRelative, a, b, c, modifiedNormal );
  460. }
  461. }
  462. } else if ( positionAttribute !== undefined ) {
  463. // non-indexed buffer geometry
  464. if ( Array.isArray( material ) ) {
  465. for ( i = 0, il = groups.length; i < il; i ++ ) {
  466. group = groups[ i ];
  467. groupMaterial = material[ group.materialIndex ];
  468. start = Math.max( group.start, drawRange.start );
  469. end = Math.min( group.start + group.count, drawRange.start + drawRange.count );
  470. for ( j = start, jl = end; j < jl; j += 3 ) {
  471. a = j;
  472. b = j + 1;
  473. c = j + 2;
  474. _calculateMorphedAttributeData( object, groupMaterial, positionAttribute, morphPosition, morphTargetsRelative, a, b, c, modifiedPosition );
  475. _calculateMorphedAttributeData( object, groupMaterial, normalAttribute, morphNormal, morphTargetsRelative, a, b, c, modifiedNormal );
  476. }
  477. }
  478. } else {
  479. start = Math.max( 0, drawRange.start );
  480. end = Math.min( positionAttribute.count, drawRange.start + drawRange.count );
  481. for ( i = start, il = end; i < il; i += 3 ) {
  482. a = i;
  483. b = i + 1;
  484. c = i + 2;
  485. _calculateMorphedAttributeData( object, material, positionAttribute, morphPosition, morphTargetsRelative, a, b, c, modifiedPosition );
  486. _calculateMorphedAttributeData( object, material, normalAttribute, morphNormal, morphTargetsRelative, a, b, c, modifiedNormal );
  487. }
  488. }
  489. }
  490. const morphedPositionAttribute = new THREE.Float32BufferAttribute( modifiedPosition, 3 );
  491. const morphedNormalAttribute = new THREE.Float32BufferAttribute( modifiedNormal, 3 );
  492. return {
  493. positionAttribute: positionAttribute,
  494. normalAttribute: normalAttribute,
  495. morphedPositionAttribute: morphedPositionAttribute,
  496. morphedNormalAttribute: morphedNormalAttribute
  497. };
  498. }
  499. THREE.BufferGeometryUtils = {};
  500. THREE.BufferGeometryUtils.computeMorphedAttributes = computeMorphedAttributes;
  501. THREE.BufferGeometryUtils.computeTangents = computeTangents;
  502. THREE.BufferGeometryUtils.estimateBytesUsed = estimateBytesUsed;
  503. THREE.BufferGeometryUtils.interleaveAttributes = interleaveAttributes;
  504. THREE.BufferGeometryUtils.mergeBufferAttributes = mergeBufferAttributes;
  505. THREE.BufferGeometryUtils.mergeBufferGeometries = mergeBufferGeometries;
  506. THREE.BufferGeometryUtils.mergeVertices = mergeVertices;
  507. THREE.BufferGeometryUtils.toTrianglesDrawMode = toTrianglesDrawMode;
  508. } )();