Object3D.tests.js 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389
  1. /* global QUnit */
  2. import { Object3D } from '../../../../src/core/Object3D.js';
  3. import { Vector3 } from '../../../../src/math/Vector3.js';
  4. import { Euler } from '../../../../src/math/Euler.js';
  5. import { Quaternion } from '../../../../src/math/Quaternion.js';
  6. import { Matrix4 } from '../../../../src/math/Matrix4.js';
  7. import {
  8. x,
  9. y,
  10. z,
  11. w,
  12. eps
  13. } from '../../utils/math-constants.js';
  14. import { EventDispatcher } from '../../../../src/core/EventDispatcher.js';
  15. const matrixEquals4 = ( a, b ) => {
  16. for ( let i = 0; i < 16; i ++ ) {
  17. if ( Math.abs( a.elements[ i ] - b.elements[ i ] ) >= eps ) {
  18. return false;
  19. }
  20. }
  21. return true;
  22. };
  23. export default QUnit.module( 'Core', () => {
  24. QUnit.module( 'Object3D', () => {
  25. const RadToDeg = 180 / Math.PI;
  26. const eulerEquals = function ( a, b, tolerance ) {
  27. tolerance = tolerance || 0.0001;
  28. if ( a.order != b.order ) {
  29. return false;
  30. }
  31. return (
  32. Math.abs( a.x - b.x ) <= tolerance &&
  33. Math.abs( a.y - b.y ) <= tolerance &&
  34. Math.abs( a.z - b.z ) <= tolerance
  35. );
  36. };
  37. // INHERITANCE
  38. QUnit.test( 'Extending', ( assert ) => {
  39. const object = new Object3D();
  40. assert.strictEqual(
  41. object instanceof EventDispatcher, true,
  42. 'Object3D extends from EventDispatcher'
  43. );
  44. } );
  45. // INSTANCING
  46. QUnit.test( 'Instancing', ( assert ) => {
  47. const object = new Object3D();
  48. assert.ok( object, 'Can instantiate an Object3D.' );
  49. } );
  50. // PROPERTIES
  51. QUnit.todo( 'id', ( assert ) => {
  52. assert.ok( false, 'everything\'s gonna be alright' );
  53. } );
  54. QUnit.todo( 'uuid', ( assert ) => {
  55. assert.ok( false, 'everything\'s gonna be alright' );
  56. } );
  57. QUnit.todo( 'name', ( assert ) => {
  58. assert.ok( false, 'everything\'s gonna be alright' );
  59. } );
  60. QUnit.test( 'type', ( assert ) => {
  61. const object = new Object3D();
  62. assert.ok(
  63. object.type === 'Object3D',
  64. 'Object3D.type should be Object3D'
  65. );
  66. } );
  67. QUnit.todo( 'parent', ( assert ) => {
  68. assert.ok( false, 'everything\'s gonna be alright' );
  69. } );
  70. QUnit.todo( 'children', ( assert ) => {
  71. assert.ok( false, 'everything\'s gonna be alright' );
  72. } );
  73. QUnit.todo( 'up', ( assert ) => {
  74. assert.ok( false, 'everything\'s gonna be alright' );
  75. } );
  76. QUnit.todo( 'position', ( assert ) => {
  77. assert.ok( false, 'everything\'s gonna be alright' );
  78. } );
  79. QUnit.todo( 'rotation', ( assert ) => {
  80. assert.ok( false, 'everything\'s gonna be alright' );
  81. } );
  82. QUnit.todo( 'quaternion', ( assert ) => {
  83. assert.ok( false, 'everything\'s gonna be alright' );
  84. } );
  85. QUnit.todo( 'scale', ( assert ) => {
  86. assert.ok( false, 'everything\'s gonna be alright' );
  87. } );
  88. QUnit.todo( 'modelViewMatrix', ( assert ) => {
  89. assert.ok( false, 'everything\'s gonna be alright' );
  90. } );
  91. QUnit.todo( 'normalMatrix', ( assert ) => {
  92. assert.ok( false, 'everything\'s gonna be alright' );
  93. } );
  94. QUnit.todo( 'matrix', ( assert ) => {
  95. assert.ok( false, 'everything\'s gonna be alright' );
  96. } );
  97. QUnit.todo( 'matrixWorld', ( assert ) => {
  98. assert.ok( false, 'everything\'s gonna be alright' );
  99. } );
  100. QUnit.todo( 'matrixAutoUpdate', ( assert ) => {
  101. assert.ok( false, 'everything\'s gonna be alright' );
  102. } );
  103. QUnit.todo( 'matrixWorldNeedsUpdate', ( assert ) => {
  104. assert.ok( false, 'everything\'s gonna be alright' );
  105. } );
  106. QUnit.todo( 'matrixWorldAutoUpdate', ( assert ) => {
  107. assert.ok( false, 'everything\'s gonna be alright' );
  108. } );
  109. QUnit.todo( 'layers', ( assert ) => {
  110. assert.ok( false, 'everything\'s gonna be alright' );
  111. } );
  112. QUnit.todo( 'visible', ( assert ) => {
  113. assert.ok( false, 'everything\'s gonna be alright' );
  114. } );
  115. QUnit.todo( 'castShadow', ( assert ) => {
  116. assert.ok( false, 'everything\'s gonna be alright' );
  117. } );
  118. QUnit.todo( 'receiveShadow', ( assert ) => {
  119. assert.ok( false, 'everything\'s gonna be alright' );
  120. } );
  121. QUnit.todo( 'frustumCulled', ( assert ) => {
  122. assert.ok( false, 'everything\'s gonna be alright' );
  123. } );
  124. QUnit.todo( 'renderOrder', ( assert ) => {
  125. assert.ok( false, 'everything\'s gonna be alright' );
  126. } );
  127. QUnit.todo( 'animations', ( assert ) => {
  128. assert.ok( false, 'everything\'s gonna be alright' );
  129. } );
  130. QUnit.todo( 'userData', ( assert ) => {
  131. assert.ok( false, 'everything\'s gonna be alright' );
  132. } );
  133. // STATIC
  134. QUnit.test( 'DEFAULT_UP', ( assert ) => {
  135. const currentDefaultUp = new Vector3().copy( Object3D.DEFAULT_UP );
  136. const v = new Vector3();
  137. try {
  138. assert.deepEqual( Object3D.DEFAULT_UP, v.set( 0, 1, 0 ), 'default DEFAULT_UP is Y-up' );
  139. const object = new Object3D();
  140. assert.deepEqual( object.up, v.set( 0, 1, 0 ), '.up of a new object inherits Object3D.DEFAULT_UP = Y-up' );
  141. Object3D.DEFAULT_UP.set( 0, 0, 1 );
  142. const object2 = new Object3D();
  143. assert.deepEqual( object2.up, v.set( 0, 0, 1 ), '.up of a new object inherits Object3D.DEFAULT_UP = Z-up' );
  144. } finally {
  145. Object3D.DEFAULT_UP.copy( currentDefaultUp );
  146. }
  147. } );
  148. QUnit.test( 'DEFAULT_MATRIX_AUTO_UPDATE', ( assert ) => {
  149. const currentDefaultMatrixAutoUpdate = Object3D.DEFAULT_MATRIX_AUTO_UPDATE;
  150. try {
  151. assert.equal( currentDefaultMatrixAutoUpdate, true, 'default DEFAULT_MATRIX_AUTO_UPDATE is true' );
  152. const object = new Object3D();
  153. assert.equal(
  154. object.matrixAutoUpdate, true,
  155. '.matrixAutoUpdate of a new object inherits Object3D.DEFAULT_MATRIX_AUTO_UPDATE = true'
  156. );
  157. Object3D.DEFAULT_MATRIX_AUTO_UPDATE = false;
  158. const object2 = new Object3D();
  159. assert.equal(
  160. object2.matrixAutoUpdate, false,
  161. '.matrixAutoUpdate of a new object inherits Object3D.DEFAULT_MATRIX_AUTO_UPDATE = false'
  162. );
  163. } finally {
  164. Object3D.DEFAULT_MATRIX_AUTO_UPDATE = currentDefaultMatrixAutoUpdate;
  165. }
  166. } );
  167. // PUBLIC
  168. QUnit.test( 'isObject3D', ( assert ) => {
  169. const object = new Object3D();
  170. assert.ok(
  171. object.isObject3D,
  172. 'Object3D.isObject3D should be true'
  173. );
  174. const object2 = {};
  175. assert.ok(
  176. object2.isObject3D === undefined,
  177. 'other object isObject3D should be undefined'
  178. );
  179. } );
  180. QUnit.todo( 'onBeforeRender', ( assert ) => {
  181. assert.ok( false, 'everything\'s gonna be alright' );
  182. } );
  183. QUnit.todo( 'onAfterRender', ( assert ) => {
  184. assert.ok( false, 'everything\'s gonna be alright' );
  185. } );
  186. QUnit.test( 'applyMatrix4', ( assert ) => {
  187. const a = new Object3D();
  188. const m = new Matrix4();
  189. const expectedPos = new Vector3( x, y, z );
  190. const expectedQuat = new Quaternion( 0.5 * Math.sqrt( 2 ), 0, 0, 0.5 * Math.sqrt( 2 ) );
  191. m.makeRotationX( Math.PI / 2 );
  192. m.setPosition( new Vector3( x, y, z ) );
  193. a.applyMatrix4( m );
  194. assert.deepEqual( a.position, expectedPos, 'Position has the expected values' );
  195. assert.ok(
  196. Math.abs( a.quaternion.x - expectedQuat.x ) <= eps &&
  197. Math.abs( a.quaternion.y - expectedQuat.y ) <= eps &&
  198. Math.abs( a.quaternion.z - expectedQuat.z ) <= eps,
  199. 'Quaternion has the expected values'
  200. );
  201. } );
  202. QUnit.test( 'applyQuaternion', ( assert ) => {
  203. const a = new Object3D();
  204. const sqrt = 0.5 * Math.sqrt( 2 );
  205. const quat = new Quaternion( 0, sqrt, 0, sqrt );
  206. const expected = new Quaternion( sqrt / 2, sqrt / 2, 0, 0 );
  207. a.quaternion.set( 0.25, 0.25, 0.25, 0.25 );
  208. a.applyQuaternion( quat );
  209. assert.ok(
  210. Math.abs( a.quaternion.x - expected.x ) <= eps &&
  211. Math.abs( a.quaternion.y - expected.y ) <= eps &&
  212. Math.abs( a.quaternion.z - expected.z ) <= eps,
  213. 'Quaternion has the expected values'
  214. );
  215. } );
  216. QUnit.test( 'setRotationFromAxisAngle', ( assert ) => {
  217. const a = new Object3D();
  218. const axis = new Vector3( 0, 1, 0 );
  219. let angle = Math.PI;
  220. const expected = new Euler( - Math.PI, 0, - Math.PI );
  221. const euler = new Euler();
  222. a.setRotationFromAxisAngle( axis, angle );
  223. euler.setFromQuaternion( a.getWorldQuaternion( new Quaternion() ) );
  224. assert.ok( eulerEquals( euler, expected ), 'Correct values after rotation' );
  225. axis.set( 1, 0, 0 );
  226. angle = 0;
  227. expected.set( 0, 0, 0 );
  228. a.setRotationFromAxisAngle( axis, angle );
  229. euler.setFromQuaternion( a.getWorldQuaternion( new Quaternion() ) );
  230. assert.ok( eulerEquals( euler, expected ), 'Correct values after zeroing' );
  231. } );
  232. QUnit.test( 'setRotationFromEuler', ( assert ) => {
  233. const a = new Object3D();
  234. const rotation = new Euler( ( 45 / RadToDeg ), 0, Math.PI );
  235. const expected = rotation.clone(); // bit obvious
  236. const euler = new Euler();
  237. a.setRotationFromEuler( rotation );
  238. euler.setFromQuaternion( a.getWorldQuaternion( new Quaternion() ) );
  239. assert.ok( eulerEquals( euler, expected ), 'Correct values after rotation' );
  240. } );
  241. QUnit.test( 'setRotationFromMatrix', ( assert ) => {
  242. const a = new Object3D();
  243. const m = new Matrix4();
  244. const eye = new Vector3( 0, 0, 0 );
  245. const target = new Vector3( 0, 1, - 1 );
  246. const up = new Vector3( 0, 1, 0 );
  247. const euler = new Euler();
  248. m.lookAt( eye, target, up );
  249. a.setRotationFromMatrix( m );
  250. euler.setFromQuaternion( a.getWorldQuaternion( new Quaternion() ) );
  251. assert.numEqual( euler.x * RadToDeg, 45, 'Correct rotation angle' );
  252. } );
  253. QUnit.test( 'setRotationFromQuaternion', ( assert ) => {
  254. const a = new Object3D();
  255. const rotation = new Quaternion().setFromEuler( new Euler( Math.PI, 0, - Math.PI ) );
  256. const euler = new Euler();
  257. a.setRotationFromQuaternion( rotation );
  258. euler.setFromQuaternion( a.getWorldQuaternion( new Quaternion() ) );
  259. assert.ok( eulerEquals( euler, new Euler( Math.PI, 0, - Math.PI ) ), 'Correct values after rotation' );
  260. } );
  261. QUnit.todo( 'rotateOnAxis', ( assert ) => {
  262. assert.ok( false, 'everything\'s gonna be alright' );
  263. } );
  264. QUnit.todo( 'rotateOnWorldAxis', ( assert ) => {
  265. assert.ok( false, 'everything\'s gonna be alright' );
  266. } );
  267. QUnit.test( 'rotateX', ( assert ) => {
  268. const obj = new Object3D();
  269. const angleInRad = 1.562;
  270. obj.rotateX( angleInRad );
  271. assert.numEqual( obj.rotation.x, angleInRad, 'x is equal' );
  272. } );
  273. QUnit.test( 'rotateY', ( assert ) => {
  274. const obj = new Object3D();
  275. const angleInRad = - 0.346;
  276. obj.rotateY( angleInRad );
  277. assert.numEqual( obj.rotation.y, angleInRad, 'y is equal' );
  278. } );
  279. QUnit.test( 'rotateZ', ( assert ) => {
  280. const obj = new Object3D();
  281. const angleInRad = 1;
  282. obj.rotateZ( angleInRad );
  283. assert.numEqual( obj.rotation.z, angleInRad, 'z is equal' );
  284. } );
  285. QUnit.test( 'translateOnAxis', ( assert ) => {
  286. const obj = new Object3D();
  287. obj.translateOnAxis( new Vector3( 1, 0, 0 ), 1 );
  288. obj.translateOnAxis( new Vector3( 0, 1, 0 ), 1.23 );
  289. obj.translateOnAxis( new Vector3( 0, 0, 1 ), - 4.56 );
  290. assert.propEqual( obj.position, {
  291. x: 1,
  292. y: 1.23,
  293. z: - 4.56,
  294. } );
  295. } );
  296. QUnit.test( 'translateX', ( assert ) => {
  297. const obj = new Object3D();
  298. obj.translateX( 1.234 );
  299. assert.numEqual( obj.position.x, 1.234, 'x is equal' );
  300. } );
  301. QUnit.test( 'translateY', ( assert ) => {
  302. const obj = new Object3D();
  303. obj.translateY( 1.234 );
  304. assert.numEqual( obj.position.y, 1.234, 'y is equal' );
  305. } );
  306. QUnit.test( 'translateZ', ( assert ) => {
  307. const obj = new Object3D();
  308. obj.translateZ( 1.234 );
  309. assert.numEqual( obj.position.z, 1.234, 'z is equal' );
  310. } );
  311. QUnit.test( 'localToWorld', ( assert ) => {
  312. const v = new Vector3();
  313. const expectedPosition = new Vector3( 5, - 1, - 4 );
  314. const parent = new Object3D();
  315. const child = new Object3D();
  316. parent.position.set( 1, 0, 0 );
  317. parent.rotation.set( 0, Math.PI / 2, 0 );
  318. parent.scale.set( 2, 1, 1 );
  319. child.position.set( 0, 1, 0 );
  320. child.rotation.set( Math.PI / 2, 0, 0 );
  321. child.scale.set( 1, 2, 1 );
  322. parent.add( child );
  323. parent.updateMatrixWorld();
  324. child.localToWorld( v.set( 2, 2, 2 ) );
  325. assert.ok(
  326. Math.abs( v.x - expectedPosition.x ) <= eps &&
  327. Math.abs( v.y - expectedPosition.y ) <= eps &&
  328. Math.abs( v.z - expectedPosition.z ) <= eps,
  329. 'local vector is converted to world'
  330. );
  331. } );
  332. QUnit.test( 'worldToLocal', ( assert ) => {
  333. const v = new Vector3();
  334. const expectedPosition = new Vector3( - 1, 0.5, - 1 );
  335. const parent = new Object3D();
  336. const child = new Object3D();
  337. parent.position.set( 1, 0, 0 );
  338. parent.rotation.set( 0, Math.PI / 2, 0 );
  339. parent.scale.set( 2, 1, 1 );
  340. child.position.set( 0, 1, 0 );
  341. child.rotation.set( Math.PI / 2, 0, 0 );
  342. child.scale.set( 1, 2, 1 );
  343. parent.add( child );
  344. parent.updateMatrixWorld();
  345. child.worldToLocal( v.set( 2, 2, 2 ) );
  346. assert.ok(
  347. Math.abs( v.x - expectedPosition.x ) <= eps &&
  348. Math.abs( v.y - expectedPosition.y ) <= eps &&
  349. Math.abs( v.z - expectedPosition.z ) <= eps,
  350. 'world vector is converted to local'
  351. );
  352. } );
  353. QUnit.test( 'lookAt', ( assert ) => {
  354. const obj = new Object3D();
  355. obj.lookAt( new Vector3( 0, - 1, 1 ) );
  356. assert.numEqual( obj.rotation.x * RadToDeg, 45, 'x is equal' );
  357. } );
  358. QUnit.test( 'add/remove/removeFromParent/clear', ( assert ) => {
  359. const a = new Object3D();
  360. const child1 = new Object3D();
  361. const child2 = new Object3D();
  362. assert.strictEqual( a.children.length, 0, 'Starts with no children' );
  363. a.add( child1 );
  364. assert.strictEqual( a.children.length, 1, 'The first child was added' );
  365. assert.strictEqual( a.children[ 0 ], child1, 'It\'s the right one' );
  366. a.add( child2 );
  367. assert.strictEqual( a.children.length, 2, 'The second child was added' );
  368. assert.strictEqual( a.children[ 1 ], child2, 'It\'s the right one' );
  369. assert.strictEqual( a.children[ 0 ], child1, 'The first one is still there' );
  370. a.remove( child1 );
  371. assert.strictEqual( a.children.length, 1, 'The first child was removed' );
  372. assert.strictEqual( a.children[ 0 ], child2, 'The second one is still there' );
  373. a.add( child1 );
  374. a.remove( child1, child2 );
  375. assert.strictEqual( a.children.length, 0, 'Both children were removed at once' );
  376. child1.add( child2 );
  377. assert.strictEqual( child1.children.length, 1, 'The second child was added to the first one' );
  378. a.add( child2 );
  379. assert.strictEqual( a.children.length, 1, 'The second one was added to the parent (no remove)' );
  380. assert.strictEqual( a.children[ 0 ], child2, 'The second one is now the parent\'s child again' );
  381. assert.strictEqual( child1.children.length, 0, 'The first one no longer has any children' );
  382. a.add( child1 );
  383. assert.strictEqual( a.children.length, 2, 'The first child was added to the parent' );
  384. a.clear();
  385. assert.strictEqual( a.children.length, 0, 'All childrens were removed' );
  386. assert.strictEqual( child1.parent, null, 'First child has no parent' );
  387. assert.strictEqual( child2.parent, null, 'Second child has no parent' );
  388. a.add( child1 );
  389. assert.strictEqual( a.children.length, 1, 'The child was added to the parent' );
  390. child1.removeFromParent();
  391. assert.strictEqual( a.children.length, 0, 'The child was removed' );
  392. assert.strictEqual( child1.parent, null, 'Child has no parent' );
  393. } );
  394. QUnit.test( 'attach', ( assert ) => {
  395. const object = new Object3D();
  396. const oldParent = new Object3D();
  397. const newParent = new Object3D();
  398. const expectedMatrixWorld = new Matrix4();
  399. // Attach to a parent
  400. object.position.set( 1, 2, 3 );
  401. object.rotation.set( Math.PI / 2, Math.PI / 3, Math.PI / 4 );
  402. object.scale.set( 2, 3, 4 );
  403. newParent.position.set( 4, 5, 6 );
  404. newParent.rotation.set( Math.PI / 5, Math.PI / 6, Math.PI / 7 );
  405. newParent.scale.set( 5, 5, 5 );
  406. object.updateMatrixWorld();
  407. newParent.updateMatrixWorld();
  408. expectedMatrixWorld.copy( object.matrixWorld );
  409. newParent.attach( object );
  410. assert.ok( object.parent && object.parent == newParent &&
  411. oldParent.children.indexOf( object ) === - 1,
  412. 'object is a child of a new parent' );
  413. assert.ok( matrixEquals4( expectedMatrixWorld, object.matrixWorld ), 'object\'s world matrix is maintained' );
  414. // Attach to a new parent from an old parent
  415. object.position.set( 1, 2, 3 );
  416. object.rotation.set( Math.PI / 2, Math.PI / 3, Math.PI / 4 );
  417. object.scale.set( 2, 3, 4 );
  418. oldParent.position.set( 4, 5, 6 );
  419. oldParent.rotation.set( Math.PI / 5, Math.PI / 6, Math.PI / 7 );
  420. oldParent.scale.set( 5, 5, 5 );
  421. newParent.position.set( 7, 8, 9 );
  422. newParent.rotation.set( Math.PI / 8, Math.PI / 9, Math.PI / 10 );
  423. newParent.scale.set( 6, 6, 6 );
  424. oldParent.add( object );
  425. oldParent.updateMatrixWorld();
  426. newParent.updateMatrixWorld();
  427. expectedMatrixWorld.copy( object.matrixWorld );
  428. newParent.attach( object );
  429. assert.ok( object.parent && object.parent == newParent &&
  430. newParent.children.indexOf( object ) !== - 1 &&
  431. oldParent.children.indexOf( object ) === - 1,
  432. 'object is no longer a child of an old parent and is a child of a new parent now' );
  433. assert.ok( matrixEquals4( expectedMatrixWorld, object.matrixWorld ),
  434. 'object\'s world matrix is maintained even it had a parent' );
  435. } );
  436. QUnit.test( 'getObjectById/getObjectByName/getObjectByProperty', ( assert ) => {
  437. const parent = new Object3D();
  438. const childName = new Object3D();
  439. const childId = new Object3D(); // id = parent.id + 2
  440. const childNothing = new Object3D();
  441. parent.prop = true;
  442. childName.name = 'foo';
  443. parent.add( childName, childId, childNothing );
  444. assert.strictEqual( parent.getObjectByProperty( 'prop', true ), parent, 'Get parent by its own property' );
  445. assert.strictEqual( parent.getObjectByName( 'foo' ), childName, 'Get child by name' );
  446. assert.strictEqual( parent.getObjectById( parent.id + 2 ), childId, 'Get child by Id' );
  447. assert.strictEqual(
  448. parent.getObjectByProperty( 'no-property', 'no-value' ), undefined,
  449. 'Unknown property results in undefined'
  450. );
  451. } );
  452. QUnit.test( 'getObjectsByProperty', ( assert ) => {
  453. const parent = new Object3D();
  454. const childName = new Object3D();
  455. const childNothing = new Object3D();
  456. const childName2 = new Object3D();
  457. const childName3 = new Object3D();
  458. parent.prop = true;
  459. childName.name = 'foo';
  460. childName2.name = 'foo';
  461. childName3.name = 'foo';
  462. childName2.add( childName3 );
  463. childName.add( childName2 );
  464. parent.add( childName, childNothing );
  465. assert.strictEqual( parent.getObjectsByProperty( 'name', 'foo' ).length, 3, 'Get amount of all childs by name "foo"' );
  466. assert.strictEqual( parent.getObjectsByProperty( 'name', 'foo' ).some( obj => obj.name !== 'foo' ), false, 'Get all childs by name "foo"' );
  467. } );
  468. QUnit.test( 'getWorldPosition', ( assert ) => {
  469. const a = new Object3D();
  470. const b = new Object3D();
  471. const expectedSingle = new Vector3( x, y, z );
  472. const expectedParent = new Vector3( x, y, 0 );
  473. const expectedChild = new Vector3( x, y, 7 );
  474. const position = new Vector3();
  475. a.translateX( x );
  476. a.translateY( y );
  477. a.translateZ( z );
  478. assert.deepEqual( a.getWorldPosition( position ), expectedSingle, 'WorldPosition as expected for single object' );
  479. // translate child and then parent
  480. b.translateZ( 7 );
  481. a.add( b );
  482. a.translateZ( - z );
  483. assert.deepEqual( a.getWorldPosition( position ), expectedParent, 'WorldPosition as expected for parent' );
  484. assert.deepEqual( b.getWorldPosition( position ), expectedChild, 'WorldPosition as expected for child' );
  485. } );
  486. QUnit.todo( 'getWorldQuaternion', ( assert ) => {
  487. assert.ok( false, 'everything\'s gonna be alright' );
  488. } );
  489. QUnit.test( 'getWorldScale', ( assert ) => {
  490. const a = new Object3D();
  491. const m = new Matrix4().makeScale( x, y, z );
  492. const expected = new Vector3( x, y, z );
  493. a.applyMatrix4( m );
  494. assert.deepEqual( a.getWorldScale( new Vector3() ), expected, 'WorldScale as expected' );
  495. } );
  496. QUnit.test( 'getWorldDirection', ( assert ) => {
  497. const a = new Object3D();
  498. const expected = new Vector3( 0, - 0.5 * Math.sqrt( 2 ), 0.5 * Math.sqrt( 2 ) );
  499. const direction = new Vector3();
  500. a.lookAt( new Vector3( 0, - 1, 1 ) );
  501. a.getWorldDirection( direction );
  502. assert.ok(
  503. Math.abs( direction.x - expected.x ) <= eps &&
  504. Math.abs( direction.y - expected.y ) <= eps &&
  505. Math.abs( direction.z - expected.z ) <= eps,
  506. 'Direction has the expected values'
  507. );
  508. } );
  509. QUnit.test( 'localTransformVariableInstantiation', ( assert ) => {
  510. const a = new Object3D();
  511. const b = new Object3D();
  512. const c = new Object3D();
  513. const d = new Object3D();
  514. a.getWorldDirection( new Vector3() );
  515. a.lookAt( new Vector3( 0, - 1, 1 ) );
  516. assert.ok( true, 'Calling lookAt after getWorldDirection does not create errors' );
  517. b.getWorldPosition( new Vector3() );
  518. b.lookAt( new Vector3( 0, - 1, 1 ) );
  519. assert.ok( true, 'Calling lookAt after getWorldPosition does not create errors' );
  520. c.getWorldQuaternion( new Quaternion() );
  521. c.lookAt( new Vector3( 0, - 1, 1 ) );
  522. assert.ok( true, 'Calling lookAt after getWorldQuaternion does not create errors' );
  523. d.getWorldScale( new Vector3() );
  524. d.lookAt( new Vector3( 0, - 1, 1 ) );
  525. assert.ok( true, 'Calling lookAt after getWorldScale does not create errors' );
  526. } );
  527. QUnit.todo( 'raycast', ( assert ) => {
  528. assert.ok( false, 'everything\'s gonna be alright' );
  529. } );
  530. QUnit.test( 'traverse/traverseVisible/traverseAncestors', ( assert ) => {
  531. const a = new Object3D();
  532. const b = new Object3D();
  533. const c = new Object3D();
  534. const d = new Object3D();
  535. let names = [];
  536. const expectedNormal = [ 'parent', 'child', 'childchild 1', 'childchild 2' ];
  537. const expectedVisible = [ 'parent', 'child', 'childchild 2' ];
  538. const expectedAncestors = [ 'child', 'parent' ];
  539. a.name = 'parent';
  540. b.name = 'child';
  541. c.name = 'childchild 1';
  542. c.visible = false;
  543. d.name = 'childchild 2';
  544. b.add( c );
  545. b.add( d );
  546. a.add( b );
  547. a.traverse( function ( obj ) {
  548. names.push( obj.name );
  549. } );
  550. assert.deepEqual( names, expectedNormal, 'Traversed objects in expected order' );
  551. names = [];
  552. a.traverseVisible( function ( obj ) {
  553. names.push( obj.name );
  554. } );
  555. assert.deepEqual( names, expectedVisible, 'Traversed visible objects in expected order' );
  556. names = [];
  557. c.traverseAncestors( function ( obj ) {
  558. names.push( obj.name );
  559. } );
  560. assert.deepEqual( names, expectedAncestors, 'Traversed ancestors in expected order' );
  561. } );
  562. QUnit.test( 'updateMatrix', ( assert ) => {
  563. const a = new Object3D();
  564. a.position.set( 2, 3, 4 );
  565. a.quaternion.set( 5, 6, 7, 8 );
  566. a.scale.set( 9, 10, 11 );
  567. assert.deepEqual( a.matrix.elements, [
  568. 1, 0, 0, 0,
  569. 0, 1, 0, 0,
  570. 0, 0, 1, 0,
  571. 0, 0, 0, 1
  572. ], 'Updating position, quaternion, or scale has no effect to matrix until calling updateMatrix()' );
  573. a.updateMatrix();
  574. assert.deepEqual( a.matrix.elements, [
  575. - 1521, 1548, - 234, 0,
  576. - 520, - 1470, 1640, 0,
  577. 1826, 44, - 1331, 0,
  578. 2, 3, 4, 1
  579. ], 'matrix is calculated from position, quaternion, and scale' );
  580. assert.equal( a.matrixWorldNeedsUpdate, true, 'The flag indicating world matrix needs to be updated should be true' );
  581. } );
  582. QUnit.test( 'updateMatrixWorld', ( assert ) => {
  583. const parent = new Object3D();
  584. const child = new Object3D();
  585. // -- Standard usage test
  586. parent.position.set( 1, 2, 3 );
  587. child.position.set( 4, 5, 6 );
  588. parent.add( child );
  589. parent.updateMatrixWorld();
  590. assert.deepEqual( parent.matrix.elements, [
  591. 1, 0, 0, 0,
  592. 0, 1, 0, 0,
  593. 0, 0, 1, 0,
  594. 1, 2, 3, 1
  595. ], 'updateMatrixWorld() updates local matrix' );
  596. assert.deepEqual( parent.matrixWorld.elements, [
  597. 1, 0, 0, 0,
  598. 0, 1, 0, 0,
  599. 0, 0, 1, 0,
  600. 1, 2, 3, 1
  601. ], 'updateMatrixWorld() updates world matrix' );
  602. assert.deepEqual( child.matrix.elements, [
  603. 1, 0, 0, 0,
  604. 0, 1, 0, 0,
  605. 0, 0, 1, 0,
  606. 4, 5, 6, 1
  607. ], 'updateMatrixWorld() updates children\'s local matrix' );
  608. assert.deepEqual( child.matrixWorld.elements, [
  609. 1, 0, 0, 0,
  610. 0, 1, 0, 0,
  611. 0, 0, 1, 0,
  612. 5, 7, 9, 1
  613. ], 'updateMatrixWorld() updates children\'s world matrices from their parent world matrix and their local matrices' );
  614. assert.equal( parent.matrixWorldNeedsUpdate || child.matrixWorldNeedsUpdate, false, 'The flag indicating world matrix needs to be updated should be false after updating world matrix' );
  615. // -- No sync between local position/quaternion/scale/matrix and world matrix test
  616. parent.position.set( 0, 0, 0 );
  617. parent.updateMatrix();
  618. assert.deepEqual( parent.matrixWorld.elements, [
  619. 1, 0, 0, 0,
  620. 0, 1, 0, 0,
  621. 0, 0, 1, 0,
  622. 1, 2, 3, 1
  623. ], 'Updating position, quaternion, scale, or local matrix has no effect to world matrix until calling updateWorldMatrix()' );
  624. // -- matrixAutoUpdate = false test
  625. // Resetting local and world matrices to the origin
  626. child.position.set( 0, 0, 0 );
  627. parent.updateMatrixWorld();
  628. parent.position.set( 1, 2, 3 );
  629. parent.matrixAutoUpdate = false;
  630. child.matrixAutoUpdate = false;
  631. parent.updateMatrixWorld();
  632. assert.deepEqual( parent.matrix.elements, [
  633. 1, 0, 0, 0,
  634. 0, 1, 0, 0,
  635. 0, 0, 1, 0,
  636. 0, 0, 0, 1
  637. ], 'updateMatrixWorld() doesn\'t update local matrix if matrixAutoUpdate is false' );
  638. assert.deepEqual( parent.matrixWorld.elements, [
  639. 1, 0, 0, 0,
  640. 0, 1, 0, 0,
  641. 0, 0, 1, 0,
  642. 0, 0, 0, 1
  643. ], 'World matrix isn\'t updated because local matrix isn\'t updated and the flag indicating world matrix needs to be updated didn\'t rise' );
  644. assert.deepEqual( child.matrixWorld.elements, [
  645. 1, 0, 0, 0,
  646. 0, 1, 0, 0,
  647. 0, 0, 1, 0,
  648. 0, 0, 0, 1
  649. ], 'No effect to child world matrix if parent local and world matrices and child local matrix are not updated' );
  650. // -- matrixWorldAutoUpdate = false test
  651. parent.position.set( 3, 2, 1 );
  652. parent.updateMatrix();
  653. parent.matrixWorldNeedsUpdate = false;
  654. child.matrixWorldAutoUpdate = false;
  655. parent.updateMatrixWorld();
  656. assert.deepEqual( child.matrixWorld.elements, [
  657. 1, 0, 0, 0,
  658. 0, 1, 0, 0,
  659. 0, 0, 1, 0,
  660. 0, 0, 0, 1
  661. ], 'No effect to child world matrix when matrixWorldAutoUpdate is set to false' );
  662. // -- Propagation to children world matrices test
  663. child.position.set( 0, 0, 0 );
  664. parent.position.set( 1, 2, 3 );
  665. child.matrixWorldAutoUpdate = true;
  666. parent.matrixAutoUpdate = true;
  667. parent.updateMatrixWorld();
  668. assert.deepEqual( child.matrixWorld.elements, [
  669. 1, 0, 0, 0,
  670. 0, 1, 0, 0,
  671. 0, 0, 1, 0,
  672. 1, 2, 3, 1
  673. ], 'Updating parent world matrix has effect to children world matrices even if children local matrices aren\'t changed' );
  674. // -- force argument test
  675. // Resetting the local and world matrices to the origin
  676. child.position.set( 0, 0, 0 );
  677. child.matrixAutoUpdate = true;
  678. parent.updateMatrixWorld();
  679. parent.position.set( 1, 2, 3 );
  680. parent.updateMatrix();
  681. parent.matrixAutoUpdate = false;
  682. parent.matrixWorldNeedsUpdate = false;
  683. parent.updateMatrixWorld( true );
  684. assert.deepEqual( parent.matrixWorld.elements, [
  685. 1, 0, 0, 0,
  686. 0, 1, 0, 0,
  687. 0, 0, 1, 0,
  688. 1, 2, 3, 1
  689. ], 'force = true forces to update world matrix even if local matrix is not changed' );
  690. // -- Restriction test: No effect to parent matrices
  691. // Resetting the local and world matrices to the origin
  692. parent.position.set( 0, 0, 0 );
  693. child.position.set( 0, 0, 0 );
  694. parent.matrixAutoUpdate = true;
  695. child.matrixAutoUpdate = true;
  696. parent.updateMatrixWorld();
  697. parent.position.set( 1, 2, 3 );
  698. child.position.set( 4, 5, 6 );
  699. child.updateMatrixWorld();
  700. assert.deepEqual( parent.matrix.elements, [
  701. 1, 0, 0, 0,
  702. 0, 1, 0, 0,
  703. 0, 0, 1, 0,
  704. 0, 0, 0, 1
  705. ], 'updateMatrixWorld() doesn\'t update parent local matrix' );
  706. assert.deepEqual( parent.matrixWorld.elements, [
  707. 1, 0, 0, 0,
  708. 0, 1, 0, 0,
  709. 0, 0, 1, 0,
  710. 0, 0, 0, 1
  711. ], 'updateMatrixWorld() doesn\'t update parent world matrix' );
  712. assert.deepEqual( child.matrixWorld.elements, [
  713. 1, 0, 0, 0,
  714. 0, 1, 0, 0,
  715. 0, 0, 1, 0,
  716. 4, 5, 6, 1
  717. ], 'updateMatrixWorld() calculates world matrix from the current parent world matrix' );
  718. } );
  719. QUnit.test( 'updateWorldMatrix', ( assert ) => {
  720. const object = new Object3D();
  721. const parent = new Object3D();
  722. const child = new Object3D();
  723. const m = new Matrix4();
  724. const v = new Vector3();
  725. parent.add( object );
  726. object.add( child );
  727. parent.position.set( 1, 2, 3 );
  728. object.position.set( 4, 5, 6 );
  729. child.position.set( 7, 8, 9 );
  730. // Update the world matrix of an object
  731. object.updateWorldMatrix();
  732. assert.deepEqual( parent.matrix.elements,
  733. m.elements,
  734. 'No effect to parents\' local matrices' );
  735. assert.deepEqual( parent.matrixWorld.elements,
  736. m.elements,
  737. 'No effect to parents\' world matrices' );
  738. assert.deepEqual( object.matrix.elements,
  739. m.setPosition( object.position ).elements,
  740. 'Object\'s local matrix is updated' );
  741. assert.deepEqual( object.matrixWorld.elements,
  742. m.setPosition( object.position ).elements,
  743. 'Object\'s world matrix is updated' );
  744. assert.deepEqual( child.matrix.elements,
  745. m.identity().elements,
  746. 'No effect to children\'s local matrices' );
  747. assert.deepEqual( child.matrixWorld.elements,
  748. m.elements,
  749. 'No effect to children\'s world matrices' );
  750. // Update the world matrices of an object and its parents
  751. object.matrix.identity();
  752. object.matrixWorld.identity();
  753. object.updateWorldMatrix( true, false );
  754. assert.deepEqual( parent.matrix.elements,
  755. m.setPosition( parent.position ).elements,
  756. 'Parents\' local matrices are updated' );
  757. assert.deepEqual( parent.matrixWorld.elements,
  758. m.setPosition( parent.position ).elements,
  759. 'Parents\' world matrices are updated' );
  760. assert.deepEqual( object.matrix.elements,
  761. m.setPosition( object.position ).elements,
  762. 'Object\'s local matrix is updated' );
  763. assert.deepEqual( object.matrixWorld.elements,
  764. m.setPosition( v.copy( parent.position ).add( object.position ) ).elements,
  765. 'Object\'s world matrix is updated' );
  766. assert.deepEqual( child.matrix.elements,
  767. m.identity().elements,
  768. 'No effect to children\'s local matrices' );
  769. assert.deepEqual( child.matrixWorld.elements,
  770. m.identity().elements,
  771. 'No effect to children\'s world matrices' );
  772. // Update the world matrices of an object and its children
  773. parent.matrix.identity();
  774. parent.matrixWorld.identity();
  775. object.matrix.identity();
  776. object.matrixWorld.identity();
  777. object.updateWorldMatrix( false, true );
  778. assert.deepEqual( parent.matrix.elements,
  779. m.elements,
  780. 'No effect to parents\' local matrices' );
  781. assert.deepEqual( parent.matrixWorld.elements,
  782. m.elements,
  783. 'No effect to parents\' world matrices' );
  784. assert.deepEqual( object.matrix.elements,
  785. m.setPosition( object.position ).elements,
  786. 'Object\'s local matrix is updated' );
  787. assert.deepEqual( object.matrixWorld.elements,
  788. m.setPosition( object.position ).elements,
  789. 'Object\'s world matrix is updated' );
  790. assert.deepEqual( child.matrix.elements,
  791. m.setPosition( child.position ).elements,
  792. 'Children\'s local matrices are updated' );
  793. assert.deepEqual( child.matrixWorld.elements,
  794. m.setPosition( v.copy( object.position ).add( child.position ) ).elements,
  795. 'Children\'s world matrices are updated' );
  796. // Update the world matrices of an object and its parents and children
  797. object.matrix.identity();
  798. object.matrixWorld.identity();
  799. child.matrix.identity();
  800. child.matrixWorld.identity();
  801. object.updateWorldMatrix( true, true );
  802. assert.deepEqual( parent.matrix.elements,
  803. m.setPosition( parent.position ).elements,
  804. 'Parents\' local matrices are updated' );
  805. assert.deepEqual( parent.matrixWorld.elements,
  806. m.setPosition( parent.position ).elements,
  807. 'Parents\' world matrices are updated' );
  808. assert.deepEqual( object.matrix.elements,
  809. m.setPosition( object.position ).elements,
  810. 'Object\'s local matrix is updated' );
  811. assert.deepEqual( object.matrixWorld.elements,
  812. m.setPosition( v.copy( parent.position ).add( object.position ) ).elements,
  813. 'Object\'s world matrix is updated' );
  814. assert.deepEqual( child.matrix.elements,
  815. m.setPosition( child.position ).elements,
  816. 'Children\'s local matrices are updated' );
  817. assert.deepEqual( child.matrixWorld.elements,
  818. m.setPosition( v.copy( parent.position ).add( object.position ).add( child.position ) ).elements,
  819. 'Children\'s world matrices are updated' );
  820. // object.matrixAutoUpdate = false test
  821. object.matrix.identity();
  822. object.matrixWorld.identity();
  823. object.matrixAutoUpdate = false;
  824. object.updateWorldMatrix( true, false );
  825. assert.deepEqual( object.matrix.elements,
  826. m.identity().elements,
  827. 'No effect to object\'s local matrix if matrixAutoUpdate is false' );
  828. assert.deepEqual( object.matrixWorld.elements,
  829. m.setPosition( parent.position ).elements,
  830. 'object\'s world matrix is updated even if matrixAutoUpdate is false' );
  831. // object.matrixWorldAutoUpdate = false test
  832. parent.matrixWorldAutoUpdate = false;
  833. child.matrixWorldAutoUpdate = false;
  834. child.matrixWorld.identity();
  835. parent.matrixWorld.identity();
  836. object.updateWorldMatrix( true, true );
  837. assert.deepEqual( child.matrixWorld.elements,
  838. m.identity().elements,
  839. 'No effect to child\'s world matrix if matrixWorldAutoUpdate is false' );
  840. assert.deepEqual( parent.matrixWorld.elements,
  841. m.identity().elements,
  842. 'No effect to parent\'s world matrix if matrixWorldAutoUpdate is false' );
  843. } );
  844. QUnit.test( 'toJSON', ( assert ) => {
  845. const a = new Object3D();
  846. const child = new Object3D();
  847. const childChild = new Object3D();
  848. a.name = 'a\'s name';
  849. a.matrix.set( 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 );
  850. a.visible = false;
  851. a.castShadow = true;
  852. a.receiveShadow = true;
  853. a.userData[ 'foo' ] = 'bar';
  854. a.up.set( 1, 0, 0 );
  855. child.uuid = '5D4E9AE8-DA61-4912-A575-71A5BE3D72CD';
  856. childChild.uuid = 'B43854B3-E970-4E85-BD41-AAF8D7BFA189';
  857. child.add( childChild );
  858. a.add( child );
  859. const gold = {
  860. 'metadata': {
  861. 'version': 4.5,
  862. 'type': 'Object',
  863. 'generator': 'Object3D.toJSON'
  864. },
  865. 'object': {
  866. 'uuid': '0A1E4F43-CB5B-4097-8F82-DC2969C0B8C2',
  867. 'type': 'Object3D',
  868. 'name': 'a\'s name',
  869. 'castShadow': true,
  870. 'receiveShadow': true,
  871. 'visible': false,
  872. 'userData': { 'foo': 'bar' },
  873. 'layers': 1,
  874. 'matrix': [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ],
  875. 'children': [
  876. {
  877. 'uuid': '5D4E9AE8-DA61-4912-A575-71A5BE3D72CD',
  878. 'type': 'Object3D',
  879. 'layers': 1,
  880. 'matrix': [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ],
  881. 'children': [
  882. {
  883. 'uuid': 'B43854B3-E970-4E85-BD41-AAF8D7BFA189',
  884. 'type': 'Object3D',
  885. 'layers': 1,
  886. 'matrix': [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ],
  887. 'up': [ 0, 1, 0 ]
  888. }
  889. ],
  890. 'up': [ 0, 1, 0 ]
  891. }
  892. ],
  893. 'up': [ 1, 0, 0 ]
  894. }
  895. };
  896. // hacks
  897. const out = a.toJSON();
  898. out.object.uuid = '0A1E4F43-CB5B-4097-8F82-DC2969C0B8C2';
  899. assert.deepEqual( out, gold, 'JSON is as expected' );
  900. } );
  901. QUnit.test( 'clone', ( assert ) => {
  902. let a;
  903. const b = new Object3D();
  904. assert.strictEqual( a, undefined, 'Undefined pre-clone()' );
  905. a = b.clone();
  906. assert.notStrictEqual( a, b, 'Defined but seperate instances post-clone()' );
  907. a.uuid = b.uuid;
  908. assert.deepEqual( a, b, 'But identical properties' );
  909. } );
  910. QUnit.test( 'copy', ( assert ) => {
  911. const a = new Object3D();
  912. const b = new Object3D();
  913. const child = new Object3D();
  914. const childChild = new Object3D();
  915. a.name = 'original';
  916. b.name = 'to-be-copied';
  917. b.position.set( x, y, z );
  918. b.quaternion.set( x, y, z, w );
  919. b.scale.set( 2, 3, 4 );
  920. // bogus QUnit.test values
  921. b.matrix.set( 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 );
  922. b.matrixWorld.set( 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 );
  923. b.matrixAutoUpdate = false;
  924. b.matrixWorldNeedsUpdate = true;
  925. b.layers.mask = 2;
  926. b.visible = false;
  927. b.castShadow = true;
  928. b.receiveShadow = true;
  929. b.frustumCulled = false;
  930. b.renderOrder = 1;
  931. b.userData[ 'foo' ] = 'bar';
  932. child.add( childChild );
  933. b.add( child );
  934. assert.notDeepEqual( a, b, 'Objects are not equal pre-copy()' );
  935. a.copy( b, true );
  936. // check they're all unique instances
  937. assert.ok(
  938. a.uuid !== b.uuid &&
  939. a.children[ 0 ].uuid !== b.children[ 0 ].uuid &&
  940. a.children[ 0 ].children[ 0 ].uuid !== b.children[ 0 ].children[ 0 ].uuid,
  941. 'UUIDs are all different'
  942. );
  943. // and now fix that
  944. a.uuid = b.uuid;
  945. a.children[ 0 ].uuid = b.children[ 0 ].uuid;
  946. a.children[ 0 ].children[ 0 ].uuid = b.children[ 0 ].children[ 0 ].uuid;
  947. assert.deepEqual( a, b, 'Objects are equal post-copy()' );
  948. } );
  949. } );
  950. } );