Object3D.tests.js 25 KB

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