BufferGeometry.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206
  1. /**
  2. * @author alteredq / http://alteredqualia.com/
  3. * @author mrdoob / http://mrdoob.com/
  4. */
  5. THREE.BufferGeometry = function () {
  6. Object.defineProperty( this, 'id', { value: THREE.GeometryIdCount ++ } );
  7. this.uuid = THREE.Math.generateUUID();
  8. this.name = '';
  9. this.type = 'BufferGeometry';
  10. this.attributes = {};
  11. this.attributesKeys = [];
  12. this.drawcalls = [];
  13. this.offsets = this.drawcalls; // backwards compatibility
  14. this.boundingBox = null;
  15. this.boundingSphere = null;
  16. };
  17. THREE.BufferGeometry.prototype = {
  18. constructor: THREE.BufferGeometry,
  19. addAttribute: function ( name, attribute ) {
  20. if ( attribute instanceof THREE.BufferAttribute === false && attribute instanceof THREE.InterleavedBufferAttribute === false ) {
  21. THREE.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' );
  22. this.attributes[ name ] = { array: arguments[ 1 ], itemSize: arguments[ 2 ] };
  23. return;
  24. }
  25. this.attributes[ name ] = attribute;
  26. this.attributesKeys = Object.keys( this.attributes );
  27. },
  28. getAttribute: function ( name ) {
  29. return this.attributes[ name ];
  30. },
  31. addDrawCall: function ( start, count, indexOffset ) {
  32. this.drawcalls.push( {
  33. start: start,
  34. count: count,
  35. index: indexOffset !== undefined ? indexOffset : 0
  36. } );
  37. },
  38. applyMatrix: function ( matrix ) {
  39. var position = this.attributes.position;
  40. if ( position !== undefined ) {
  41. matrix.applyToVector3Array( position.array );
  42. position.needsUpdate = true;
  43. }
  44. var normal = this.attributes.normal;
  45. if ( normal !== undefined ) {
  46. var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix );
  47. normalMatrix.applyToVector3Array( normal.array );
  48. normal.needsUpdate = true;
  49. }
  50. if ( this.boundingBox !== null ) {
  51. this.computeBoundingBox();
  52. }
  53. if ( this.boundingSphere !== null ) {
  54. this.computeBoundingSphere();
  55. }
  56. },
  57. center: function () {
  58. this.computeBoundingBox();
  59. var offset = this.boundingBox.center().negate();
  60. this.applyMatrix( new THREE.Matrix4().setPosition( offset ) );
  61. return offset;
  62. },
  63. setFromObject: function ( object ) {
  64. console.log( 'THREE.BufferGeometry.setFromObject(). Converting ', object, this );
  65. var geometry = object.geometry;
  66. var material = object.material;
  67. if ( object instanceof THREE.PointCloud || object instanceof THREE.Line ) {
  68. var positions = new Float32Array( geometry.vertices.length * 3 );
  69. var colors = new Float32Array( geometry.colors.length * 3 );
  70. this.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ).copyVector3sArray( geometry.vertices ) );
  71. this.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ).copyColorsArray( geometry.colors ) );
  72. this.computeBoundingSphere();
  73. } else if ( object instanceof THREE.Mesh ) {
  74. if ( geometry instanceof THREE.DynamicGeometry ) {
  75. this.fromDynamicGeometry( geometry );
  76. } else if ( geometry instanceof THREE.Geometry ) {
  77. this.fromGeometry( geometry, material );
  78. }
  79. }
  80. if ( material.attributes !== undefined ) {
  81. var attributes = material.attributes;
  82. for ( var name in attributes ) {
  83. var attribute = attributes[ name ];
  84. var type = attribute.type;
  85. var array = attribute.value;
  86. switch ( type ) {
  87. case "f":
  88. var floats = new Float32Array( array.length );
  89. this.addAttribute( name, new THREE.BufferAttribute( floats, 1 ).copyArray( array ) );
  90. break;
  91. case "c":
  92. var colors = new Float32Array( array.length * 3 );
  93. this.addAttribute( name, new THREE.BufferAttribute( colors, 3 ).copyColorsArray( array ) );
  94. break;
  95. case "v3":
  96. var colors = new Float32Array( array.length * 3 );
  97. this.addAttribute( name, new THREE.BufferAttribute( colors, 3 ).copyVector3sArray( array ) );
  98. break;
  99. default:
  100. console.warn( 'THREE.BufferGeometry.setFromObject(). TODO: attribute unsupported', type );
  101. break;
  102. }
  103. }
  104. }
  105. return this;
  106. },
  107. updateFromObject: function ( object ) {
  108. var geometry = object.geometry;
  109. if ( geometry.verticesNeedUpdate === true ) {
  110. var attribute = this.attributes.position;
  111. if ( attribute !== undefined ) {
  112. attribute.copyVector3sArray( geometry.vertices );
  113. attribute.needsUpdate = true;
  114. }
  115. geometry.verticesNeedUpdate = false;
  116. }
  117. if ( geometry.colorsNeedUpdate === true ) {
  118. var attribute = this.attributes.color;
  119. if ( attribute !== undefined ) {
  120. attribute.copyColorsArray( geometry.colors );
  121. attribute.needsUpdate = true;
  122. }
  123. geometry.colorsNeedUpdate = false;
  124. }
  125. },
  126. updateFromMaterial: function ( material ) {
  127. if ( material.attributes !== undefined ) {
  128. var attributes = material.attributes;
  129. for ( var name in attributes ) {
  130. var attribute = attributes[ name ];
  131. var type = attribute.type;
  132. var array = attribute.value;
  133. switch ( type ) {
  134. case "f":
  135. this.attributes[ name ].copyArray( array );
  136. this.attributes[ name ].needsUpdate = true;
  137. break;
  138. case "c":
  139. this.attributes[ name ].copyColorsArray( array );
  140. this.attributes[ name ].needsUpdate = true;
  141. break;
  142. case "v3":
  143. this.attributes[ name ].copyVector3sArray( array );
  144. this.attributes[ name ].needsUpdate = true;
  145. break;
  146. }
  147. }
  148. }
  149. },
  150. fromGeometry: function ( geometry, material ) {
  151. material = material || { 'vertexColors': THREE.NoColors };
  152. var vertices = geometry.vertices;
  153. var faces = geometry.faces;
  154. var faceVertexUvs = geometry.faceVertexUvs;
  155. var vertexColors = material.vertexColors;
  156. var hasFaceVertexUv = faceVertexUvs[ 0 ] && faceVertexUvs[ 0 ].length > 0;
  157. var hasFaceVertexUv2 = faceVertexUvs[ 1 ] && faceVertexUvs[ 1 ].length > 0;
  158. var hasFaceVertexNormals = faces[ 0 ] && faces[ 0 ].vertexNormals.length == 3;
  159. var positions = new Float32Array( faces.length * 3 * 3 );
  160. this.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
  161. var normals = new Float32Array( faces.length * 3 * 3 );
  162. this.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) );
  163. if ( vertexColors !== THREE.NoColors ) {
  164. var colors = new Float32Array( faces.length * 3 * 3 );
  165. this.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) );
  166. }
  167. if ( hasFaceVertexUv === true ) {
  168. var uvs = new Float32Array( faces.length * 3 * 2 );
  169. this.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) );
  170. }
  171. if ( hasFaceVertexUv2 === true ) {
  172. var uvs2 = new Float32Array( faces.length * 3 * 2 );
  173. this.addAttribute( 'uv2', new THREE.BufferAttribute( uvs2, 2 ) );
  174. }
  175. for ( var i = 0, i2 = 0, i3 = 0; i < faces.length; i ++, i2 += 6, i3 += 9 ) {
  176. var face = faces[ i ];
  177. var a = vertices[ face.a ];
  178. var b = vertices[ face.b ];
  179. var c = vertices[ face.c ];
  180. positions[ i3 ] = a.x;
  181. positions[ i3 + 1 ] = a.y;
  182. positions[ i3 + 2 ] = a.z;
  183. positions[ i3 + 3 ] = b.x;
  184. positions[ i3 + 4 ] = b.y;
  185. positions[ i3 + 5 ] = b.z;
  186. positions[ i3 + 6 ] = c.x;
  187. positions[ i3 + 7 ] = c.y;
  188. positions[ i3 + 8 ] = c.z;
  189. if ( hasFaceVertexNormals === true ) {
  190. var na = face.vertexNormals[ 0 ];
  191. var nb = face.vertexNormals[ 1 ];
  192. var nc = face.vertexNormals[ 2 ];
  193. normals[ i3 ] = na.x;
  194. normals[ i3 + 1 ] = na.y;
  195. normals[ i3 + 2 ] = na.z;
  196. normals[ i3 + 3 ] = nb.x;
  197. normals[ i3 + 4 ] = nb.y;
  198. normals[ i3 + 5 ] = nb.z;
  199. normals[ i3 + 6 ] = nc.x;
  200. normals[ i3 + 7 ] = nc.y;
  201. normals[ i3 + 8 ] = nc.z;
  202. } else {
  203. var n = face.normal;
  204. normals[ i3 ] = n.x;
  205. normals[ i3 + 1 ] = n.y;
  206. normals[ i3 + 2 ] = n.z;
  207. normals[ i3 + 3 ] = n.x;
  208. normals[ i3 + 4 ] = n.y;
  209. normals[ i3 + 5 ] = n.z;
  210. normals[ i3 + 6 ] = n.x;
  211. normals[ i3 + 7 ] = n.y;
  212. normals[ i3 + 8 ] = n.z;
  213. }
  214. if ( vertexColors === THREE.FaceColors ) {
  215. var fc = face.color;
  216. colors[ i3 ] = fc.r;
  217. colors[ i3 + 1 ] = fc.g;
  218. colors[ i3 + 2 ] = fc.b;
  219. colors[ i3 + 3 ] = fc.r;
  220. colors[ i3 + 4 ] = fc.g;
  221. colors[ i3 + 5 ] = fc.b;
  222. colors[ i3 + 6 ] = fc.r;
  223. colors[ i3 + 7 ] = fc.g;
  224. colors[ i3 + 8 ] = fc.b;
  225. } else if ( vertexColors === THREE.VertexColors ) {
  226. var vca = face.vertexColors[ 0 ];
  227. var vcb = face.vertexColors[ 1 ];
  228. var vcc = face.vertexColors[ 2 ];
  229. colors[ i3 ] = vca.r;
  230. colors[ i3 + 1 ] = vca.g;
  231. colors[ i3 + 2 ] = vca.b;
  232. colors[ i3 + 3 ] = vcb.r;
  233. colors[ i3 + 4 ] = vcb.g;
  234. colors[ i3 + 5 ] = vcb.b;
  235. colors[ i3 + 6 ] = vcc.r;
  236. colors[ i3 + 7 ] = vcc.g;
  237. colors[ i3 + 8 ] = vcc.b;
  238. }
  239. if ( hasFaceVertexUv === true ) {
  240. var vertexUvs = faceVertexUvs[ 0 ][ i ];
  241. if ( vertexUvs !== undefined ) {
  242. var uva = vertexUvs[ 0 ];
  243. var uvb = vertexUvs[ 1 ];
  244. var uvc = vertexUvs[ 2 ];
  245. uvs[ i2 ] = uva.x;
  246. uvs[ i2 + 1 ] = uva.y;
  247. uvs[ i2 + 2 ] = uvb.x;
  248. uvs[ i2 + 3 ] = uvb.y;
  249. uvs[ i2 + 4 ] = uvc.x;
  250. uvs[ i2 + 5 ] = uvc.y;
  251. } else {
  252. THREE.warn( 'THREE.BufferGeometry.fromGeometry(): Undefined vertexUv', i )
  253. }
  254. }
  255. if ( hasFaceVertexUv2 === true ) {
  256. var vertexUvs = faceVertexUvs[ 1 ][ i ];
  257. if ( vertexUvs !== undefined ) {
  258. var uva = vertexUvs[ 0 ];
  259. var uvb = vertexUvs[ 1 ];
  260. var uvc = vertexUvs[ 2 ];
  261. uvs2[ i2 ] = uva.x;
  262. uvs2[ i2 + 1 ] = uva.y;
  263. uvs2[ i2 + 2 ] = uvb.x;
  264. uvs2[ i2 + 3 ] = uvb.y;
  265. uvs2[ i2 + 4 ] = uvc.x;
  266. uvs2[ i2 + 5 ] = uvc.y;
  267. } else {
  268. THREE.warn( 'THREE.BufferGeometry.fromGeometry(): Undefined vertexUv2', i )
  269. }
  270. }
  271. }
  272. this.computeBoundingSphere();
  273. return this;
  274. },
  275. fromDynamicGeometry: function ( geometry ) {
  276. var indices = new Uint16Array( geometry.faces.length * 3 );
  277. this.addAttribute( 'index', new THREE.BufferAttribute( indices, 1 ).copyFacesArray( geometry.faces ) );
  278. var positions = new Float32Array( geometry.vertices.length * 3 );
  279. this.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ).copyVector3sArray( geometry.vertices ) );
  280. var normals = new Float32Array( geometry.normals.length * 3 );
  281. this.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ).copyVector3sArray( geometry.normals ) );
  282. var colors = new Float32Array( geometry.colors.length * 3 );
  283. this.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ).copyVector3sArray( geometry.colors ) );
  284. var uvs = new Float32Array( geometry.uvs.length * 2 );
  285. this.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ).copyVector2sArray( geometry.uvs ) );
  286. this.computeBoundingSphere();
  287. return this;
  288. },
  289. computeBoundingBox: function () {
  290. var vector = new THREE.Vector3();
  291. return function () {
  292. if ( this.boundingBox === null ) {
  293. this.boundingBox = new THREE.Box3();
  294. }
  295. var positions = this.attributes.position.array;
  296. if ( positions ) {
  297. var bb = this.boundingBox;
  298. bb.makeEmpty();
  299. for ( var i = 0, il = positions.length; i < il; i += 3 ) {
  300. vector.fromArray( positions, i );
  301. bb.expandByPoint( vector );
  302. }
  303. }
  304. if ( positions === undefined || positions.length === 0 ) {
  305. this.boundingBox.min.set( 0, 0, 0 );
  306. this.boundingBox.max.set( 0, 0, 0 );
  307. }
  308. if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {
  309. THREE.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this );
  310. }
  311. }
  312. }(),
  313. computeBoundingSphere: function () {
  314. var box = new THREE.Box3();
  315. var vector = new THREE.Vector3();
  316. return function () {
  317. if ( this.boundingSphere === null ) {
  318. this.boundingSphere = new THREE.Sphere();
  319. }
  320. var positions = this.attributes.position.array;
  321. if ( positions ) {
  322. box.makeEmpty();
  323. var center = this.boundingSphere.center;
  324. for ( var i = 0, il = positions.length; i < il; i += 3 ) {
  325. vector.fromArray( positions, i );
  326. box.expandByPoint( vector );
  327. }
  328. box.center( center );
  329. // hoping to find a boundingSphere with a radius smaller than the
  330. // boundingSphere of the boundingBox: sqrt(3) smaller in the best case
  331. var maxRadiusSq = 0;
  332. for ( var i = 0, il = positions.length; i < il; i += 3 ) {
  333. vector.fromArray( positions, i );
  334. maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) );
  335. }
  336. this.boundingSphere.radius = Math.sqrt( maxRadiusSq );
  337. if ( isNaN( this.boundingSphere.radius ) ) {
  338. THREE.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this );
  339. }
  340. }
  341. }
  342. }(),
  343. computeFaceNormals: function () {
  344. // backwards compatibility
  345. },
  346. computeVertexNormals: function () {
  347. var attributes = this.attributes;
  348. if ( attributes.position ) {
  349. var positions = attributes.position.array;
  350. if ( attributes.normal === undefined ) {
  351. this.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( positions.length ), 3 ) );
  352. } else {
  353. // reset existing normals to zero
  354. var normals = attributes.normal.array;
  355. for ( var i = 0, il = normals.length; i < il; i ++ ) {
  356. normals[ i ] = 0;
  357. }
  358. }
  359. var normals = attributes.normal.array;
  360. var vA, vB, vC,
  361. pA = new THREE.Vector3(),
  362. pB = new THREE.Vector3(),
  363. pC = new THREE.Vector3(),
  364. cb = new THREE.Vector3(),
  365. ab = new THREE.Vector3();
  366. // indexed elements
  367. if ( attributes.index ) {
  368. var indices = attributes.index.array;
  369. var offsets = ( this.offsets.length > 0 ? this.offsets : [ { start: 0, count: indices.length, index: 0 } ] );
  370. for ( var j = 0, jl = offsets.length; j < jl; ++ j ) {
  371. var start = offsets[ j ].start;
  372. var count = offsets[ j ].count;
  373. var index = offsets[ j ].index;
  374. for ( var i = start, il = start + count; i < il; i += 3 ) {
  375. vA = ( index + indices[ i ] ) * 3;
  376. vB = ( index + indices[ i + 1 ] ) * 3;
  377. vC = ( index + indices[ i + 2 ] ) * 3;
  378. pA.fromArray( positions, vA );
  379. pB.fromArray( positions, vB );
  380. pC.fromArray( positions, vC );
  381. cb.subVectors( pC, pB );
  382. ab.subVectors( pA, pB );
  383. cb.cross( ab );
  384. normals[ vA ] += cb.x;
  385. normals[ vA + 1 ] += cb.y;
  386. normals[ vA + 2 ] += cb.z;
  387. normals[ vB ] += cb.x;
  388. normals[ vB + 1 ] += cb.y;
  389. normals[ vB + 2 ] += cb.z;
  390. normals[ vC ] += cb.x;
  391. normals[ vC + 1 ] += cb.y;
  392. normals[ vC + 2 ] += cb.z;
  393. }
  394. }
  395. } else {
  396. // non-indexed elements (unconnected triangle soup)
  397. for ( var i = 0, il = positions.length; i < il; i += 9 ) {
  398. pA.fromArray( positions, i );
  399. pB.fromArray( positions, i + 3 );
  400. pC.fromArray( positions, i + 6 );
  401. cb.subVectors( pC, pB );
  402. ab.subVectors( pA, pB );
  403. cb.cross( ab );
  404. normals[ i ] = cb.x;
  405. normals[ i + 1 ] = cb.y;
  406. normals[ i + 2 ] = cb.z;
  407. normals[ i + 3 ] = cb.x;
  408. normals[ i + 4 ] = cb.y;
  409. normals[ i + 5 ] = cb.z;
  410. normals[ i + 6 ] = cb.x;
  411. normals[ i + 7 ] = cb.y;
  412. normals[ i + 8 ] = cb.z;
  413. }
  414. }
  415. this.normalizeNormals();
  416. attributes.normal.needsUpdate = true;
  417. }
  418. },
  419. computeTangents: function () {
  420. // based on http://www.terathon.com/code/tangent.html
  421. // (per vertex tangents)
  422. if ( this.attributes.index === undefined ||
  423. this.attributes.position === undefined ||
  424. this.attributes.normal === undefined ||
  425. this.attributes.uv === undefined ) {
  426. THREE.warn( 'THREE.BufferGeometry: Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()' );
  427. return;
  428. }
  429. var indices = this.attributes.index.array;
  430. var positions = this.attributes.position.array;
  431. var normals = this.attributes.normal.array;
  432. var uvs = this.attributes.uv.array;
  433. var nVertices = positions.length / 3;
  434. if ( this.attributes.tangent === undefined ) {
  435. this.addAttribute( 'tangent', new THREE.BufferAttribute( new Float32Array( 4 * nVertices ), 4 ) );
  436. }
  437. var tangents = this.attributes.tangent.array;
  438. var tan1 = [], tan2 = [];
  439. for ( var k = 0; k < nVertices; k ++ ) {
  440. tan1[ k ] = new THREE.Vector3();
  441. tan2[ k ] = new THREE.Vector3();
  442. }
  443. var vA = new THREE.Vector3(),
  444. vB = new THREE.Vector3(),
  445. vC = new THREE.Vector3(),
  446. uvA = new THREE.Vector2(),
  447. uvB = new THREE.Vector2(),
  448. uvC = new THREE.Vector2(),
  449. x1, x2, y1, y2, z1, z2,
  450. s1, s2, t1, t2, r;
  451. var sdir = new THREE.Vector3(), tdir = new THREE.Vector3();
  452. function handleTriangle( a, b, c ) {
  453. vA.fromArray( positions, a * 3 );
  454. vB.fromArray( positions, b * 3 );
  455. vC.fromArray( positions, c * 3 );
  456. uvA.fromArray( uvs, a * 2 );
  457. uvB.fromArray( uvs, b * 2 );
  458. uvC.fromArray( uvs, c * 2 );
  459. x1 = vB.x - vA.x;
  460. x2 = vC.x - vA.x;
  461. y1 = vB.y - vA.y;
  462. y2 = vC.y - vA.y;
  463. z1 = vB.z - vA.z;
  464. z2 = vC.z - vA.z;
  465. s1 = uvB.x - uvA.x;
  466. s2 = uvC.x - uvA.x;
  467. t1 = uvB.y - uvA.y;
  468. t2 = uvC.y - uvA.y;
  469. r = 1.0 / ( s1 * t2 - s2 * t1 );
  470. sdir.set(
  471. ( t2 * x1 - t1 * x2 ) * r,
  472. ( t2 * y1 - t1 * y2 ) * r,
  473. ( t2 * z1 - t1 * z2 ) * r
  474. );
  475. tdir.set(
  476. ( s1 * x2 - s2 * x1 ) * r,
  477. ( s1 * y2 - s2 * y1 ) * r,
  478. ( s1 * z2 - s2 * z1 ) * r
  479. );
  480. tan1[ a ].add( sdir );
  481. tan1[ b ].add( sdir );
  482. tan1[ c ].add( sdir );
  483. tan2[ a ].add( tdir );
  484. tan2[ b ].add( tdir );
  485. tan2[ c ].add( tdir );
  486. }
  487. var i, il;
  488. var j, jl;
  489. var iA, iB, iC;
  490. if ( this.drawcalls.length === 0 ) {
  491. this.addDrawCall( 0, indices.length, 0 );
  492. }
  493. var drawcalls = this.drawcalls;
  494. for ( j = 0, jl = drawcalls.length; j < jl; ++ j ) {
  495. var start = drawcalls[ j ].start;
  496. var count = drawcalls[ j ].count;
  497. var index = drawcalls[ j ].index;
  498. for ( i = start, il = start + count; i < il; i += 3 ) {
  499. iA = index + indices[ i ];
  500. iB = index + indices[ i + 1 ];
  501. iC = index + indices[ i + 2 ];
  502. handleTriangle( iA, iB, iC );
  503. }
  504. }
  505. var tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3();
  506. var n = new THREE.Vector3(), n2 = new THREE.Vector3();
  507. var w, t, test;
  508. function handleVertex( v ) {
  509. n.fromArray( normals, v * 3 );
  510. n2.copy( n );
  511. t = tan1[ v ];
  512. // Gram-Schmidt orthogonalize
  513. tmp.copy( t );
  514. tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize();
  515. // Calculate handedness
  516. tmp2.crossVectors( n2, t );
  517. test = tmp2.dot( tan2[ v ] );
  518. w = ( test < 0.0 ) ? - 1.0 : 1.0;
  519. tangents[ v * 4 ] = tmp.x;
  520. tangents[ v * 4 + 1 ] = tmp.y;
  521. tangents[ v * 4 + 2 ] = tmp.z;
  522. tangents[ v * 4 + 3 ] = w;
  523. }
  524. for ( j = 0, jl = drawcalls.length; j < jl; ++ j ) {
  525. var start = drawcalls[ j ].start;
  526. var count = drawcalls[ j ].count;
  527. var index = drawcalls[ j ].index;
  528. for ( i = start, il = start + count; i < il; i += 3 ) {
  529. iA = index + indices[ i ];
  530. iB = index + indices[ i + 1 ];
  531. iC = index + indices[ i + 2 ];
  532. handleVertex( iA );
  533. handleVertex( iB );
  534. handleVertex( iC );
  535. }
  536. }
  537. },
  538. /*
  539. Compute the draw offset for large models by chunking the index buffer into chunks of 65k addressable vertices.
  540. This method will effectively rewrite the index buffer and remap all attributes to match the new indices.
  541. WARNING: This method will also expand the vertex count to prevent sprawled triangles across draw offsets.
  542. size - Defaults to 65535 or 4294967296 if extension OES_element_index_uint supported, but allows for larger or smaller chunks.
  543. */
  544. computeOffsets: function ( size ) {
  545. if ( size === undefined ) size = THREE.BufferGeometry.MaxIndex;
  546. var indices = this.attributes.index.array;
  547. var vertices = this.attributes.position.array;
  548. var facesCount = ( indices.length / 3 );
  549. var UintArray = ( ( vertices.length / 3 ) > 65535 && THREE.BufferGeometry.MaxIndex > 65535 ) ? Uint32Array : Uint16Array;
  550. /*
  551. THREE.log("Computing buffers in offsets of "+size+" -> indices:"+indices.length+" vertices:"+vertices.length);
  552. THREE.log("Faces to process: "+(indices.length/3));
  553. THREE.log("Reordering "+verticesCount+" vertices.");
  554. */
  555. var sortedIndices = new UintArray( indices.length );
  556. var indexPtr = 0;
  557. var vertexPtr = 0;
  558. var offsets = [ { start:0, count:0, index:0 } ];
  559. var offset = offsets[ 0 ];
  560. var duplicatedVertices = 0;
  561. var newVerticeMaps = 0;
  562. var faceVertices = new Int32Array( 6 );
  563. var vertexMap = new Int32Array( vertices.length );
  564. var revVertexMap = new Int32Array( vertices.length );
  565. for ( var j = 0; j < vertices.length; j ++ ) { vertexMap[ j ] = - 1; revVertexMap[ j ] = - 1; }
  566. /*
  567. Traverse every face and reorder vertices in the proper offsets of 65k.
  568. We can have more than 'size' entries in the index buffer per offset, but only reference 'size' values.
  569. */
  570. for ( var findex = 0; findex < facesCount; findex ++ ) {
  571. newVerticeMaps = 0;
  572. for ( var vo = 0; vo < 3; vo ++ ) {
  573. var vid = indices[ findex * 3 + vo ];
  574. if ( vertexMap[ vid ] == - 1 ) {
  575. //Unmapped vertice
  576. faceVertices[ vo * 2 ] = vid;
  577. faceVertices[ vo * 2 + 1 ] = - 1;
  578. newVerticeMaps ++;
  579. } else if ( vertexMap[ vid ] < offset.index ) {
  580. //Reused vertices from previous block (duplicate)
  581. faceVertices[ vo * 2 ] = vid;
  582. faceVertices[ vo * 2 + 1 ] = - 1;
  583. duplicatedVertices ++;
  584. } else {
  585. //Reused vertice in the current block
  586. faceVertices[ vo * 2 ] = vid;
  587. faceVertices[ vo * 2 + 1 ] = vertexMap[ vid ];
  588. }
  589. }
  590. var faceMax = vertexPtr + newVerticeMaps;
  591. if ( faceMax > ( offset.index + size ) ) {
  592. var new_offset = { start:indexPtr, count:0, index:vertexPtr };
  593. offsets.push( new_offset );
  594. offset = new_offset;
  595. //Re-evaluate reused vertices in light of new offset.
  596. for ( var v = 0; v < 6; v += 2 ) {
  597. var new_vid = faceVertices[ v + 1 ];
  598. if ( new_vid > - 1 && new_vid < offset.index )
  599. faceVertices[ v + 1 ] = - 1;
  600. }
  601. }
  602. //Reindex the face.
  603. for ( var v = 0; v < 6; v += 2 ) {
  604. var vid = faceVertices[ v ];
  605. var new_vid = faceVertices[ v + 1 ];
  606. if ( new_vid === - 1 )
  607. new_vid = vertexPtr ++;
  608. vertexMap[ vid ] = new_vid;
  609. revVertexMap[ new_vid ] = vid;
  610. sortedIndices[ indexPtr ++ ] = new_vid - offset.index; //XXX overflows at 16bit
  611. offset.count ++;
  612. }
  613. }
  614. /* Move all attribute values to map to the new computed indices , also expand the vertice stack to match our new vertexPtr. */
  615. this.reorderBuffers( sortedIndices, revVertexMap, vertexPtr );
  616. this.offsets = offsets; // TODO: Deprecate
  617. this.drawcalls = offsets;
  618. /*
  619. var orderTime = Date.now();
  620. THREE.log("Reorder time: "+(orderTime-s)+"ms");
  621. THREE.log("Duplicated "+duplicatedVertices+" vertices.");
  622. THREE.log("Compute Buffers time: "+(Date.now()-s)+"ms");
  623. THREE.log("Draw offsets: "+offsets.length);
  624. */
  625. return offsets;
  626. },
  627. merge: function ( geometry, offset ) {
  628. if ( geometry instanceof THREE.BufferGeometry === false ) {
  629. THREE.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry );
  630. return;
  631. }
  632. if ( offset === undefined ) offset = 0;
  633. var attributes = this.attributes;
  634. for ( var key in attributes ) {
  635. if ( geometry.attributes[ key ] === undefined ) continue;
  636. var attribute1 = attributes[ key ];
  637. var attributeArray1 = attribute1.array;
  638. var attribute2 = geometry.attributes[ key ];
  639. var attributeArray2 = attribute2.array;
  640. var attributeSize = attribute2.itemSize;
  641. for ( var i = 0, j = attributeSize * offset; i < attributeArray2.length; i ++, j ++ ) {
  642. attributeArray1[ j ] = attributeArray2[ i ];
  643. }
  644. }
  645. return this;
  646. },
  647. normalizeNormals: function () {
  648. var normals = this.attributes.normal.array;
  649. var x, y, z, n;
  650. for ( var i = 0, il = normals.length; i < il; i += 3 ) {
  651. x = normals[ i ];
  652. y = normals[ i + 1 ];
  653. z = normals[ i + 2 ];
  654. n = 1.0 / Math.sqrt( x * x + y * y + z * z );
  655. normals[ i ] *= n;
  656. normals[ i + 1 ] *= n;
  657. normals[ i + 2 ] *= n;
  658. }
  659. },
  660. /*
  661. reoderBuffers:
  662. Reorder attributes based on a new indexBuffer and indexMap.
  663. indexBuffer - Uint16Array of the new ordered indices.
  664. indexMap - Int32Array where the position is the new vertex ID and the value the old vertex ID for each vertex.
  665. vertexCount - Amount of total vertices considered in this reordering (in case you want to grow the vertice stack).
  666. */
  667. reorderBuffers: function ( indexBuffer, indexMap, vertexCount ) {
  668. /* Create a copy of all attributes for reordering. */
  669. var sortedAttributes = {};
  670. for ( var attr in this.attributes ) {
  671. if ( attr == 'index' )
  672. continue;
  673. var sourceArray = this.attributes[ attr ].array;
  674. sortedAttributes[ attr ] = new sourceArray.constructor( this.attributes[ attr ].itemSize * vertexCount );
  675. }
  676. /* Move attribute positions based on the new index map */
  677. for ( var new_vid = 0; new_vid < vertexCount; new_vid ++ ) {
  678. var vid = indexMap[ new_vid ];
  679. for ( var attr in this.attributes ) {
  680. if ( attr == 'index' )
  681. continue;
  682. var attrArray = this.attributes[ attr ].array;
  683. var attrSize = this.attributes[ attr ].itemSize;
  684. var sortedAttr = sortedAttributes[ attr ];
  685. for ( var k = 0; k < attrSize; k ++ )
  686. sortedAttr[ new_vid * attrSize + k ] = attrArray[ vid * attrSize + k ];
  687. }
  688. }
  689. /* Carry the new sorted buffers locally */
  690. this.attributes[ 'index' ].array = indexBuffer;
  691. for ( var attr in this.attributes ) {
  692. if ( attr == 'index' )
  693. continue;
  694. this.attributes[ attr ].array = sortedAttributes[ attr ];
  695. this.attributes[ attr ].numItems = this.attributes[ attr ].itemSize * vertexCount;
  696. }
  697. },
  698. toJSON: function() {
  699. // we will store all serialization data on 'data'
  700. var data = {};
  701. // add metadata
  702. data.metadata = {
  703. version: 4.4,
  704. type: 'BufferGeometry',
  705. generator: 'BufferGeometry.toJSON'
  706. };
  707. // standard BufferGeometry serialization
  708. data.uuid = this.uuid;
  709. data.type = this.type;
  710. if ( this.name !== '' ) data.name = this.name;
  711. if ( this.parameters !== undefined ) {
  712. var parameters = this.parameters;
  713. for ( var key in parameters ) {
  714. if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ];
  715. }
  716. return data;
  717. }
  718. data.data = { attributes: {} };
  719. var attributes = this.attributes;
  720. var offsets = this.offsets;
  721. var boundingSphere = this.boundingSphere;
  722. for ( var key in attributes ) {
  723. var attribute = attributes[ key ];
  724. var array = Array.prototype.slice.call( attribute.array );
  725. data.data.attributes[ key ] = {
  726. itemSize: attribute.itemSize,
  727. type: attribute.array.constructor.name,
  728. array: array
  729. }
  730. }
  731. if ( offsets.length > 0 ) {
  732. data.data.offsets = JSON.parse( JSON.stringify( offsets ) );
  733. }
  734. if ( boundingSphere !== null ) {
  735. data.data.boundingSphere = {
  736. center: boundingSphere.center.toArray(),
  737. radius: boundingSphere.radius
  738. }
  739. }
  740. return data;
  741. },
  742. clone: function () {
  743. var geometry = new THREE.BufferGeometry();
  744. for ( var attr in this.attributes ) {
  745. var sourceAttr = this.attributes[ attr ];
  746. geometry.addAttribute( attr, sourceAttr.clone() );
  747. }
  748. for ( var i = 0, il = this.offsets.length; i < il; i ++ ) {
  749. var offset = this.offsets[ i ];
  750. geometry.offsets.push( {
  751. start: offset.start,
  752. index: offset.index,
  753. count: offset.count
  754. } );
  755. }
  756. return geometry;
  757. },
  758. dispose: function () {
  759. this.dispatchEvent( { type: 'dispose' } );
  760. }
  761. };
  762. THREE.EventDispatcher.prototype.apply( THREE.BufferGeometry.prototype );
  763. THREE.BufferGeometry.MaxIndex = 65535;