Object3D.tests.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868
  1. /* global QUnit */
  2. import { Object3D } from '../../../../src/core/Object3D';
  3. import { Vector3 } from '../../../../src/math/Vector3';
  4. import { Euler } from '../../../../src/math/Euler';
  5. import { Quaternion } from '../../../../src/math/Quaternion';
  6. import { Matrix4 } from '../../../../src/math/Matrix4';
  7. import {
  8. x,
  9. y,
  10. z,
  11. w,
  12. eps
  13. } from '../math/Constants.tests';
  14. export default QUnit.module( 'Core', () => {
  15. QUnit.module( 'Object3D', () => {
  16. var RadToDeg = 180 / Math.PI;
  17. var eulerEquals = function ( a, b, tolerance ) {
  18. tolerance = tolerance || 0.0001;
  19. if ( a.order != b.order ) {
  20. return false;
  21. }
  22. return (
  23. Math.abs( a.x - b.x ) <= tolerance &&
  24. Math.abs( a.y - b.y ) <= tolerance &&
  25. Math.abs( a.z - b.z ) <= tolerance
  26. );
  27. };
  28. // INHERITANCE
  29. QUnit.todo( "Extending", ( assert ) => {
  30. assert.ok( false, "everything's gonna be alright" );
  31. } );
  32. // INSTANCING
  33. QUnit.todo( "Instancing", ( assert ) => {
  34. assert.ok( false, "everything's gonna be alright" );
  35. } );
  36. // STATIC STUFF
  37. QUnit.todo( "DefaultUp", ( assert ) => {
  38. assert.ok( false, "everything's gonna be alright" );
  39. } );
  40. QUnit.todo( "DefaultMatrixAutoUpdate", ( assert ) => {
  41. assert.ok( false, "everything's gonna be alright" );
  42. } );
  43. // PUBLIC STUFF
  44. QUnit.todo( "isObject3D", ( assert ) => {
  45. assert.ok( false, "everything's gonna be alright" );
  46. } );
  47. QUnit.todo( "onBeforeRender", ( assert ) => {
  48. assert.ok( false, "everything's gonna be alright" );
  49. } );
  50. QUnit.todo( "onAfterRender", ( assert ) => {
  51. assert.ok( false, "everything's gonna be alright" );
  52. } );
  53. QUnit.test( "applyMatrix4", ( assert ) => {
  54. var a = new Object3D();
  55. var m = new Matrix4();
  56. var expectedPos = new Vector3( x, y, z );
  57. var expectedQuat = new Quaternion( 0.5 * Math.sqrt( 2 ), 0, 0, 0.5 * Math.sqrt( 2 ) );
  58. m.makeRotationX( Math.PI / 2 );
  59. m.setPosition( new Vector3( x, y, z ) );
  60. a.applyMatrix4( m );
  61. assert.deepEqual( a.position, expectedPos, "Position has the expected values" );
  62. assert.ok(
  63. Math.abs( a.quaternion.x - expectedQuat.x ) <= eps &&
  64. Math.abs( a.quaternion.y - expectedQuat.y ) <= eps &&
  65. Math.abs( a.quaternion.z - expectedQuat.z ) <= eps,
  66. "Quaternion has the expected values"
  67. );
  68. } );
  69. QUnit.test( "applyQuaternion", ( assert ) => {
  70. var a = new Object3D();
  71. var sqrt = 0.5 * Math.sqrt( 2 );
  72. var quat = new Quaternion( 0, sqrt, 0, sqrt );
  73. var expected = new Quaternion( sqrt / 2, sqrt / 2, 0, 0 );
  74. a.quaternion.set( 0.25, 0.25, 0.25, 0.25 );
  75. a.applyQuaternion( quat );
  76. assert.ok(
  77. Math.abs( a.quaternion.x - expected.x ) <= eps &&
  78. Math.abs( a.quaternion.y - expected.y ) <= eps &&
  79. Math.abs( a.quaternion.z - expected.z ) <= eps,
  80. "Quaternion has the expected values"
  81. );
  82. } );
  83. QUnit.test( "setRotationFromAxisAngle", ( assert ) => {
  84. var a = new Object3D();
  85. var axis = new Vector3( 0, 1, 0 );
  86. var angle = Math.PI;
  87. var expected = new Euler( - Math.PI, 0, - Math.PI );
  88. var euler = new Euler();
  89. a.setRotationFromAxisAngle( axis, angle );
  90. euler.setFromQuaternion( a.getWorldQuaternion( new Quaternion() ) );
  91. assert.ok( eulerEquals( euler, expected ), "Correct values after rotation" );
  92. axis.set( 1, 0, 0 );
  93. var angle = 0;
  94. expected.set( 0, 0, 0 );
  95. a.setRotationFromAxisAngle( axis, angle );
  96. euler.setFromQuaternion( a.getWorldQuaternion( new Quaternion() ) );
  97. assert.ok( eulerEquals( euler, expected ), "Correct values after zeroing" );
  98. } );
  99. QUnit.test( "setRotationFromEuler", ( assert ) => {
  100. var a = new Object3D();
  101. var rotation = new Euler( ( 45 / RadToDeg ), 0, Math.PI );
  102. var expected = rotation.clone(); // bit obvious
  103. var euler = new Euler();
  104. a.setRotationFromEuler( rotation );
  105. euler.setFromQuaternion( a.getWorldQuaternion( new Quaternion() ) );
  106. assert.ok( eulerEquals( euler, expected ), "Correct values after rotation" );
  107. } );
  108. QUnit.test( "setRotationFromMatrix", ( assert ) => {
  109. var a = new Object3D();
  110. var m = new Matrix4();
  111. var eye = new Vector3( 0, 0, 0 );
  112. var target = new Vector3( 0, 1, - 1 );
  113. var up = new Vector3( 0, 1, 0 );
  114. var euler = new Euler();
  115. m.lookAt( eye, target, up );
  116. a.setRotationFromMatrix( m );
  117. euler.setFromQuaternion( a.getWorldQuaternion( new Quaternion() ) );
  118. assert.numEqual( euler.x * RadToDeg, 45, "Correct rotation angle" );
  119. } );
  120. QUnit.test( "setRotationFromQuaternion", ( assert ) => {
  121. var a = new Object3D();
  122. var rotation = new Quaternion().setFromEuler( new Euler( Math.PI, 0, - Math.PI ) );
  123. var euler = new Euler();
  124. a.setRotationFromQuaternion( rotation );
  125. euler.setFromQuaternion( a.getWorldQuaternion( new Quaternion() ) );
  126. assert.ok( eulerEquals( euler, new Euler( Math.PI, 0, - Math.PI ) ), "Correct values after rotation" );
  127. } );
  128. QUnit.todo( "rotateOnAxis", ( assert ) => {
  129. assert.ok( false, "everything's gonna be alright" );
  130. } );
  131. QUnit.todo( "rotateOnWorldAxis", ( assert ) => {
  132. assert.ok( false, "everything's gonna be alright" );
  133. } );
  134. QUnit.test( "rotateX", ( assert ) => {
  135. var obj = new Object3D();
  136. var angleInRad = 1.562;
  137. obj.rotateX( angleInRad );
  138. assert.numEqual( obj.rotation.x, angleInRad, "x is equal" );
  139. } );
  140. QUnit.test( "rotateY", ( assert ) => {
  141. var obj = new Object3D();
  142. var angleInRad = - 0.346;
  143. obj.rotateY( angleInRad );
  144. assert.numEqual( obj.rotation.y, angleInRad, "y is equal" );
  145. } );
  146. QUnit.test( "rotateZ", ( assert ) => {
  147. var obj = new Object3D();
  148. var angleInRad = 1;
  149. obj.rotateZ( angleInRad );
  150. assert.numEqual( obj.rotation.z, angleInRad, "z is equal" );
  151. } );
  152. QUnit.test( "translateOnAxis", ( assert ) => {
  153. var obj = new Object3D();
  154. obj.translateOnAxis( new Vector3( 1, 0, 0 ), 1 );
  155. obj.translateOnAxis( new Vector3( 0, 1, 0 ), 1.23 );
  156. obj.translateOnAxis( new Vector3( 0, 0, 1 ), - 4.56 );
  157. assert.propEqual( obj.position, {
  158. x: 1,
  159. y: 1.23,
  160. z: - 4.56
  161. } );
  162. } );
  163. QUnit.test( "translateX", ( assert ) => {
  164. var obj = new Object3D();
  165. obj.translateX( 1.234 );
  166. assert.numEqual( obj.position.x, 1.234, "x is equal" );
  167. } );
  168. QUnit.test( "translateY", ( assert ) => {
  169. var obj = new Object3D();
  170. obj.translateY( 1.234 );
  171. assert.numEqual( obj.position.y, 1.234, "y is equal" );
  172. } );
  173. QUnit.test( "translateZ", ( assert ) => {
  174. var obj = new Object3D();
  175. obj.translateZ( 1.234 );
  176. assert.numEqual( obj.position.z, 1.234, "z is equal" );
  177. } );
  178. QUnit.test( "localToWorld", ( assert ) => {
  179. const v = new Vector3();
  180. const expectedPosition = new Vector3( 5, - 1, - 4 );
  181. const parent = new Object3D();
  182. const child = new Object3D();
  183. parent.position.set( 1, 0, 0 );
  184. parent.rotation.set( 0, Math.PI / 2, 0 );
  185. parent.scale.set( 2, 1, 1 );
  186. child.position.set( 0, 1, 0 );
  187. child.rotation.set( Math.PI / 2, 0, 0 );
  188. child.scale.set( 1, 2, 1 );
  189. parent.add( child );
  190. parent.updateMatrixWorld();
  191. child.localToWorld( v.set( 2, 2, 2 ) );
  192. assert.ok(
  193. Math.abs( v.x - expectedPosition.x ) <= eps &&
  194. Math.abs( v.y - expectedPosition.y ) <= eps &&
  195. Math.abs( v.z - expectedPosition.z ) <= eps,
  196. "local vector is converted to world"
  197. );
  198. } );
  199. QUnit.test( "worldToLocal", ( assert ) => {
  200. const v = new Vector3();
  201. const expectedPosition = new Vector3( - 1, 0.5, - 1 );
  202. const parent = new Object3D();
  203. const child = new Object3D();
  204. parent.position.set( 1, 0, 0 );
  205. parent.rotation.set( 0, Math.PI / 2, 0 );
  206. parent.scale.set( 2, 1, 1 );
  207. child.position.set( 0, 1, 0 );
  208. child.rotation.set( Math.PI / 2, 0, 0 );
  209. child.scale.set( 1, 2, 1 );
  210. parent.add( child );
  211. parent.updateMatrixWorld();
  212. child.worldToLocal( v.set( 2, 2, 2 ) );
  213. assert.ok(
  214. Math.abs( v.x - expectedPosition.x ) <= eps &&
  215. Math.abs( v.y - expectedPosition.y ) <= eps &&
  216. Math.abs( v.z - expectedPosition.z ) <= eps,
  217. "world vector is converted to local"
  218. );
  219. } );
  220. QUnit.test( "lookAt", ( assert ) => {
  221. var obj = new Object3D();
  222. obj.lookAt( new Vector3( 0, - 1, 1 ) );
  223. assert.numEqual( obj.rotation.x * RadToDeg, 45, "x is equal" );
  224. } );
  225. QUnit.test( "add/remove/clear", ( assert ) => {
  226. var a = new Object3D();
  227. var child1 = new Object3D();
  228. var child2 = new Object3D();
  229. assert.strictEqual( a.children.length, 0, "Starts with no children" );
  230. a.add( child1 );
  231. assert.strictEqual( a.children.length, 1, "The first child was added" );
  232. assert.strictEqual( a.children[ 0 ], child1, "It's the right one" );
  233. a.add( child2 );
  234. assert.strictEqual( a.children.length, 2, "The second child was added" );
  235. assert.strictEqual( a.children[ 1 ], child2, "It's the right one" );
  236. assert.strictEqual( a.children[ 0 ], child1, "The first one is still there" );
  237. a.remove( child1 );
  238. assert.strictEqual( a.children.length, 1, "The first child was removed" );
  239. assert.strictEqual( a.children[ 0 ], child2, "The second one is still there" );
  240. a.add( child1 );
  241. a.remove( child1, child2 );
  242. assert.strictEqual( a.children.length, 0, "Both children were removed at once" );
  243. child1.add( child2 );
  244. assert.strictEqual( child1.children.length, 1, "The second child was added to the first one" );
  245. a.add( child2 );
  246. assert.strictEqual( a.children.length, 1, "The second one was added to the parent (no remove)" );
  247. assert.strictEqual( a.children[ 0 ], child2, "The second one is now the parent's child again" );
  248. assert.strictEqual( child1.children.length, 0, "The first one no longer has any children" );
  249. a.add( child1 );
  250. assert.strictEqual( a.children.length, 2, "The first child was added to the parent" );
  251. a.clear();
  252. assert.strictEqual( a.children.length, 0, "All childrens were removed" );
  253. assert.strictEqual( child1.parent, null, "First child has no parent" );
  254. assert.strictEqual( child2.parent, null, "Second child has no parent" );
  255. } );
  256. QUnit.test( "getObjectById/getObjectByName/getObjectByProperty", ( assert ) => {
  257. var parent = new Object3D();
  258. var childName = new Object3D();
  259. var childId = new Object3D(); // id = parent.id + 2
  260. var childNothing = new Object3D();
  261. parent.prop = true;
  262. childName.name = "foo";
  263. parent.add( childName, childId, childNothing );
  264. assert.strictEqual( parent.getObjectByProperty( 'prop', true ), parent, "Get parent by its own property" );
  265. assert.strictEqual( parent.getObjectByName( "foo" ), childName, "Get child by name" );
  266. assert.strictEqual( parent.getObjectById( parent.id + 2 ), childId, "Get child by Id" );
  267. assert.strictEqual(
  268. parent.getObjectByProperty( 'no-property', 'no-value' ), undefined,
  269. "Unknown property results in undefined"
  270. );
  271. } );
  272. QUnit.test( "getWorldPosition", ( assert ) => {
  273. var a = new Object3D();
  274. var b = new Object3D();
  275. var expectedSingle = new Vector3( x, y, z );
  276. var expectedParent = new Vector3( x, y, 0 );
  277. var expectedChild = new Vector3( x, y, 7 + ( z - z ) );
  278. var position = new Vector3();
  279. a.translateX( x );
  280. a.translateY( y );
  281. a.translateZ( z );
  282. assert.deepEqual( a.getWorldPosition( position ), expectedSingle, "WorldPosition as expected for single object" );
  283. // translate child and then parent
  284. b.translateZ( 7 );
  285. a.add( b );
  286. a.translateZ( - z );
  287. assert.deepEqual( a.getWorldPosition( position ), expectedParent, "WorldPosition as expected for parent" );
  288. assert.deepEqual( b.getWorldPosition( position ), expectedChild, "WorldPosition as expected for child" );
  289. } );
  290. QUnit.todo( "getWorldQuaternion", ( assert ) => {
  291. assert.ok( false, "everything's gonna be alright" );
  292. } );
  293. QUnit.test( "getWorldScale", ( assert ) => {
  294. var a = new Object3D();
  295. var m = new Matrix4().makeScale( x, y, z );
  296. var expected = new Vector3( x, y, z );
  297. a.applyMatrix4( m );
  298. assert.deepEqual( a.getWorldScale( new Vector3() ), expected, "WorldScale as expected" );
  299. } );
  300. QUnit.test( "getWorldDirection", ( assert ) => {
  301. var a = new Object3D();
  302. var expected = new Vector3( 0, - 0.5 * Math.sqrt( 2 ), 0.5 * Math.sqrt( 2 ) );
  303. var direction = new Vector3();
  304. a.lookAt( new Vector3( 0, - 1, 1 ) );
  305. a.getWorldDirection( direction );
  306. assert.ok(
  307. Math.abs( direction.x - expected.x ) <= eps &&
  308. Math.abs( direction.y - expected.y ) <= eps &&
  309. Math.abs( direction.z - expected.z ) <= eps,
  310. "Direction has the expected values"
  311. );
  312. } );
  313. QUnit.test( "localTransformVariableInstantiation", ( assert ) => {
  314. var a = new Object3D();
  315. var b = new Object3D();
  316. var c = new Object3D();
  317. var d = new Object3D();
  318. a.getWorldDirection( new Vector3() );
  319. a.lookAt( new Vector3( 0, - 1, 1 ) );
  320. assert.ok( true, "Calling lookAt after getWorldDirection does not create errors" );
  321. b.getWorldPosition( new Vector3() );
  322. b.lookAt( new Vector3( 0, - 1, 1 ) );
  323. assert.ok( true, "Calling lookAt after getWorldPosition does not create errors" );
  324. c.getWorldQuaternion( new Quaternion() );
  325. c.lookAt( new Vector3( 0, - 1, 1 ) );
  326. assert.ok( true, "Calling lookAt after getWorldQuaternion does not create errors" );
  327. d.getWorldScale( new Vector3() );
  328. d.lookAt( new Vector3( 0, - 1, 1 ) );
  329. assert.ok( true, "Calling lookAt after getWorldScale does not create errors" );
  330. } );
  331. QUnit.todo( "raycast", ( assert ) => {
  332. assert.ok( false, "everything's gonna be alright" );
  333. } );
  334. QUnit.test( "traverse/traverseVisible/traverseAncestors", ( assert ) => {
  335. var a = new Object3D();
  336. var b = new Object3D();
  337. var c = new Object3D();
  338. var d = new Object3D();
  339. var names = [];
  340. var expectedNormal = [ "parent", "child", "childchild 1", "childchild 2" ];
  341. var expectedVisible = [ "parent", "child", "childchild 2" ];
  342. var expectedAncestors = [ "child", "parent" ];
  343. a.name = "parent";
  344. b.name = "child";
  345. c.name = "childchild 1";
  346. c.visible = false;
  347. d.name = "childchild 2";
  348. b.add( c );
  349. b.add( d );
  350. a.add( b );
  351. a.traverse( function ( obj ) {
  352. names.push( obj.name );
  353. } );
  354. assert.deepEqual( names, expectedNormal, "Traversed objects in expected order" );
  355. var names = [];
  356. a.traverseVisible( function ( obj ) {
  357. names.push( obj.name );
  358. } );
  359. assert.deepEqual( names, expectedVisible, "Traversed visible objects in expected order" );
  360. var names = [];
  361. c.traverseAncestors( function ( obj ) {
  362. names.push( obj.name );
  363. } );
  364. assert.deepEqual( names, expectedAncestors, "Traversed ancestors in expected order" );
  365. } );
  366. QUnit.test( "updateMatrix", ( assert ) => {
  367. const a = new Object3D();
  368. a.position.set( 2, 3, 4 );
  369. a.quaternion.set( 5, 6, 7, 8 );
  370. a.scale.set( 9, 10, 11 );
  371. assert.deepEqual( a.matrix.elements, [
  372. 1, 0, 0, 0,
  373. 0, 1, 0, 0,
  374. 0, 0, 1, 0,
  375. 0, 0, 0, 1
  376. ], "Updating position, quaternion, or scale has no effect to matrix until calling updateMatrix()" );
  377. a.updateMatrix();
  378. assert.deepEqual( a.matrix.elements, [
  379. -1521, 1548, -234, 0,
  380. -520, -1470, 1640, 0,
  381. 1826, 44, -1331, 0,
  382. 2, 3, 4, 1
  383. ], "matrix is calculated from position, quaternion, and scale" );
  384. assert.equal( a.matrixWorldNeedsUpdate, true, "The flag indicating world matrix needs to be updated should be true" );
  385. } );
  386. QUnit.test( "updateMatrixWorld", ( assert ) => {
  387. const parent = new Object3D();
  388. const child = new Object3D();
  389. // -- Standard usage test
  390. parent.position.set( 1, 2, 3 );
  391. child.position.set( 4, 5, 6 );
  392. parent.add( child );
  393. parent.updateMatrixWorld();
  394. assert.deepEqual( parent.matrix.elements, [
  395. 1, 0, 0, 0,
  396. 0, 1, 0, 0,
  397. 0, 0, 1, 0,
  398. 1, 2, 3, 1
  399. ], "updateMatrixWorld() updates local matrix" );
  400. assert.deepEqual( parent.matrixWorld.elements, [
  401. 1, 0, 0, 0,
  402. 0, 1, 0, 0,
  403. 0, 0, 1, 0,
  404. 1, 2, 3, 1
  405. ], "updateMatrixWorld() updates world matrix" );
  406. assert.deepEqual( child.matrix.elements, [
  407. 1, 0, 0, 0,
  408. 0, 1, 0, 0,
  409. 0, 0, 1, 0,
  410. 4, 5, 6, 1
  411. ], "updateMatrixWorld() updates children's local matrix" );
  412. assert.deepEqual( child.matrixWorld.elements, [
  413. 1, 0, 0, 0,
  414. 0, 1, 0, 0,
  415. 0, 0, 1, 0,
  416. 5, 7, 9, 1
  417. ], "updateMatrixWorld() updates children's world matrices from their parent world matrix and their local matrices" );
  418. assert.equal( parent.matrixWorldNeedsUpdate || child.matrixWorldNeedsUpdate, false, "The flag indicating world matrix needs to be updated should be false after updating world matrix" );
  419. // -- No sync between local position/quaternion/scale/matrix and world matrix test
  420. parent.position.set( 0, 0, 0 );
  421. parent.updateMatrix();
  422. assert.deepEqual( parent.matrixWorld.elements, [
  423. 1, 0, 0, 0,
  424. 0, 1, 0, 0,
  425. 0, 0, 1, 0,
  426. 1, 2, 3, 1
  427. ], "Updating position, quaternion, scale, or local matrix has no effect to world matrix until calling updateWorldMatrix()" );
  428. // -- matrixAutoUpdate = false test
  429. // Resetting local and world matrices to the origin
  430. child.position.set( 0, 0, 0 );
  431. parent.updateMatrixWorld();
  432. parent.position.set( 1, 2, 3 );
  433. parent.matrixAutoUpdate = false;
  434. child.matrixAutoUpdate = false;
  435. parent.updateMatrixWorld();
  436. assert.deepEqual( parent.matrix.elements, [
  437. 1, 0, 0, 0,
  438. 0, 1, 0, 0,
  439. 0, 0, 1, 0,
  440. 0, 0, 0, 1
  441. ], "updateMatrixWorld() doesn't update local matrix if matrixAutoUpdate is false" );
  442. assert.deepEqual( parent.matrixWorld.elements, [
  443. 1, 0, 0, 0,
  444. 0, 1, 0, 0,
  445. 0, 0, 1, 0,
  446. 0, 0, 0, 1
  447. ], "World matrix isn't updated because local matrix isn't updated and the flag indicating world matrix needs to be updated didn't rise" );
  448. assert.deepEqual( child.matrixWorld.elements, [
  449. 1, 0, 0, 0,
  450. 0, 1, 0, 0,
  451. 0, 0, 1, 0,
  452. 0, 0, 0, 1
  453. ], "No effect to child world matrix if parent local and world matrices and child local matrix are not updated" );
  454. // -- Propagation to children world matrices test
  455. parent.matrixAutoUpdate = true;
  456. parent.updateMatrixWorld();
  457. assert.deepEqual( child.matrixWorld.elements, [
  458. 1, 0, 0, 0,
  459. 0, 1, 0, 0,
  460. 0, 0, 1, 0,
  461. 1, 2, 3, 1
  462. ], "Updating parent world matrix has effect to children world matrices even if children local matrices aren't changed" );
  463. // -- force argument test
  464. // Resetting the local and world matrices to the origin
  465. child.position.set( 0, 0, 0 );
  466. child.matrixAutoUpdate = true;
  467. parent.updateMatrixWorld();
  468. parent.position.set( 1, 2, 3 );
  469. parent.updateMatrix();
  470. parent.matrixAutoUpdate = false;
  471. parent.matrixWorldNeedsUpdate = false;
  472. parent.updateMatrixWorld( true );
  473. assert.deepEqual( parent.matrixWorld.elements, [
  474. 1, 0, 0, 0,
  475. 0, 1, 0, 0,
  476. 0, 0, 1, 0,
  477. 1, 2, 3, 1
  478. ], "force = true forces to update world matrix even if local matrix is not changed" );
  479. // -- Restriction test: No effect to parent matrices
  480. // Resetting the local and world matrices to the origin
  481. parent.position.set( 0, 0, 0 );
  482. child.position.set( 0, 0, 0 );
  483. parent.matrixAutoUpdate = true;
  484. child.matrixAutoUpdate = true;
  485. parent.updateMatrixWorld();
  486. parent.position.set( 1, 2, 3 );
  487. child.position.set( 4, 5, 6 );
  488. child.updateMatrixWorld();
  489. assert.deepEqual( parent.matrix.elements, [
  490. 1, 0, 0, 0,
  491. 0, 1, 0, 0,
  492. 0, 0, 1, 0,
  493. 0, 0, 0, 1
  494. ], "updateMatrixWorld() doesn't update parent local matrix" );
  495. assert.deepEqual( parent.matrixWorld.elements, [
  496. 1, 0, 0, 0,
  497. 0, 1, 0, 0,
  498. 0, 0, 1, 0,
  499. 0, 0, 0, 1
  500. ], "updateMatrixWorld() doesn't update parent world matrix" );
  501. assert.deepEqual( child.matrixWorld.elements, [
  502. 1, 0, 0, 0,
  503. 0, 1, 0, 0,
  504. 0, 0, 1, 0,
  505. 4, 5, 6, 1
  506. ], "updateMatrixWorld() calculates world matrix from the current parent world matrix" );
  507. } );
  508. QUnit.test( "toJSON", ( assert ) => {
  509. var a = new Object3D();
  510. var child = new Object3D();
  511. var childChild = new Object3D();
  512. a.name = "a's name";
  513. a.matrix.set( 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 );
  514. a.visible = false;
  515. a.castShadow = true;
  516. a.receiveShadow = true;
  517. a.userData[ "foo" ] = "bar";
  518. child.uuid = "5D4E9AE8-DA61-4912-A575-71A5BE3D72CD";
  519. childChild.uuid = "B43854B3-E970-4E85-BD41-AAF8D7BFA189";
  520. child.add( childChild );
  521. a.add( child );
  522. var gold = {
  523. "metadata": {
  524. "version": 4.5,
  525. "type": "Object",
  526. "generator": "Object3D.toJSON"
  527. },
  528. "object": {
  529. "uuid": "0A1E4F43-CB5B-4097-8F82-DC2969C0B8C2",
  530. "type": "Object3D",
  531. "name": "a's name",
  532. "castShadow": true,
  533. "receiveShadow": true,
  534. "visible": false,
  535. "userData": { "foo": "bar" },
  536. "layers": 1,
  537. "matrix": [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ],
  538. "children": [
  539. {
  540. "uuid": "5D4E9AE8-DA61-4912-A575-71A5BE3D72CD",
  541. "type": "Object3D",
  542. "layers": 1,
  543. "matrix": [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ],
  544. "children": [
  545. {
  546. "uuid": "B43854B3-E970-4E85-BD41-AAF8D7BFA189",
  547. "type": "Object3D",
  548. "layers": 1,
  549. "matrix": [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ]
  550. }
  551. ]
  552. }
  553. ]
  554. }
  555. };
  556. // hacks
  557. var out = a.toJSON();
  558. out.object.uuid = "0A1E4F43-CB5B-4097-8F82-DC2969C0B8C2";
  559. assert.deepEqual( out, gold, "JSON is as expected" );
  560. } );
  561. QUnit.test( "clone", ( assert ) => {
  562. var a;
  563. var b = new Object3D();
  564. assert.strictEqual( a, undefined, "Undefined pre-clone()" );
  565. a = b.clone();
  566. assert.notStrictEqual( a, b, "Defined but seperate instances post-clone()" );
  567. a.uuid = b.uuid;
  568. assert.deepEqual( a, b, "But identical properties" );
  569. } );
  570. QUnit.test( "copy", ( assert ) => {
  571. var a = new Object3D();
  572. var b = new Object3D();
  573. var child = new Object3D();
  574. var childChild = new Object3D();
  575. a.name = "original";
  576. b.name = "to-be-copied";
  577. b.position.set( x, y, z );
  578. b.quaternion.set( x, y, z, w );
  579. b.scale.set( 2, 3, 4 );
  580. // bogus QUnit.test values
  581. b.matrix.set( 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 );
  582. b.matrixWorld.set( 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 );
  583. b.matrixAutoUpdate = false;
  584. b.matrixWorldNeedsUpdate = true;
  585. b.layers.mask = 2;
  586. b.visible = false;
  587. b.castShadow = true;
  588. b.receiveShadow = true;
  589. b.frustumCulled = false;
  590. b.renderOrder = 1;
  591. b.userData[ "foo" ] = "bar";
  592. child.add( childChild );
  593. b.add( child );
  594. assert.notDeepEqual( a, b, "Objects are not equal pre-copy()" );
  595. a.copy( b, true );
  596. // check they're all unique instances
  597. assert.ok(
  598. a.uuid !== b.uuid &&
  599. a.children[ 0 ].uuid !== b.children[ 0 ].uuid &&
  600. a.children[ 0 ].children[ 0 ].uuid !== b.children[ 0 ].children[ 0 ].uuid,
  601. "UUIDs are all different"
  602. );
  603. // and now fix that
  604. a.uuid = b.uuid;
  605. a.children[ 0 ].uuid = b.children[ 0 ].uuid;
  606. a.children[ 0 ].children[ 0 ].uuid = b.children[ 0 ].children[ 0 ].uuid;
  607. assert.deepEqual( a, b, "Objects are equal post-copy()" );
  608. } );
  609. } );
  610. } );