BufferGeometry.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795
  1. /**
  2. * @author alteredq / http://alteredqualia.com/
  3. */
  4. THREE.BufferGeometry = function () {
  5. this.id = THREE.GeometryIdCount ++;
  6. this.uuid = THREE.Math.generateUUID();
  7. this.name = '';
  8. this.attributes = {};
  9. this.drawcalls = [];
  10. this.offsets = this.drawcalls; // backwards compatibility
  11. this.boundingBox = null;
  12. this.boundingSphere = null;
  13. };
  14. THREE.BufferGeometry.prototype = {
  15. constructor: THREE.BufferGeometry,
  16. addAttribute: function ( name, attribute ) {
  17. if ( attribute instanceof THREE.BufferAttribute === false ) {
  18. console.warn( 'DEPRECATED: BufferGeometry\'s addAttribute() now expects ( name, attribute ).' );
  19. this.attributes[ name ] = { array: arguments[ 1 ], itemSize: arguments[ 2 ] };
  20. return;
  21. }
  22. this.attributes[ name ] = attribute;
  23. },
  24. getAttribute: function ( name ) {
  25. return this.attributes[ name ];
  26. },
  27. addDrawCall: function ( start, count, indexOffset ) {
  28. this.drawcalls.push( {
  29. start: start,
  30. count: count,
  31. index: indexOffset !== undefined ? indexOffset : 0
  32. } );
  33. },
  34. applyMatrix: function ( matrix ) {
  35. var position = this.attributes.position;
  36. if ( position !== undefined ) {
  37. matrix.applyToVector3Array( position.array );
  38. position.needsUpdate = true;
  39. }
  40. var normal = this.attributes.normal;
  41. if ( normal !== undefined ) {
  42. var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix );
  43. normalMatrix.applyToVector3Array( normal.array );
  44. normal.needsUpdate = true;
  45. }
  46. },
  47. computeBoundingBox: function () {
  48. if ( this.boundingBox === null ) {
  49. this.boundingBox = new THREE.Box3();
  50. }
  51. var positions = this.attributes[ "position" ].array;
  52. if ( positions ) {
  53. var bb = this.boundingBox;
  54. if( positions.length >= 3 ) {
  55. bb.min.x = bb.max.x = positions[ 0 ];
  56. bb.min.y = bb.max.y = positions[ 1 ];
  57. bb.min.z = bb.max.z = positions[ 2 ];
  58. }
  59. for ( var i = 3, il = positions.length; i < il; i += 3 ) {
  60. var x = positions[ i ];
  61. var y = positions[ i + 1 ];
  62. var z = positions[ i + 2 ];
  63. // bounding box
  64. if ( x < bb.min.x ) {
  65. bb.min.x = x;
  66. } else if ( x > bb.max.x ) {
  67. bb.max.x = x;
  68. }
  69. if ( y < bb.min.y ) {
  70. bb.min.y = y;
  71. } else if ( y > bb.max.y ) {
  72. bb.max.y = y;
  73. }
  74. if ( z < bb.min.z ) {
  75. bb.min.z = z;
  76. } else if ( z > bb.max.z ) {
  77. bb.max.z = z;
  78. }
  79. }
  80. }
  81. if ( positions === undefined || positions.length === 0 ) {
  82. this.boundingBox.min.set( 0, 0, 0 );
  83. this.boundingBox.max.set( 0, 0, 0 );
  84. }
  85. },
  86. computeBoundingSphere: function () {
  87. var box = new THREE.Box3();
  88. var vector = new THREE.Vector3();
  89. return function () {
  90. if ( this.boundingSphere === null ) {
  91. this.boundingSphere = new THREE.Sphere();
  92. }
  93. var positions = this.attributes[ "position" ].array;
  94. if ( positions ) {
  95. box.makeEmpty();
  96. var center = this.boundingSphere.center;
  97. for ( var i = 0, il = positions.length; i < il; i += 3 ) {
  98. vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
  99. box.addPoint( vector );
  100. }
  101. box.center( center );
  102. var maxRadiusSq = 0;
  103. for ( var i = 0, il = positions.length; i < il; i += 3 ) {
  104. vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
  105. maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) );
  106. }
  107. this.boundingSphere.radius = Math.sqrt( maxRadiusSq );
  108. }
  109. }
  110. }(),
  111. computeFaceNormals: function () {
  112. // backwards compatibility
  113. },
  114. computeVertexNormals: function () {
  115. if ( this.attributes[ "position" ] ) {
  116. var i, il;
  117. var j, jl;
  118. var nVertexElements = this.attributes[ "position" ].array.length;
  119. if ( this.attributes[ "normal" ] === undefined ) {
  120. this.attributes[ "normal" ] = {
  121. itemSize: 3,
  122. array: new Float32Array( nVertexElements )
  123. };
  124. } else {
  125. // reset existing normals to zero
  126. for ( i = 0, il = this.attributes[ "normal" ].array.length; i < il; i ++ ) {
  127. this.attributes[ "normal" ].array[ i ] = 0;
  128. }
  129. }
  130. var positions = this.attributes[ "position" ].array;
  131. var normals = this.attributes[ "normal" ].array;
  132. var vA, vB, vC, x, y, z,
  133. pA = new THREE.Vector3(),
  134. pB = new THREE.Vector3(),
  135. pC = new THREE.Vector3(),
  136. cb = new THREE.Vector3(),
  137. ab = new THREE.Vector3();
  138. // indexed elements
  139. if ( this.attributes[ "index" ] ) {
  140. var indices = this.attributes[ "index" ].array;
  141. var offsets = this.offsets;
  142. for ( j = 0, jl = offsets.length; j < jl; ++ j ) {
  143. var start = offsets[ j ].start;
  144. var count = offsets[ j ].count;
  145. var index = offsets[ j ].index;
  146. for ( i = start, il = start + count; i < il; i += 3 ) {
  147. vA = index + indices[ i ];
  148. vB = index + indices[ i + 1 ];
  149. vC = index + indices[ i + 2 ];
  150. x = positions[ vA * 3 ];
  151. y = positions[ vA * 3 + 1 ];
  152. z = positions[ vA * 3 + 2 ];
  153. pA.set( x, y, z );
  154. x = positions[ vB * 3 ];
  155. y = positions[ vB * 3 + 1 ];
  156. z = positions[ vB * 3 + 2 ];
  157. pB.set( x, y, z );
  158. x = positions[ vC * 3 ];
  159. y = positions[ vC * 3 + 1 ];
  160. z = positions[ vC * 3 + 2 ];
  161. pC.set( x, y, z );
  162. cb.subVectors( pC, pB );
  163. ab.subVectors( pA, pB );
  164. cb.cross( ab );
  165. normals[ vA * 3 ] += cb.x;
  166. normals[ vA * 3 + 1 ] += cb.y;
  167. normals[ vA * 3 + 2 ] += cb.z;
  168. normals[ vB * 3 ] += cb.x;
  169. normals[ vB * 3 + 1 ] += cb.y;
  170. normals[ vB * 3 + 2 ] += cb.z;
  171. normals[ vC * 3 ] += cb.x;
  172. normals[ vC * 3 + 1 ] += cb.y;
  173. normals[ vC * 3 + 2 ] += cb.z;
  174. }
  175. }
  176. // non-indexed elements (unconnected triangle soup)
  177. } else {
  178. for ( i = 0, il = positions.length; i < il; i += 9 ) {
  179. x = positions[ i ];
  180. y = positions[ i + 1 ];
  181. z = positions[ i + 2 ];
  182. pA.set( x, y, z );
  183. x = positions[ i + 3 ];
  184. y = positions[ i + 4 ];
  185. z = positions[ i + 5 ];
  186. pB.set( x, y, z );
  187. x = positions[ i + 6 ];
  188. y = positions[ i + 7 ];
  189. z = positions[ i + 8 ];
  190. pC.set( x, y, z );
  191. cb.subVectors( pC, pB );
  192. ab.subVectors( pA, pB );
  193. cb.cross( ab );
  194. normals[ i ] = cb.x;
  195. normals[ i + 1 ] = cb.y;
  196. normals[ i + 2 ] = cb.z;
  197. normals[ i + 3 ] = cb.x;
  198. normals[ i + 4 ] = cb.y;
  199. normals[ i + 5 ] = cb.z;
  200. normals[ i + 6 ] = cb.x;
  201. normals[ i + 7 ] = cb.y;
  202. normals[ i + 8 ] = cb.z;
  203. }
  204. }
  205. this.normalizeNormals();
  206. this.normalsNeedUpdate = true;
  207. }
  208. },
  209. normalizeNormals: function () {
  210. var normals = this.attributes[ "normal" ].array;
  211. var x, y, z, n;
  212. for ( var i = 0, il = normals.length; i < il; i += 3 ) {
  213. x = normals[ i ];
  214. y = normals[ i + 1 ];
  215. z = normals[ i + 2 ];
  216. n = 1.0 / Math.sqrt( x * x + y * y + z * z );
  217. normals[ i ] *= n;
  218. normals[ i + 1 ] *= n;
  219. normals[ i + 2 ] *= n;
  220. }
  221. },
  222. computeTangents: function () {
  223. // based on http://www.terathon.com/code/tangent.html
  224. // (per vertex tangents)
  225. if ( this.attributes[ "index" ] === undefined ||
  226. this.attributes[ "position" ] === undefined ||
  227. this.attributes[ "normal" ] === undefined ||
  228. this.attributes[ "uv" ] === undefined ) {
  229. console.warn( "Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()" );
  230. return;
  231. }
  232. var indices = this.attributes[ "index" ].array;
  233. var positions = this.attributes[ "position" ].array;
  234. var normals = this.attributes[ "normal" ].array;
  235. var uvs = this.attributes[ "uv" ].array;
  236. var nVertices = positions.length / 3;
  237. if ( this.attributes[ "tangent" ] === undefined ) {
  238. var nTangentElements = 4 * nVertices;
  239. this.attributes[ "tangent" ] = {
  240. itemSize: 4,
  241. array: new Float32Array( nTangentElements )
  242. };
  243. }
  244. var tangents = this.attributes[ "tangent" ].array;
  245. var tan1 = [], tan2 = [];
  246. for ( var k = 0; k < nVertices; k ++ ) {
  247. tan1[ k ] = new THREE.Vector3();
  248. tan2[ k ] = new THREE.Vector3();
  249. }
  250. var xA, yA, zA,
  251. xB, yB, zB,
  252. xC, yC, zC,
  253. uA, vA,
  254. uB, vB,
  255. uC, vC,
  256. x1, x2, y1, y2, z1, z2,
  257. s1, s2, t1, t2, r;
  258. var sdir = new THREE.Vector3(), tdir = new THREE.Vector3();
  259. function handleTriangle( a, b, c ) {
  260. xA = positions[ a * 3 ];
  261. yA = positions[ a * 3 + 1 ];
  262. zA = positions[ a * 3 + 2 ];
  263. xB = positions[ b * 3 ];
  264. yB = positions[ b * 3 + 1 ];
  265. zB = positions[ b * 3 + 2 ];
  266. xC = positions[ c * 3 ];
  267. yC = positions[ c * 3 + 1 ];
  268. zC = positions[ c * 3 + 2 ];
  269. uA = uvs[ a * 2 ];
  270. vA = uvs[ a * 2 + 1 ];
  271. uB = uvs[ b * 2 ];
  272. vB = uvs[ b * 2 + 1 ];
  273. uC = uvs[ c * 2 ];
  274. vC = uvs[ c * 2 + 1 ];
  275. x1 = xB - xA;
  276. x2 = xC - xA;
  277. y1 = yB - yA;
  278. y2 = yC - yA;
  279. z1 = zB - zA;
  280. z2 = zC - zA;
  281. s1 = uB - uA;
  282. s2 = uC - uA;
  283. t1 = vB - vA;
  284. t2 = vC - vA;
  285. r = 1.0 / ( s1 * t2 - s2 * t1 );
  286. sdir.set(
  287. ( t2 * x1 - t1 * x2 ) * r,
  288. ( t2 * y1 - t1 * y2 ) * r,
  289. ( t2 * z1 - t1 * z2 ) * r
  290. );
  291. tdir.set(
  292. ( s1 * x2 - s2 * x1 ) * r,
  293. ( s1 * y2 - s2 * y1 ) * r,
  294. ( s1 * z2 - s2 * z1 ) * r
  295. );
  296. tan1[ a ].add( sdir );
  297. tan1[ b ].add( sdir );
  298. tan1[ c ].add( sdir );
  299. tan2[ a ].add( tdir );
  300. tan2[ b ].add( tdir );
  301. tan2[ c ].add( tdir );
  302. }
  303. var i, il;
  304. var j, jl;
  305. var iA, iB, iC;
  306. var offsets = this.offsets;
  307. for ( j = 0, jl = offsets.length; j < jl; ++ j ) {
  308. var start = offsets[ j ].start;
  309. var count = offsets[ j ].count;
  310. var index = offsets[ j ].index;
  311. for ( i = start, il = start + count; i < il; i += 3 ) {
  312. iA = index + indices[ i ];
  313. iB = index + indices[ i + 1 ];
  314. iC = index + indices[ i + 2 ];
  315. handleTriangle( iA, iB, iC );
  316. }
  317. }
  318. var tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3();
  319. var n = new THREE.Vector3(), n2 = new THREE.Vector3();
  320. var w, t, test;
  321. function handleVertex( v ) {
  322. n.x = normals[ v * 3 ];
  323. n.y = normals[ v * 3 + 1 ];
  324. n.z = normals[ v * 3 + 2 ];
  325. n2.copy( n );
  326. t = tan1[ v ];
  327. // Gram-Schmidt orthogonalize
  328. tmp.copy( t );
  329. tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize();
  330. // Calculate handedness
  331. tmp2.crossVectors( n2, t );
  332. test = tmp2.dot( tan2[ v ] );
  333. w = ( test < 0.0 ) ? -1.0 : 1.0;
  334. tangents[ v * 4 ] = tmp.x;
  335. tangents[ v * 4 + 1 ] = tmp.y;
  336. tangents[ v * 4 + 2 ] = tmp.z;
  337. tangents[ v * 4 + 3 ] = w;
  338. }
  339. for ( j = 0, jl = offsets.length; j < jl; ++ j ) {
  340. var start = offsets[ j ].start;
  341. var count = offsets[ j ].count;
  342. var index = offsets[ j ].index;
  343. for ( i = start, il = start + count; i < il; i += 3 ) {
  344. iA = index + indices[ i ];
  345. iB = index + indices[ i + 1 ];
  346. iC = index + indices[ i + 2 ];
  347. handleVertex( iA );
  348. handleVertex( iB );
  349. handleVertex( iC );
  350. }
  351. }
  352. },
  353. /*
  354. computeOffsets
  355. Compute the draw offset for large models by chunking the index buffer into chunks of 65k addressable vertices.
  356. This method will effectively rewrite the index buffer and remap all attributes to match the new indices.
  357. WARNING: This method will also expand the vertex count to prevent sprawled triangles across draw offsets.
  358. indexBufferSize - Defaults to 65535, but allows for larger or smaller chunks.
  359. */
  360. computeOffsets: function(indexBufferSize) {
  361. var size = indexBufferSize;
  362. if(indexBufferSize === undefined)
  363. size = 65535; //WebGL limits type of index buffer values to 16-bit.
  364. var s = Date.now();
  365. var indices = this.attributes['index'].array;
  366. var vertices = this.attributes['position'].array;
  367. var verticesCount = (vertices.length/3);
  368. var facesCount = (indices.length/3);
  369. /*
  370. console.log("Computing buffers in offsets of "+size+" -> indices:"+indices.length+" vertices:"+vertices.length);
  371. console.log("Faces to process: "+(indices.length/3));
  372. console.log("Reordering "+verticesCount+" vertices.");
  373. */
  374. var sortedIndices = new Uint16Array( indices.length ); //16-bit buffers
  375. var indexPtr = 0;
  376. var vertexPtr = 0;
  377. var offsets = [ { start:0, count:0, index:0 } ];
  378. var offset = offsets[0];
  379. var duplicatedVertices = 0;
  380. var newVerticeMaps = 0;
  381. var faceVertices = new Int32Array(6);
  382. var vertexMap = new Int32Array( vertices.length );
  383. var revVertexMap = new Int32Array( vertices.length );
  384. for(var j = 0; j < vertices.length; j++) { vertexMap[j] = -1; revVertexMap[j] = -1; }
  385. /*
  386. Traverse every face and reorder vertices in the proper offsets of 65k.
  387. We can have more than 65k entries in the index buffer per offset, but only reference 65k values.
  388. */
  389. for(var findex = 0; findex < facesCount; findex++) {
  390. newVerticeMaps = 0;
  391. for(var vo = 0; vo < 3; vo++) {
  392. var vid = indices[ findex*3 + vo ];
  393. if(vertexMap[vid] == -1) {
  394. //Unmapped vertice
  395. faceVertices[vo*2] = vid;
  396. faceVertices[vo*2+1] = -1;
  397. newVerticeMaps++;
  398. } else if(vertexMap[vid] < offset.index) {
  399. //Reused vertices from previous block (duplicate)
  400. faceVertices[vo*2] = vid;
  401. faceVertices[vo*2+1] = -1;
  402. duplicatedVertices++;
  403. } else {
  404. //Reused vertice in the current block
  405. faceVertices[vo*2] = vid;
  406. faceVertices[vo*2+1] = vertexMap[vid];
  407. }
  408. }
  409. var faceMax = vertexPtr + newVerticeMaps;
  410. if(faceMax > (offset.index + size)) {
  411. var new_offset = { start:indexPtr, count:0, index:vertexPtr };
  412. offsets.push(new_offset);
  413. offset = new_offset;
  414. //Re-evaluate reused vertices in light of new offset.
  415. for(var v = 0; v < 6; v+=2) {
  416. var new_vid = faceVertices[v+1];
  417. if(new_vid > -1 && new_vid < offset.index)
  418. faceVertices[v+1] = -1;
  419. }
  420. }
  421. //Reindex the face.
  422. for(var v = 0; v < 6; v+=2) {
  423. var vid = faceVertices[v];
  424. var new_vid = faceVertices[v+1];
  425. if(new_vid === -1)
  426. new_vid = vertexPtr++;
  427. vertexMap[vid] = new_vid;
  428. revVertexMap[new_vid] = vid;
  429. sortedIndices[indexPtr++] = new_vid - offset.index; //XXX overflows at 16bit
  430. offset.count++;
  431. }
  432. }
  433. /* Move all attribute values to map to the new computed indices , also expand the vertice stack to match our new vertexPtr. */
  434. this.reorderBuffers(sortedIndices, revVertexMap, vertexPtr);
  435. this.offsets = offsets;
  436. /*
  437. var orderTime = Date.now();
  438. console.log("Reorder time: "+(orderTime-s)+"ms");
  439. console.log("Duplicated "+duplicatedVertices+" vertices.");
  440. console.log("Compute Buffers time: "+(Date.now()-s)+"ms");
  441. console.log("Draw offsets: "+offsets.length);
  442. */
  443. return offsets;
  444. },
  445. /*
  446. reoderBuffers:
  447. Reorder attributes based on a new indexBuffer and indexMap.
  448. indexBuffer - Uint16Array of the new ordered indices.
  449. indexMap - Int32Array where the position is the new vertex ID and the value the old vertex ID for each vertex.
  450. vertexCount - Amount of total vertices considered in this reordering (in case you want to grow the vertice stack).
  451. */
  452. reorderBuffers: function(indexBuffer, indexMap, vertexCount) {
  453. /* Create a copy of all attributes for reordering. */
  454. var sortedAttributes = {};
  455. var types = [ Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array ];
  456. for( var attr in this.attributes ) {
  457. if(attr == 'index')
  458. continue;
  459. var sourceArray = this.attributes[attr].array;
  460. for ( var i = 0, il = types.length; i < il; i++ ) {
  461. var type = types[i];
  462. if (sourceArray instanceof type) {
  463. sortedAttributes[attr] = new type( this.attributes[attr].itemSize * vertexCount );
  464. break;
  465. }
  466. }
  467. }
  468. /* Move attribute positions based on the new index map */
  469. for(var new_vid = 0; new_vid < vertexCount; new_vid++) {
  470. var vid = indexMap[new_vid];
  471. for ( var attr in this.attributes ) {
  472. if(attr == 'index')
  473. continue;
  474. var attrArray = this.attributes[attr].array;
  475. var attrSize = this.attributes[attr].itemSize;
  476. var sortedAttr = sortedAttributes[attr];
  477. for(var k = 0; k < attrSize; k++)
  478. sortedAttr[ new_vid * attrSize + k ] = attrArray[ vid * attrSize + k ];
  479. }
  480. }
  481. /* Carry the new sorted buffers locally */
  482. this.attributes['index'].array = indexBuffer;
  483. for ( var attr in this.attributes ) {
  484. if(attr == 'index')
  485. continue;
  486. this.attributes[attr].array = sortedAttributes[attr];
  487. this.attributes[attr].numItems = this.attributes[attr].itemSize * vertexCount;
  488. }
  489. },
  490. clone: function () {
  491. var geometry = new THREE.BufferGeometry();
  492. var types = [ Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array ];
  493. for ( var attr in this.attributes ) {
  494. var sourceAttr = this.attributes[ attr ];
  495. var sourceArray = sourceAttr.array;
  496. var attribute = {
  497. itemSize: sourceAttr.itemSize,
  498. array: null
  499. };
  500. for ( var i = 0, il = types.length; i < il; i ++ ) {
  501. var type = types[ i ];
  502. if ( sourceArray instanceof type ) {
  503. attribute.array = new type( sourceArray );
  504. break;
  505. }
  506. }
  507. geometry.attributes[ attr ] = attribute;
  508. }
  509. for ( var i = 0, il = this.offsets.length; i < il; i ++ ) {
  510. var offset = this.offsets[ i ];
  511. geometry.offsets.push( {
  512. start: offset.start,
  513. index: offset.index,
  514. count: offset.count
  515. } );
  516. }
  517. return geometry;
  518. },
  519. dispose: function () {
  520. this.dispatchEvent( { type: 'dispose' } );
  521. }
  522. };
  523. THREE.EventDispatcher.prototype.apply( THREE.BufferGeometry.prototype );