BufferGeometry.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  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. // attributes
  9. this.attributes = {};
  10. // attributes typed arrays are kept only if dynamic flag is set
  11. this.dynamic = true;
  12. // offsets for chunks when using indexed elements
  13. this.offsets = [];
  14. // boundings
  15. this.boundingBox = null;
  16. this.boundingSphere = null;
  17. this.hasTangents = false;
  18. // for compatibility
  19. this.morphTargets = [];
  20. };
  21. THREE.BufferGeometry.prototype = {
  22. constructor: THREE.BufferGeometry,
  23. addAttribute: function( name, type, numItems, itemSize ) {
  24. this.attributes[ name ] = {
  25. itemSize: itemSize,
  26. array: new type( numItems * itemSize )
  27. };
  28. },
  29. applyMatrix: function ( matrix ) {
  30. var positionArray;
  31. var normalArray;
  32. if ( this.attributes[ "position" ] ) positionArray = this.attributes[ "position" ].array;
  33. if ( this.attributes[ "normal" ] ) normalArray = this.attributes[ "normal" ].array;
  34. if ( positionArray !== undefined ) {
  35. matrix.multiplyVector3Array( positionArray );
  36. this.verticesNeedUpdate = true;
  37. }
  38. if ( normalArray !== undefined ) {
  39. var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix );
  40. normalMatrix.multiplyVector3Array( normalArray );
  41. this.normalizeNormals();
  42. this.normalsNeedUpdate = true;
  43. }
  44. },
  45. computeBoundingBox: function () {
  46. if ( this.boundingBox === null ) {
  47. this.boundingBox = new THREE.Box3();
  48. }
  49. var positions = this.attributes[ "position" ].array;
  50. if ( positions ) {
  51. var bb = this.boundingBox;
  52. var x, y, z;
  53. if( positions.length >= 3 ) {
  54. bb.min.x = bb.max.x = positions[ 0 ];
  55. bb.min.y = bb.max.y = positions[ 1 ];
  56. bb.min.z = bb.max.z = positions[ 2 ];
  57. }
  58. for ( var i = 3, il = positions.length; i < il; i += 3 ) {
  59. x = positions[ i ];
  60. y = positions[ i + 1 ];
  61. z = positions[ i + 2 ];
  62. // bounding box
  63. if ( x < bb.min.x ) {
  64. bb.min.x = x;
  65. } else if ( x > bb.max.x ) {
  66. bb.max.x = x;
  67. }
  68. if ( y < bb.min.y ) {
  69. bb.min.y = y;
  70. } else if ( y > bb.max.y ) {
  71. bb.max.y = y;
  72. }
  73. if ( z < bb.min.z ) {
  74. bb.min.z = z;
  75. } else if ( z > bb.max.z ) {
  76. bb.max.z = z;
  77. }
  78. }
  79. }
  80. if ( positions === undefined || positions.length === 0 ) {
  81. this.boundingBox.min.set( 0, 0, 0 );
  82. this.boundingBox.max.set( 0, 0, 0 );
  83. }
  84. },
  85. computeBoundingSphere: function () {
  86. var box = new THREE.Box3();
  87. var vector = new THREE.Vector3();
  88. return function () {
  89. if ( this.boundingSphere === null ) {
  90. this.boundingSphere = new THREE.Sphere();
  91. }
  92. var positions = this.attributes[ "position" ].array;
  93. if ( positions ) {
  94. box.makeEmpty();
  95. var center = this.boundingSphere.center;
  96. for ( var i = 0, il = positions.length; i < il; i += 3 ) {
  97. vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
  98. box.addPoint( vector );
  99. }
  100. box.center( center );
  101. var maxRadiusSq = 0;
  102. for ( var i = 0, il = positions.length; i < il; i += 3 ) {
  103. vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
  104. maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) );
  105. }
  106. this.boundingSphere.radius = Math.sqrt( maxRadiusSq );
  107. }
  108. }
  109. }(),
  110. computeVertexNormals: function () {
  111. if ( this.attributes[ "position" ] ) {
  112. var i, il;
  113. var j, jl;
  114. var nVertexElements = this.attributes[ "position" ].array.length;
  115. if ( this.attributes[ "normal" ] === undefined ) {
  116. this.attributes[ "normal" ] = {
  117. itemSize: 3,
  118. array: new Float32Array( nVertexElements )
  119. };
  120. } else {
  121. // reset existing normals to zero
  122. for ( i = 0, il = this.attributes[ "normal" ].array.length; i < il; i ++ ) {
  123. this.attributes[ "normal" ].array[ i ] = 0;
  124. }
  125. }
  126. var positions = this.attributes[ "position" ].array;
  127. var normals = this.attributes[ "normal" ].array;
  128. var vA, vB, vC, x, y, z,
  129. pA = new THREE.Vector3(),
  130. pB = new THREE.Vector3(),
  131. pC = new THREE.Vector3(),
  132. cb = new THREE.Vector3(),
  133. ab = new THREE.Vector3();
  134. // indexed elements
  135. if ( this.attributes[ "index" ] ) {
  136. var indices = this.attributes[ "index" ].array;
  137. var offsets = this.offsets;
  138. for ( j = 0, jl = offsets.length; j < jl; ++ j ) {
  139. var start = offsets[ j ].start;
  140. var count = offsets[ j ].count;
  141. var index = offsets[ j ].index;
  142. for ( i = start, il = start + count; i < il; i += 3 ) {
  143. vA = index + indices[ i ];
  144. vB = index + indices[ i + 1 ];
  145. vC = index + indices[ i + 2 ];
  146. x = positions[ vA * 3 ];
  147. y = positions[ vA * 3 + 1 ];
  148. z = positions[ vA * 3 + 2 ];
  149. pA.set( x, y, z );
  150. x = positions[ vB * 3 ];
  151. y = positions[ vB * 3 + 1 ];
  152. z = positions[ vB * 3 + 2 ];
  153. pB.set( x, y, z );
  154. x = positions[ vC * 3 ];
  155. y = positions[ vC * 3 + 1 ];
  156. z = positions[ vC * 3 + 2 ];
  157. pC.set( x, y, z );
  158. cb.subVectors( pC, pB );
  159. ab.subVectors( pA, pB );
  160. cb.cross( ab );
  161. normals[ vA * 3 ] += cb.x;
  162. normals[ vA * 3 + 1 ] += cb.y;
  163. normals[ vA * 3 + 2 ] += cb.z;
  164. normals[ vB * 3 ] += cb.x;
  165. normals[ vB * 3 + 1 ] += cb.y;
  166. normals[ vB * 3 + 2 ] += cb.z;
  167. normals[ vC * 3 ] += cb.x;
  168. normals[ vC * 3 + 1 ] += cb.y;
  169. normals[ vC * 3 + 2 ] += cb.z;
  170. }
  171. }
  172. // non-indexed elements (unconnected triangle soup)
  173. } else {
  174. for ( i = 0, il = positions.length; i < il; i += 9 ) {
  175. x = positions[ i ];
  176. y = positions[ i + 1 ];
  177. z = positions[ i + 2 ];
  178. pA.set( x, y, z );
  179. x = positions[ i + 3 ];
  180. y = positions[ i + 4 ];
  181. z = positions[ i + 5 ];
  182. pB.set( x, y, z );
  183. x = positions[ i + 6 ];
  184. y = positions[ i + 7 ];
  185. z = positions[ i + 8 ];
  186. pC.set( x, y, z );
  187. cb.subVectors( pC, pB );
  188. ab.subVectors( pA, pB );
  189. cb.cross( ab );
  190. normals[ i ] = cb.x;
  191. normals[ i + 1 ] = cb.y;
  192. normals[ i + 2 ] = cb.z;
  193. normals[ i + 3 ] = cb.x;
  194. normals[ i + 4 ] = cb.y;
  195. normals[ i + 5 ] = cb.z;
  196. normals[ i + 6 ] = cb.x;
  197. normals[ i + 7 ] = cb.y;
  198. normals[ i + 8 ] = cb.z;
  199. }
  200. }
  201. this.normalizeNormals();
  202. this.normalsNeedUpdate = true;
  203. }
  204. },
  205. normalizeNormals: function () {
  206. var normals = this.attributes[ "normal" ].array;
  207. var x, y, z, n;
  208. for ( var i = 0, il = normals.length; i < il; i += 3 ) {
  209. x = normals[ i ];
  210. y = normals[ i + 1 ];
  211. z = normals[ i + 2 ];
  212. n = 1.0 / Math.sqrt( x * x + y * y + z * z );
  213. normals[ i ] *= n;
  214. normals[ i + 1 ] *= n;
  215. normals[ i + 2 ] *= n;
  216. }
  217. },
  218. computeTangents: function () {
  219. // based on http://www.terathon.com/code/tangent.html
  220. // (per vertex tangents)
  221. if ( this.attributes[ "index" ] === undefined ||
  222. this.attributes[ "position" ] === undefined ||
  223. this.attributes[ "normal" ] === undefined ||
  224. this.attributes[ "uv" ] === undefined ) {
  225. console.warn( "Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()" );
  226. return;
  227. }
  228. var indices = this.attributes[ "index" ].array;
  229. var positions = this.attributes[ "position" ].array;
  230. var normals = this.attributes[ "normal" ].array;
  231. var uvs = this.attributes[ "uv" ].array;
  232. var nVertices = positions.length / 3;
  233. if ( this.attributes[ "tangent" ] === undefined ) {
  234. var nTangentElements = 4 * nVertices;
  235. this.attributes[ "tangent" ] = {
  236. itemSize: 4,
  237. array: new Float32Array( nTangentElements )
  238. };
  239. }
  240. var tangents = this.attributes[ "tangent" ].array;
  241. var tan1 = [], tan2 = [];
  242. for ( var k = 0; k < nVertices; k ++ ) {
  243. tan1[ k ] = new THREE.Vector3();
  244. tan2[ k ] = new THREE.Vector3();
  245. }
  246. var xA, yA, zA,
  247. xB, yB, zB,
  248. xC, yC, zC,
  249. uA, vA,
  250. uB, vB,
  251. uC, vC,
  252. x1, x2, y1, y2, z1, z2,
  253. s1, s2, t1, t2, r;
  254. var sdir = new THREE.Vector3(), tdir = new THREE.Vector3();
  255. function handleTriangle( a, b, c ) {
  256. xA = positions[ a * 3 ];
  257. yA = positions[ a * 3 + 1 ];
  258. zA = positions[ a * 3 + 2 ];
  259. xB = positions[ b * 3 ];
  260. yB = positions[ b * 3 + 1 ];
  261. zB = positions[ b * 3 + 2 ];
  262. xC = positions[ c * 3 ];
  263. yC = positions[ c * 3 + 1 ];
  264. zC = positions[ c * 3 + 2 ];
  265. uA = uvs[ a * 2 ];
  266. vA = uvs[ a * 2 + 1 ];
  267. uB = uvs[ b * 2 ];
  268. vB = uvs[ b * 2 + 1 ];
  269. uC = uvs[ c * 2 ];
  270. vC = uvs[ c * 2 + 1 ];
  271. x1 = xB - xA;
  272. x2 = xC - xA;
  273. y1 = yB - yA;
  274. y2 = yC - yA;
  275. z1 = zB - zA;
  276. z2 = zC - zA;
  277. s1 = uB - uA;
  278. s2 = uC - uA;
  279. t1 = vB - vA;
  280. t2 = vC - vA;
  281. r = 1.0 / ( s1 * t2 - s2 * t1 );
  282. sdir.set(
  283. ( t2 * x1 - t1 * x2 ) * r,
  284. ( t2 * y1 - t1 * y2 ) * r,
  285. ( t2 * z1 - t1 * z2 ) * r
  286. );
  287. tdir.set(
  288. ( s1 * x2 - s2 * x1 ) * r,
  289. ( s1 * y2 - s2 * y1 ) * r,
  290. ( s1 * z2 - s2 * z1 ) * r
  291. );
  292. tan1[ a ].add( sdir );
  293. tan1[ b ].add( sdir );
  294. tan1[ c ].add( sdir );
  295. tan2[ a ].add( tdir );
  296. tan2[ b ].add( tdir );
  297. tan2[ c ].add( tdir );
  298. }
  299. var i, il;
  300. var j, jl;
  301. var iA, iB, iC;
  302. var offsets = this.offsets;
  303. for ( j = 0, jl = offsets.length; j < jl; ++ j ) {
  304. var start = offsets[ j ].start;
  305. var count = offsets[ j ].count;
  306. var index = offsets[ j ].index;
  307. for ( i = start, il = start + count; i < il; i += 3 ) {
  308. iA = index + indices[ i ];
  309. iB = index + indices[ i + 1 ];
  310. iC = index + indices[ i + 2 ];
  311. handleTriangle( iA, iB, iC );
  312. }
  313. }
  314. var tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3();
  315. var n = new THREE.Vector3(), n2 = new THREE.Vector3();
  316. var w, t, test;
  317. function handleVertex( v ) {
  318. n.x = normals[ v * 3 ];
  319. n.y = normals[ v * 3 + 1 ];
  320. n.z = normals[ v * 3 + 2 ];
  321. n2.copy( n );
  322. t = tan1[ v ];
  323. // Gram-Schmidt orthogonalize
  324. tmp.copy( t );
  325. tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize();
  326. // Calculate handedness
  327. tmp2.crossVectors( n2, t );
  328. test = tmp2.dot( tan2[ v ] );
  329. w = ( test < 0.0 ) ? -1.0 : 1.0;
  330. tangents[ v * 4 ] = tmp.x;
  331. tangents[ v * 4 + 1 ] = tmp.y;
  332. tangents[ v * 4 + 2 ] = tmp.z;
  333. tangents[ v * 4 + 3 ] = w;
  334. }
  335. for ( j = 0, jl = offsets.length; j < jl; ++ j ) {
  336. var start = offsets[ j ].start;
  337. var count = offsets[ j ].count;
  338. var index = offsets[ j ].index;
  339. for ( i = start, il = start + count; i < il; i += 3 ) {
  340. iA = index + indices[ i ];
  341. iB = index + indices[ i + 1 ];
  342. iC = index + indices[ i + 2 ];
  343. handleVertex( iA );
  344. handleVertex( iB );
  345. handleVertex( iC );
  346. }
  347. }
  348. this.hasTangents = true;
  349. this.tangentsNeedUpdate = true;
  350. },
  351. clone: function () {
  352. var geometry = new THREE.BufferGeometry();
  353. var types = [ Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array ];
  354. for ( var attr in this.attributes ) {
  355. var sourceAttr = this.attributes[ attr ];
  356. var sourceArray = sourceAttr.array;
  357. var attribute = {
  358. itemSize: sourceAttr.itemSize,
  359. numItems: sourceAttr.numItems,
  360. array: null
  361. };
  362. for ( var i = 0, il = types.length; i < il; i ++ ) {
  363. var type = types[ i ];
  364. if ( sourceArray instanceof type ) {
  365. attribute.array = new type( sourceArray );
  366. break;
  367. }
  368. }
  369. geometry.attributes[ attr ] = attribute;
  370. }
  371. for ( var i = 0, il = this.offsets.length; i < il; i ++ ) {
  372. var offset = this.offsets[ i ];
  373. geometry.offsets.push( {
  374. start: offset.start,
  375. index: offset.index,
  376. count: offset.count
  377. } );
  378. }
  379. return geometry;
  380. },
  381. dispose: function () {
  382. this.dispatchEvent( { type: 'dispose' } );
  383. }
  384. };
  385. THREE.EventDispatcher.prototype.apply( THREE.BufferGeometry.prototype );