BufferGeometry.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. /**
  2. * @author simonThiele / https://github.com/simonThiele
  3. */
  4. module( "BufferGeometry" );
  5. var DegToRad = Math.PI / 180;
  6. test( "add / delete Attribute", function() {
  7. var geometry = new THREE.BufferGeometry();
  8. var attributeName = "position";
  9. ok ( geometry.attributes[attributeName] === undefined , 'no attribute defined' );
  10. geometry.addAttribute( attributeName, new THREE.BufferAttribute( new Float32Array( [1, 2, 3], 1 ) ) );
  11. ok ( geometry.attributes[attributeName] !== undefined , 'attribute is defined' );
  12. geometry.removeAttribute( attributeName );
  13. ok ( geometry.attributes[attributeName] === undefined , 'no attribute defined' );
  14. });
  15. test( "applyMatrix", function() {
  16. var geometry = new THREE.BufferGeometry();
  17. geometry.addAttribute( "position", new THREE.BufferAttribute( new Float32Array(6), 3 ) );
  18. var matrix = new THREE.Matrix4().set(
  19. 1, 0, 0, 1.5,
  20. 0, 1, 0, -2,
  21. 0, 0, 1, 3,
  22. 0, 0, 0, 1
  23. );
  24. geometry.applyMatrix(matrix);
  25. var position = geometry.attributes.position.array;
  26. var m = matrix.elements;
  27. ok( position[0] === m[12] && position[1] === m[13] && position[2] === m[14], "position was extracted from matrix" );
  28. ok( position[3] === m[12] && position[4] === m[13] && position[5] === m[14], "position was extracted from matrix twice" );
  29. ok( geometry.attributes.position.version === 1, "version was increased during update" );
  30. });
  31. test( "rotateX/Y/Z", function() {
  32. var geometry = new THREE.BufferGeometry();
  33. geometry.addAttribute( "position", new THREE.BufferAttribute( new Float32Array([1, 2, 3, 4, 5, 6]), 3 ) );
  34. var pos = geometry.attributes.position.array;
  35. geometry.rotateX( 180 * DegToRad );
  36. // object was rotated around x so all items should be flipped but the x ones
  37. ok( pos[0] === 1 && pos[1] === -2 && pos[2] === -3 &&
  38. pos[3] === 4 && pos[4] === -5 && pos[5] === -6, "vertices were rotated around x by 180 degrees" );
  39. geometry.rotateY( 180 * DegToRad );
  40. // vertices were rotated around y so all items should be flipped again but the y ones
  41. ok( pos[0] === -1 && pos[1] === -2 && pos[2] === 3 &&
  42. pos[3] === -4 && pos[4] === -5 && pos[5] === 6, "vertices were rotated around y by 180 degrees" );
  43. geometry.rotateZ( 180 * DegToRad );
  44. // vertices were rotated around z so all items should be flipped again but the z ones
  45. ok( pos[0] === 1 && pos[1] === 2 && pos[2] === 3 &&
  46. pos[3] === 4 && pos[4] === 5 && pos[5] === 6, "vertices were rotated around z by 180 degrees" );
  47. });
  48. test( "translate", function() {
  49. var geometry = new THREE.BufferGeometry();
  50. geometry.addAttribute( "position", new THREE.BufferAttribute( new Float32Array([1, 2, 3, 4, 5, 6]), 3 ) );
  51. var pos = geometry.attributes.position.array;
  52. geometry.translate( 10, 20, 30 );
  53. ok( pos[0] === 11 && pos[1] === 22 && pos[2] === 33 &&
  54. pos[3] === 14 && pos[4] === 25 && pos[5] === 36, "vertices were translated" );
  55. });
  56. test( "scale", function() {
  57. var geometry = new THREE.BufferGeometry();
  58. geometry.addAttribute( "position", new THREE.BufferAttribute( new Float32Array([-1, -1, -1, 2, 2, 2]), 3 ) );
  59. var pos = geometry.attributes.position.array;
  60. geometry.scale( 1, 2, 3 );
  61. ok( pos[0] === -1 && pos[1] === -2 && pos[2] === -3 &&
  62. pos[3] === 2 && pos[4] === 4 && pos[5] === 6, "vertices were scaled" );
  63. });
  64. test( "center", function() {
  65. var geometry = new THREE.BufferGeometry();
  66. geometry.addAttribute( "position", new THREE.BufferAttribute( new Float32Array([
  67. -1, -1, -1,
  68. 1, 1, 1,
  69. 4, 4, 4
  70. ]), 3 ) );
  71. geometry.center();
  72. var pos = geometry.attributes.position.array;
  73. var bb = geometry.boundingBox;
  74. // the boundingBox should go from (-1, -1, -1) to (4, 4, 4) so it has a size of (5, 5, 5)
  75. // after centering it the vertices should be placed between (-2.5, -2.5, -2.5) and (2.5, 2.5, 2.5)
  76. ok( pos[0] === -2.5 && pos[1] === -2.5 && pos[2] === -2.5 &&
  77. pos[3] === -0.5 && pos[4] === -0.5 && pos[5] === -0.5 &&
  78. pos[6] === 2.5 && pos[7] === 2.5 && pos[8] === 2.5, "vertices were replaced by boundingBox dimensions" );
  79. });
  80. test( "setFromObject", function() {
  81. var lineGeo = new THREE.Geometry();
  82. lineGeo.vertices.push(
  83. new THREE.Vector3( -10, 0, 0 ),
  84. new THREE.Vector3( 0, 10, 0 ),
  85. new THREE.Vector3( 10, 0, 0 )
  86. );
  87. lineGeo.colors.push(
  88. new THREE.Color(1, 0, 0 ),
  89. new THREE.Color(0, 1, 0 ),
  90. new THREE.Color(0, 0, 1 )
  91. );
  92. var line = new THREE.Line( lineGeo, null );
  93. var geometry = new THREE.BufferGeometry().setFromObject( line );
  94. var pos = geometry.attributes.position.array;
  95. var col = geometry.attributes.color.array;
  96. var v = lineGeo.vertices;
  97. var c = lineGeo.colors;
  98. ok(
  99. // position exists
  100. pos !== undefined &&
  101. // vertex arrays have the same size
  102. v.length * 3 === pos.length &&
  103. // there are three complete vertices (each vertex contains three values)
  104. geometry.attributes.position.count === 3 &&
  105. // check if both arrays contains the same data
  106. pos[0] === v[0].x && pos[1] === v[0].y && pos[2] === v[0].z &&
  107. pos[3] === v[1].x && pos[4] === v[1].y && pos[5] === v[1].z &&
  108. pos[6] === v[2].x && pos[7] === v[2].y && pos[8] === v[2].z
  109. , "positions are equal" );
  110. ok(
  111. // color exists
  112. col !== undefined &&
  113. // color arrays have the same size
  114. c.length * 3 === col.length &&
  115. // there are three complete colors (each color contains three values)
  116. geometry.attributes.color.count === 3 &&
  117. // check if both arrays contains the same data
  118. col[0] === c[0].r && col[1] === c[0].g && col[2] === c[0].b &&
  119. col[3] === c[1].r && col[4] === c[1].g && col[5] === c[1].b &&
  120. col[6] === c[2].r && col[7] === c[2].g && col[8] === c[2].b
  121. , "colors are equal" );
  122. });
  123. test( "computeBoundingBox", function() {
  124. var bb = getBBForVertices( [-1, -2, -3, 13, -2, -3.5, -1, -20, 0, -4, 5, 6] );
  125. ok( bb.min.x === -4 && bb.min.y === -20 && bb.min.z === -3.5, "min values are set correctly" );
  126. ok( bb.max.x === 13 && bb.max.y === 5 && bb.max.z === 6, "max values are set correctly" );
  127. bb = getBBForVertices( [] );
  128. ok( bb.min.x === 0 && bb.min.y === 0 && bb.min.z === 0, "since there are no values given, the bb has size = 0" );
  129. ok( bb.max.x === 0 && bb.max.y === 0 && bb.max.z === 0, "since there are no values given, the bb has size = 0" );
  130. bb = getBBForVertices( [-1, -1, -1] );
  131. ok( bb.min.x === bb.max.x && bb.min.y === bb.max.y && bb.min.z === bb.max.z, "since there is only one vertex, max and min are equal" );
  132. ok( bb.min.x === -1 && bb.min.y === -1 && bb.min.z === -1, "since there is only one vertex, min and max are this vertex" );
  133. });
  134. test( "computeBoundingSphere", function() {
  135. var bs = getBSForVertices( [-10, 0, 0, 10, 0, 0] );
  136. ok( bs.radius === (10 + 10) / 2, "radius is equal to deltaMinMax / 2" )
  137. ok( bs.center.x === 0 && bs.center.y === 0 && bs.center.y === 0, "bounding sphere is at ( 0, 0, 0 )" )
  138. var bs = getBSForVertices( [-5, 11, -3, 5, -11, 3] );
  139. var radius = new THREE.Vector3(5, 11, 3).length();
  140. ok( bs.radius === radius, "radius is equal to directionLength" )
  141. ok( bs.center.x === 0 && bs.center.y === 0 && bs.center.y === 0, "bounding sphere is at ( 0, 0, 0 )" )
  142. });
  143. function getBBForVertices(vertices) {
  144. var geometry = new THREE.BufferGeometry();
  145. geometry.addAttribute( "position", new THREE.BufferAttribute( new Float32Array(vertices), 3 ) );
  146. geometry.computeBoundingBox();
  147. return geometry.boundingBox;
  148. }
  149. function getBSForVertices(vertices) {
  150. var geometry = new THREE.BufferGeometry();
  151. geometry.addAttribute( "position", new THREE.BufferAttribute( new Float32Array(vertices), 3 ) );
  152. geometry.computeBoundingSphere();
  153. return geometry.boundingSphere;
  154. }
  155. test( "computeVertexNormals", function() {
  156. // get normals for a counter clockwise created triangle
  157. var normals = getNormalsForVertices([-1, 0, 0, 1, 0, 0, 0, 1, 0]);
  158. ok( normals[0] === 0 && normals[1] === 0 && normals[2] === 1,
  159. "first normal is pointing to screen since the the triangle was created counter clockwise" );
  160. ok( normals[3] === 0 && normals[4] === 0 && normals[5] === 1,
  161. "second normal is pointing to screen since the the triangle was created counter clockwise" );
  162. ok( normals[6] === 0 && normals[7] === 0 && normals[8] === 1,
  163. "third normal is pointing to screen since the the triangle was created counter clockwise" );
  164. // get normals for a clockwise created triangle
  165. var normals = getNormalsForVertices([1, 0, 0, -1, 0, 0, 0, 1, 0]);
  166. ok( normals[0] === 0 && normals[1] === 0 && normals[2] === -1,
  167. "first normal is pointing to screen since the the triangle was created clockwise" );
  168. ok( normals[3] === 0 && normals[4] === 0 && normals[5] === -1,
  169. "second normal is pointing to screen since the the triangle was created clockwise" );
  170. ok( normals[6] === 0 && normals[7] === 0 && normals[8] === -1,
  171. "third normal is pointing to screen since the the triangle was created clockwise" );
  172. var normals = getNormalsForVertices([0, 0, 1, 0, 0, -1, 1, 1, 0]);
  173. // the triangle is rotated by 45 degrees to the right so the normals of the three vertices
  174. // should point to (1, -1, 0).normalized(). The simplest solution is to check against a normalized
  175. // vector (1, -1, 0) but you will get calculation errors because of floating calculations so another
  176. // valid technique is to create a vector which stands in 90 degrees to the normals and calculate the
  177. // dot product which is the cos of the angle between them. This should be < floating calculation error
  178. // which can be taken from Number.EPSILON
  179. var direction = new THREE.Vector3(1, 1, 0).normalize(); // a vector which should have 90 degrees difference to normals
  180. var difference = direction.dot( new THREE.Vector3( normals[0], normals[1], normals[2] ) );
  181. ok( difference < Number.EPSILON, "normal is equal to reference vector");
  182. // get normals for a line should be NAN because you need min a triangle to calculate normals
  183. var normals = getNormalsForVertices([1, 0, 0, -1, 0, 0]);
  184. for (var i = 0; i < normals.length; i++) {
  185. ok ( !normals[i], "normals can't be calculated which is good");
  186. }
  187. });
  188. function getNormalsForVertices(vertices) {
  189. var geometry = new THREE.BufferGeometry();
  190. geometry.addAttribute( "position", new THREE.BufferAttribute( new Float32Array(vertices), 3 ) );
  191. geometry.computeVertexNormals();
  192. ok( geometry.attributes.normal !== undefined, "normal attribute was created" );
  193. return geometry.attributes.normal.array;
  194. }
  195. test( "merge", function() {
  196. var geometry1 = new THREE.BufferGeometry();
  197. geometry1.addAttribute( "attrName", new THREE.BufferAttribute( new Float32Array([1, 2, 3, 0, 0, 0]), 3 ) );
  198. var geometry2 = new THREE.BufferGeometry();
  199. geometry2.addAttribute( "attrName", new THREE.BufferAttribute( new Float32Array([4, 5, 6]), 3 ) );
  200. var attr = geometry1.attributes.attrName.array;
  201. geometry1.merge(geometry2, 1);
  202. // merged array should be 1, 2, 3, 4, 5, 6
  203. for (var i = 0; i < attr.length; i++) {
  204. ok( attr[i] === i + 1, "");
  205. }
  206. geometry1.merge(geometry2);
  207. ok( attr[0] === 4 && attr[1] === 5 && attr[2] === 6, "copied the 3 attributes without offset" );
  208. });
  209. test( "copy", function() {
  210. var geometry = new THREE.BufferGeometry();
  211. geometry.addAttribute( "attrName", new THREE.BufferAttribute( new Float32Array([1, 2, 3, 4, 5, 6]), 3 ) );
  212. geometry.addAttribute( "attrName2", new THREE.BufferAttribute( new Float32Array([0, 1, 3, 5, 6]), 1 ) );
  213. var copy = new THREE.BufferGeometry().copy(geometry);
  214. ok( copy !== geometry && geometry.id !== copy.id, "new object was created" );
  215. Object.keys(geometry.attributes).forEach(function(key) {
  216. var attribute = geometry.attributes[key];
  217. ok( attribute !== undefined, "all attributes where copied");
  218. for (var i = 0; i < attribute.array.length; i++) {
  219. ok( attribute.array[i] === copy.attributes[key].array[i], "values of the attribute are equal" );
  220. }
  221. });
  222. });