ccc.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915
  1. class Object3D extends EventDispatcher {
  2. constructor() {
  3. super();
  4. this.isObject3D = true;
  5. Object.defineProperty( this, 'id', { value: _object3DId ++ } );
  6. this.uuid = generateUUID();
  7. this.name = '';
  8. this.type = 'Object3D';
  9. this.parent = null;
  10. this.children = [];
  11. this.up = Object3D.DefaultUp.clone();
  12. const position = new Vector3();
  13. const rotation = new Euler();
  14. const quaternion = new Quaternion();
  15. const scale = new Vector3( 1, 1, 1 );
  16. function onRotationChange() {
  17. quaternion.setFromEuler( rotation, false );
  18. }
  19. function onQuaternionChange() {
  20. rotation.setFromQuaternion( quaternion, undefined, false );
  21. }
  22. rotation._onChange( onRotationChange );
  23. quaternion._onChange( onQuaternionChange );
  24. Object.defineProperties( this, {
  25. position: {
  26. configurable: true,
  27. enumerable: true,
  28. value: position
  29. },
  30. rotation: {
  31. configurable: true,
  32. enumerable: true,
  33. value: rotation
  34. },
  35. quaternion: {
  36. configurable: true,
  37. enumerable: true,
  38. value: quaternion
  39. },
  40. scale: {
  41. configurable: true,
  42. enumerable: true,
  43. value: scale
  44. },
  45. modelViewMatrix: {
  46. value: new Matrix4()
  47. },
  48. normalMatrix: {
  49. value: new Matrix3()
  50. }
  51. } );
  52. this.matrix = new Matrix4();
  53. this.matrixWorld = new Matrix4();
  54. this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate;
  55. this.matrixWorldNeedsUpdate = false;
  56. this.matrixWorldAutoUpdate = Object3D.DefaultMatrixWorldAutoUpdate; // checked by the renderer
  57. this.layers = new Layers();
  58. this.visible = true;
  59. this.choice = null;
  60. this.castShadow = false;
  61. this.receiveShadow = false;
  62. this.frustumCulled = true;
  63. this.renderOrder = 0;
  64. this.animations = [];
  65. this.userData = {};
  66. }
  67. onBeforeRender( /* renderer, scene, camera, geometry, material, group */ ) {}
  68. onAfterRender( /* renderer, scene, camera, geometry, material, group */ ) {}
  69. applyMatrix4( matrix ) {
  70. if ( this.matrixAutoUpdate ) this.updateMatrix();
  71. this.matrix.premultiply( matrix );
  72. this.matrix.decompose( this.position, this.quaternion, this.scale );
  73. }
  74. applyQuaternion( q ) {
  75. this.quaternion.premultiply( q );
  76. return this;
  77. }
  78. setRotationFromAxisAngle( axis, angle ) {
  79. // assumes axis is normalized
  80. this.quaternion.setFromAxisAngle( axis, angle );
  81. }
  82. setRotationFromEuler( euler ) {
  83. this.quaternion.setFromEuler( euler, true );
  84. }
  85. setRotationFromMatrix( m ) {
  86. // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
  87. this.quaternion.setFromRotationMatrix( m );
  88. }
  89. setRotationFromQuaternion( q ) {
  90. // assumes q is normalized
  91. this.quaternion.copy( q );
  92. }
  93. rotateOnAxis( axis, angle ) {
  94. // rotate object on axis in object space
  95. // axis is assumed to be normalized
  96. _q1.setFromAxisAngle( axis, angle );
  97. this.quaternion.multiply( _q1 );
  98. return this;
  99. }
  100. rotateOnWorldAxis( axis, angle ) {
  101. // rotate object on axis in world space
  102. // axis is assumed to be normalized
  103. // method assumes no rotated parent
  104. _q1.setFromAxisAngle( axis, angle );
  105. this.quaternion.premultiply( _q1 );
  106. return this;
  107. }
  108. rotateX( angle ) {
  109. return this.rotateOnAxis( _xAxis, angle );
  110. }
  111. rotateY( angle ) {
  112. return this.rotateOnAxis( _yAxis, angle );
  113. }
  114. rotateZ( angle ) {
  115. return this.rotateOnAxis( _zAxis, angle );
  116. }
  117. translateOnAxis( axis, distance ) {
  118. // translate object by distance along axis in object space
  119. // axis is assumed to be normalized
  120. _v1$4.copy( axis ).applyQuaternion( this.quaternion );
  121. this.position.add( _v1$4.multiplyScalar( distance ) );
  122. return this;
  123. }
  124. translateX( distance ) {
  125. return this.translateOnAxis( _xAxis, distance );
  126. }
  127. translateY( distance ) {
  128. return this.translateOnAxis( _yAxis, distance );
  129. }
  130. translateZ( distance ) {
  131. return this.translateOnAxis( _zAxis, distance );
  132. }
  133. localToWorld( vector ) {
  134. return vector.applyMatrix4( this.matrixWorld );
  135. }
  136. worldToLocal( vector ) {
  137. return vector.applyMatrix4( _m1$1.copy( this.matrixWorld ).invert() );
  138. }
  139. lookAt( x, y, z ) {
  140. // This method does not support objects having non-uniformly-scaled parent(s)
  141. if ( x.isVector3 ) {
  142. _target.copy( x );
  143. } else {
  144. _target.set( x, y, z );
  145. }
  146. const parent = this.parent;
  147. this.updateWorldMatrix( true, false );
  148. _position$3.setFromMatrixPosition( this.matrixWorld );
  149. if ( this.isCamera || this.isLight ) {
  150. _m1$1.lookAt( _position$3, _target, this.up );
  151. } else {
  152. _m1$1.lookAt( _target, _position$3, this.up );
  153. }
  154. this.quaternion.setFromRotationMatrix( _m1$1 );
  155. if ( parent ) {
  156. _m1$1.extractRotation( parent.matrixWorld );
  157. _q1.setFromRotationMatrix( _m1$1 );
  158. this.quaternion.premultiply( _q1.invert() );
  159. }
  160. }
  161. add( object ) {
  162. if ( arguments.length > 1 ) {
  163. for ( let i = 0; i < arguments.length; i ++ ) {
  164. this.add( arguments[ i ] );
  165. }
  166. return this;
  167. }
  168. if ( object === this ) {
  169. console.error( 'THREE.Object3D.add: object can\'t be added as a child of itself.', object );
  170. return this;
  171. }
  172. if ( object && object.isObject3D ) {
  173. if ( object.parent !== null ) {
  174. object.parent.remove( object );
  175. }
  176. object.parent = this;
  177. this.children.push( object );
  178. object.dispatchEvent( _addedEvent );
  179. } else {
  180. console.error( 'THREE.Object3D.add: object not an instance of THREE.Object3D.', object );
  181. }
  182. return this;
  183. }
  184. remove( object ) {
  185. if ( arguments.length > 1 ) {
  186. for ( let i = 0; i < arguments.length; i ++ ) {
  187. this.remove( arguments[ i ] );
  188. }
  189. return this;
  190. }
  191. const index = this.children.indexOf( object );
  192. if ( index !== - 1 ) {
  193. object.parent = null;
  194. this.children.splice( index, 1 );
  195. object.dispatchEvent( _removedEvent );
  196. }
  197. return this;
  198. }
  199. removeFromParent() {
  200. const parent = this.parent;
  201. if ( parent !== null ) {
  202. parent.remove( this );
  203. }
  204. return this;
  205. }
  206. clear() {
  207. for ( let i = 0; i < this.children.length; i ++ ) {
  208. const object = this.children[ i ];
  209. object.parent = null;
  210. object.dispatchEvent( _removedEvent );
  211. }
  212. this.children.length = 0;
  213. return this;
  214. }
  215. attach( object ) {
  216. // adds object as a child of this, while maintaining the object's world transform
  217. // Note: This method does not support scene graphs having non-uniformly-scaled nodes(s)
  218. this.updateWorldMatrix( true, false );
  219. _m1$1.copy( this.matrixWorld ).invert();
  220. if ( object.parent !== null ) {
  221. object.parent.updateWorldMatrix( true, false );
  222. _m1$1.multiply( object.parent.matrixWorld );
  223. }
  224. object.applyMatrix4( _m1$1 );
  225. this.add( object );
  226. object.updateWorldMatrix( false, true );
  227. return this;
  228. }
  229. getObjectById( id ) {
  230. return this.getObjectByProperty( 'id', id );
  231. }
  232. getObjectByName( name ) {
  233. return this.getObjectByProperty( 'name', name );
  234. }
  235. getObjectByProperty( name, value ) {
  236. if ( this[ name ] === value ) return this;
  237. for ( let i = 0, l = this.children.length; i < l; i ++ ) {
  238. const child = this.children[ i ];
  239. const object = child.getObjectByProperty( name, value );
  240. if ( object !== undefined ) {
  241. return object;
  242. }
  243. }
  244. return undefined;
  245. }
  246. getWorldPosition( target ) {
  247. this.updateWorldMatrix( true, false );
  248. return target.setFromMatrixPosition( this.matrixWorld );
  249. }
  250. getWorldQuaternion( target ) {
  251. this.updateWorldMatrix( true, false );
  252. this.matrixWorld.decompose( _position$3, target, _scale$2 );
  253. return target;
  254. }
  255. getWorldScale( target ) {
  256. this.updateWorldMatrix( true, false );
  257. this.matrixWorld.decompose( _position$3, _quaternion$2, target );
  258. return target;
  259. }
  260. getWorldDirection( target ) {
  261. this.updateWorldMatrix( true, false );
  262. const e = this.matrixWorld.elements;
  263. return target.set( e[ 8 ], e[ 9 ], e[ 10 ] ).normalize();
  264. }
  265. raycast( /* raycaster, intersects */ ) {}
  266. traverse( callback ) {
  267. callback( this );
  268. const children = this.children;
  269. for ( let i = 0, l = children.length; i < l; i ++ ) {
  270. children[ i ].traverse( callback );
  271. }
  272. }
  273. traverseVisible( callback ) {
  274. if ( this.visible === false ) return;
  275. callback( this );
  276. const children = this.children;
  277. for ( let i = 0, l = children.length; i < l; i ++ ) {
  278. children[ i ].traverseVisible( callback );
  279. }
  280. }
  281. traverseAncestors( callback ) {
  282. const parent = this.parent;
  283. if ( parent !== null ) {
  284. callback( parent );
  285. parent.traverseAncestors( callback );
  286. }
  287. }
  288. updateMatrix() {
  289. this.matrix.compose( this.position, this.quaternion, this.scale );
  290. this.matrixWorldNeedsUpdate = true;
  291. }
  292. updateMatrixWorld( force ) {
  293. if ( this.matrixAutoUpdate ) this.updateMatrix();
  294. if ( this.matrixWorldNeedsUpdate || force ) {
  295. if ( this.parent === null ) {
  296. this.matrixWorld.copy( this.matrix );
  297. } else {
  298. this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
  299. }
  300. this.matrixWorldNeedsUpdate = false;
  301. force = true;
  302. }
  303. // update children
  304. const children = this.children;
  305. for ( let i = 0, l = children.length; i < l; i ++ ) {
  306. const child = children[ i ];
  307. if ( child.matrixWorldAutoUpdate === true || force === true ) {
  308. child.updateMatrixWorld( force );
  309. }
  310. }
  311. }
  312. updateWorldMatrix( updateParents, updateChildren ) {
  313. const parent = this.parent;
  314. if ( updateParents === true && parent !== null && parent.matrixWorldAutoUpdate === true ) {
  315. parent.updateWorldMatrix( true, false );
  316. }
  317. if ( this.matrixAutoUpdate ) this.updateMatrix();
  318. if ( this.parent === null ) {
  319. this.matrixWorld.copy( this.matrix );
  320. } else {
  321. this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
  322. }
  323. // update children
  324. if ( updateChildren === true ) {
  325. const children = this.children;
  326. for ( let i = 0, l = children.length; i < l; i ++ ) {
  327. const child = children[ i ];
  328. if ( child.matrixWorldAutoUpdate === true ) {
  329. child.updateWorldMatrix( false, true );
  330. }
  331. }
  332. }
  333. }
  334. toJSON( meta ) {
  335. // meta is a string when called from JSON.stringify
  336. const isRootObject = ( meta === undefined || typeof meta === 'string' );
  337. const output = {};
  338. // meta is a hash used to collect geometries, materials.
  339. // not providing it implies that this is the root object
  340. // being serialized.
  341. if ( isRootObject ) {
  342. // initialize meta obj
  343. meta = {
  344. geometries: {},
  345. materials: {},
  346. textures: {},
  347. images: {},
  348. shapes: {},
  349. skeletons: {},
  350. animations: {},
  351. nodes: {}
  352. };
  353. output.metadata = {
  354. version: 4.5,
  355. type: 'Object',
  356. generator: 'Object3D.toJSON'
  357. };
  358. }
  359. // standard Object3D serialization
  360. const object = {};
  361. object.uuid = this.uuid;
  362. object.type = this.type;
  363. object.choice = this.choice;
  364. if ( this.name !== '' ) object.name = this.name;
  365. if ( this.castShadow === true ) object.castShadow = true;
  366. if ( this.receiveShadow === true ) object.receiveShadow = true;
  367. if ( this.visible === false ) object.visible = false;
  368. // if ( this.choice === false ) object.choice = false;
  369. if ( this.frustumCulled === false ) object.frustumCulled = false;
  370. if ( this.renderOrder !== 0 ) object.renderOrder = this.renderOrder;
  371. if ( JSON.stringify( this.userData ) !== '{}' ) object.userData = this.userData;
  372. object.layers = this.layers.mask;
  373. object.matrix = this.matrix.toArray();
  374. if ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false;
  375. // object specific properties
  376. if ( this.isInstancedMesh ) {
  377. object.type = 'InstancedMesh';
  378. object.count = this.count;
  379. object.instanceMatrix = this.instanceMatrix.toJSON();
  380. if ( this.instanceColor !== null ) object.instanceColor = this.instanceColor.toJSON();
  381. }
  382. //
  383. function serialize( library, element ) {
  384. if ( library[ element.uuid ] === undefined ) {
  385. library[ element.uuid ] = element.toJSON( meta );
  386. }
  387. return element.uuid;
  388. }
  389. if ( this.isScene ) {
  390. if ( this.background ) {
  391. if ( this.background.isColor ) {
  392. object.background = this.background.toJSON();
  393. } else if ( this.background.isTexture ) {
  394. object.background = this.background.toJSON( meta ).uuid;
  395. }
  396. }
  397. if ( this.environment && this.environment.isTexture && this.environment.isRenderTargetTexture !== true ) {
  398. object.environment = this.environment.toJSON( meta ).uuid;
  399. }
  400. } else if ( this.isMesh || this.isLine || this.isPoints ) {
  401. object.geometry = serialize( meta.geometries, this.geometry );
  402. const parameters = this.geometry.parameters;
  403. if ( parameters !== undefined && parameters.shapes !== undefined ) {
  404. const shapes = parameters.shapes;
  405. if ( Array.isArray( shapes ) ) {
  406. for ( let i = 0, l = shapes.length; i < l; i ++ ) {
  407. const shape = shapes[ i ];
  408. serialize( meta.shapes, shape );
  409. }
  410. } else {
  411. serialize( meta.shapes, shapes );
  412. }
  413. }
  414. }
  415. if ( this.isSkinnedMesh ) {
  416. object.bindMode = this.bindMode;
  417. object.bindMatrix = this.bindMatrix.toArray();
  418. if ( this.skeleton !== undefined ) {
  419. serialize( meta.skeletons, this.skeleton );
  420. object.skeleton = this.skeleton.uuid;
  421. }
  422. }
  423. if ( this.material !== undefined ) {
  424. if ( Array.isArray( this.material ) ) {
  425. const uuids = [];
  426. for ( let i = 0, l = this.material.length; i < l; i ++ ) {
  427. uuids.push( serialize( meta.materials, this.material[ i ] ) );
  428. }
  429. object.material = uuids;
  430. } else {
  431. object.material = serialize( meta.materials, this.material );
  432. }
  433. }
  434. //
  435. if ( this.children.length > 0 ) {
  436. object.children = [];
  437. for ( let i = 0; i < this.children.length; i ++ ) {
  438. object.children.push( this.children[ i ].toJSON( meta ).object );
  439. }
  440. }
  441. //
  442. if ( this.animations.length > 0 ) {
  443. object.animations = [];
  444. for ( let i = 0; i < this.animations.length; i ++ ) {
  445. const animation = this.animations[ i ];
  446. object.animations.push( serialize( meta.animations, animation ) );
  447. }
  448. }
  449. if ( isRootObject ) {
  450. const geometries = extractFromCache( meta.geometries );
  451. const materials = extractFromCache( meta.materials );
  452. const textures = extractFromCache( meta.textures );
  453. const images = extractFromCache( meta.images );
  454. const shapes = extractFromCache( meta.shapes );
  455. const skeletons = extractFromCache( meta.skeletons );
  456. const animations = extractFromCache( meta.animations );
  457. const nodes = extractFromCache( meta.nodes );
  458. if ( geometries.length > 0 ) output.geometries = geometries;
  459. if ( materials.length > 0 ) output.materials = materials;
  460. if ( textures.length > 0 ) output.textures = textures;
  461. if ( images.length > 0 ) output.images = images;
  462. if ( shapes.length > 0 ) output.shapes = shapes;
  463. if ( skeletons.length > 0 ) output.skeletons = skeletons;
  464. if ( animations.length > 0 ) output.animations = animations;
  465. if ( nodes.length > 0 ) output.nodes = nodes;
  466. }
  467. output.object = object;
  468. return output;
  469. // extract data from the cache hash
  470. // remove metadata on each item
  471. // and return as array
  472. function extractFromCache( cache ) {
  473. const values = [];
  474. for ( const key in cache ) {
  475. const data = cache[ key ];
  476. delete data.metadata;
  477. values.push( data );
  478. }
  479. return values;
  480. }
  481. }
  482. clone( recursive ) {
  483. return new this.constructor().copy( this, recursive );
  484. }
  485. copy( source, recursive = true ) {
  486. this.name = source.name;
  487. this.up.copy( source.up );
  488. this.position.copy( source.position );
  489. this.rotation.order = source.rotation.order;
  490. this.quaternion.copy( source.quaternion );
  491. this.scale.copy( source.scale );
  492. this.matrix.copy( source.matrix );
  493. this.matrixWorld.copy( source.matrixWorld );
  494. this.matrixAutoUpdate = source.matrixAutoUpdate;
  495. this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;
  496. this.matrixWorldAutoUpdate = source.matrixWorldAutoUpdate;
  497. this.layers.mask = source.layers.mask;
  498. this.visible = source.visible;
  499. this.choice = source.choice;
  500. this.castShadow = source.castShadow;
  501. this.receiveShadow = source.receiveShadow;
  502. this.frustumCulled = source.frustumCulled;
  503. this.renderOrder = source.renderOrder;
  504. this.userData = JSON.parse( JSON.stringify( source.userData ) );
  505. if ( recursive === true ) {
  506. for ( let i = 0; i < source.children.length; i ++ ) {
  507. const child = source.children[ i ];
  508. this.add( child.clone() );
  509. }
  510. }
  511. return this;
  512. }
  513. }