Object3D.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
  1. /**
  2. * @author mrdoob / http://mrdoob.com/
  3. * @author mikael emtinger / http://gomo.se/
  4. * @author alteredq / http://alteredqualia.com/
  5. * @author WestLangley / http://github.com/WestLangley
  6. * @author elephantatwork / www.elephantatwork.ch
  7. */
  8. THREE.Object3D = function () {
  9. Object.defineProperty( this, 'id', { value: THREE.Object3DIdCount ++ } );
  10. this.uuid = THREE.Math.generateUUID();
  11. this.name = '';
  12. this.type = 'Object3D';
  13. this.parent = null;
  14. this.children = [];
  15. this.up = THREE.Object3D.DefaultUp.clone();
  16. var position = new THREE.Vector3();
  17. var rotation = new THREE.Euler();
  18. var quaternion = new THREE.Quaternion();
  19. var scale = new THREE.Vector3( 1, 1, 1 );
  20. function onRotationChange() {
  21. quaternion.setFromEuler( rotation, false );
  22. }
  23. function onQuaternionChange() {
  24. rotation.setFromQuaternion( quaternion, undefined, false );
  25. }
  26. rotation.onChange( onRotationChange );
  27. quaternion.onChange( onQuaternionChange );
  28. Object.defineProperties( this, {
  29. position: {
  30. enumerable: true,
  31. value: position
  32. },
  33. rotation: {
  34. enumerable: true,
  35. value: rotation
  36. },
  37. quaternion: {
  38. enumerable: true,
  39. value: quaternion
  40. },
  41. scale: {
  42. enumerable: true,
  43. value: scale
  44. },
  45. modelViewMatrix: {
  46. value: new THREE.Matrix4()
  47. },
  48. normalMatrix: {
  49. value: new THREE.Matrix3()
  50. }
  51. } );
  52. this.rotationAutoUpdate = true;
  53. this.matrix = new THREE.Matrix4();
  54. this.matrixWorld = new THREE.Matrix4();
  55. this.matrixAutoUpdate = THREE.Object3D.DefaultMatrixAutoUpdate;
  56. this.matrixWorldNeedsUpdate = false;
  57. this.visible = true;
  58. this.castShadow = false;
  59. this.receiveShadow = false;
  60. this.frustumCulled = true;
  61. this.renderOrder = 0;
  62. this.userData = {};
  63. };
  64. THREE.Object3D.DefaultUp = new THREE.Vector3( 0, 1, 0 );
  65. THREE.Object3D.DefaultMatrixAutoUpdate = true;
  66. THREE.Object3D.prototype = {
  67. constructor: THREE.Object3D,
  68. get eulerOrder () {
  69. console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' );
  70. return this.rotation.order;
  71. },
  72. set eulerOrder ( value ) {
  73. console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' );
  74. this.rotation.order = value;
  75. },
  76. get useQuaternion () {
  77. console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' );
  78. },
  79. set useQuaternion ( value ) {
  80. console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' );
  81. },
  82. set renderDepth ( value ) {
  83. console.warn( 'THREE.Object3D: .renderDepth has been removed. Use .renderOrder, instead.' );
  84. },
  85. //
  86. applyMatrix: function ( matrix ) {
  87. this.matrix.multiplyMatrices( matrix, this.matrix );
  88. this.matrix.decompose( this.position, this.quaternion, this.scale );
  89. },
  90. setRotationFromAxisAngle: function ( axis, angle ) {
  91. // assumes axis is normalized
  92. this.quaternion.setFromAxisAngle( axis, angle );
  93. },
  94. setRotationFromEuler: function ( euler ) {
  95. this.quaternion.setFromEuler( euler, true );
  96. },
  97. setRotationFromMatrix: function ( m ) {
  98. // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
  99. this.quaternion.setFromRotationMatrix( m );
  100. },
  101. setRotationFromQuaternion: function ( q ) {
  102. // assumes q is normalized
  103. this.quaternion.copy( q );
  104. },
  105. rotateOnAxis: function () {
  106. // rotate object on axis in object space
  107. // axis is assumed to be normalized
  108. var q1 = new THREE.Quaternion();
  109. return function ( axis, angle ) {
  110. q1.setFromAxisAngle( axis, angle );
  111. this.quaternion.multiply( q1 );
  112. return this;
  113. };
  114. }(),
  115. rotateX: function () {
  116. var v1 = new THREE.Vector3( 1, 0, 0 );
  117. return function ( angle ) {
  118. return this.rotateOnAxis( v1, angle );
  119. };
  120. }(),
  121. rotateY: function () {
  122. var v1 = new THREE.Vector3( 0, 1, 0 );
  123. return function ( angle ) {
  124. return this.rotateOnAxis( v1, angle );
  125. };
  126. }(),
  127. rotateZ: function () {
  128. var v1 = new THREE.Vector3( 0, 0, 1 );
  129. return function ( angle ) {
  130. return this.rotateOnAxis( v1, angle );
  131. };
  132. }(),
  133. translateOnAxis: function () {
  134. // translate object by distance along axis in object space
  135. // axis is assumed to be normalized
  136. var v1 = new THREE.Vector3();
  137. return function ( axis, distance ) {
  138. v1.copy( axis ).applyQuaternion( this.quaternion );
  139. this.position.add( v1.multiplyScalar( distance ) );
  140. return this;
  141. };
  142. }(),
  143. translate: function ( distance, axis ) {
  144. console.warn( 'THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.' );
  145. return this.translateOnAxis( axis, distance );
  146. },
  147. translateX: function () {
  148. var v1 = new THREE.Vector3( 1, 0, 0 );
  149. return function ( distance ) {
  150. return this.translateOnAxis( v1, distance );
  151. };
  152. }(),
  153. translateY: function () {
  154. var v1 = new THREE.Vector3( 0, 1, 0 );
  155. return function ( distance ) {
  156. return this.translateOnAxis( v1, distance );
  157. };
  158. }(),
  159. translateZ: function () {
  160. var v1 = new THREE.Vector3( 0, 0, 1 );
  161. return function ( distance ) {
  162. return this.translateOnAxis( v1, distance );
  163. };
  164. }(),
  165. localToWorld: function ( vector ) {
  166. return vector.applyMatrix4( this.matrixWorld );
  167. },
  168. worldToLocal: function () {
  169. var m1 = new THREE.Matrix4();
  170. return function ( vector ) {
  171. return vector.applyMatrix4( m1.getInverse( this.matrixWorld ) );
  172. };
  173. }(),
  174. lookAt: function () {
  175. // This routine does not support objects with rotated and/or translated parent(s)
  176. var m1 = new THREE.Matrix4();
  177. return function ( vector ) {
  178. m1.lookAt( vector, this.position, this.up );
  179. this.quaternion.setFromRotationMatrix( m1 );
  180. };
  181. }(),
  182. add: function ( object ) {
  183. if ( arguments.length > 1 ) {
  184. for ( var i = 0; i < arguments.length; i ++ ) {
  185. this.add( arguments[ i ] );
  186. }
  187. return this;
  188. }
  189. if ( object === this ) {
  190. console.error( "THREE.Object3D.add: object can't be added as a child of itself.", object );
  191. return this;
  192. }
  193. if ( object instanceof THREE.Object3D ) {
  194. if ( object.parent !== null ) {
  195. object.parent.remove( object );
  196. }
  197. object.parent = this;
  198. object.dispatchEvent( { type: 'added' } );
  199. this.children.push( object );
  200. } else {
  201. console.error( "THREE.Object3D.add: object not an instance of THREE.Object3D.", object );
  202. }
  203. return this;
  204. },
  205. remove: function ( object ) {
  206. if ( arguments.length > 1 ) {
  207. for ( var i = 0; i < arguments.length; i ++ ) {
  208. this.remove( arguments[ i ] );
  209. }
  210. }
  211. var index = this.children.indexOf( object );
  212. if ( index !== - 1 ) {
  213. object.parent = null;
  214. object.dispatchEvent( { type: 'removed' } );
  215. this.children.splice( index, 1 );
  216. }
  217. },
  218. getChildByName: function ( name ) {
  219. console.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' );
  220. return this.getObjectByName( name );
  221. },
  222. getObjectById: function ( id ) {
  223. return this.getObjectByProperty( 'id', id );
  224. },
  225. getObjectByName: function ( name ) {
  226. return this.getObjectByProperty( 'name', name );
  227. },
  228. getObjectByProperty: function ( name, value ) {
  229. if ( this[ name ] === value ) return this;
  230. for ( var i = 0, l = this.children.length; i < l; i ++ ) {
  231. var child = this.children[ i ];
  232. var object = child.getObjectByProperty( name, value );
  233. if ( object !== undefined ) {
  234. return object;
  235. }
  236. }
  237. return undefined;
  238. },
  239. getWorldPosition: function ( optionalTarget ) {
  240. var result = optionalTarget || new THREE.Vector3();
  241. this.updateMatrixWorld( true );
  242. return result.setFromMatrixPosition( this.matrixWorld );
  243. },
  244. getWorldQuaternion: function () {
  245. var position = new THREE.Vector3();
  246. var scale = new THREE.Vector3();
  247. return function ( optionalTarget ) {
  248. var result = optionalTarget || new THREE.Quaternion();
  249. this.updateMatrixWorld( true );
  250. this.matrixWorld.decompose( position, result, scale );
  251. return result;
  252. };
  253. }(),
  254. getWorldRotation: function () {
  255. var quaternion = new THREE.Quaternion();
  256. return function ( optionalTarget ) {
  257. var result = optionalTarget || new THREE.Euler();
  258. this.getWorldQuaternion( quaternion );
  259. return result.setFromQuaternion( quaternion, this.rotation.order, false );
  260. };
  261. }(),
  262. getWorldScale: function () {
  263. var position = new THREE.Vector3();
  264. var quaternion = new THREE.Quaternion();
  265. return function ( optionalTarget ) {
  266. var result = optionalTarget || new THREE.Vector3();
  267. this.updateMatrixWorld( true );
  268. this.matrixWorld.decompose( position, quaternion, result );
  269. return result;
  270. };
  271. }(),
  272. getWorldDirection: function () {
  273. var quaternion = new THREE.Quaternion();
  274. return function ( optionalTarget ) {
  275. var result = optionalTarget || new THREE.Vector3();
  276. this.getWorldQuaternion( quaternion );
  277. return result.set( 0, 0, 1 ).applyQuaternion( quaternion );
  278. };
  279. }(),
  280. raycast: function () {},
  281. traverse: function ( callback ) {
  282. callback( this );
  283. var children = this.children;
  284. for ( var i = 0, l = children.length; i < l; i ++ ) {
  285. children[ i ].traverse( callback );
  286. }
  287. },
  288. traverseVisible: function ( callback ) {
  289. if ( this.visible === false ) return;
  290. callback( this );
  291. var children = this.children;
  292. for ( var i = 0, l = children.length; i < l; i ++ ) {
  293. children[ i ].traverseVisible( callback );
  294. }
  295. },
  296. traverseAncestors: function ( callback ) {
  297. var parent = this.parent;
  298. if ( parent !== null ) {
  299. callback( parent );
  300. parent.traverseAncestors( callback );
  301. }
  302. },
  303. updateMatrix: function () {
  304. this.matrix.compose( this.position, this.quaternion, this.scale );
  305. this.matrixWorldNeedsUpdate = true;
  306. },
  307. updateMatrixWorld: function ( force ) {
  308. if ( this.matrixAutoUpdate === true ) this.updateMatrix();
  309. if ( this.matrixWorldNeedsUpdate === true || force === true ) {
  310. if ( this.parent === null ) {
  311. this.matrixWorld.copy( this.matrix );
  312. } else {
  313. this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
  314. }
  315. this.matrixWorldNeedsUpdate = false;
  316. force = true;
  317. }
  318. // update children
  319. for ( var i = 0, l = this.children.length; i < l; i ++ ) {
  320. this.children[ i ].updateMatrixWorld( force );
  321. }
  322. },
  323. toJSON: function ( meta ) {
  324. var isRootObject = ( meta === undefined );
  325. var output = {};
  326. // meta is a hash used to collect geometries, materials.
  327. // not providing it implies that this is the root object
  328. // being serialized.
  329. if ( isRootObject ) {
  330. // initialize meta obj
  331. meta = {
  332. geometries: {},
  333. materials: {},
  334. textures: {},
  335. images: {}
  336. };
  337. output.metadata = {
  338. version: 4.4,
  339. type: 'Object',
  340. generator: 'Object3D.toJSON'
  341. };
  342. }
  343. // standard Object3D serialization
  344. var object = {};
  345. object.uuid = this.uuid;
  346. object.type = this.type;
  347. if ( this.name !== '' ) object.name = this.name;
  348. if ( JSON.stringify( this.userData ) !== '{}' ) object.userData = this.userData;
  349. if ( this.castShadow === true ) object.castShadow = true;
  350. if ( this.receiveShadow === true ) object.receiveShadow = true;
  351. if ( this.visible === false ) object.visible = false;
  352. object.matrix = this.matrix.toArray();
  353. //
  354. if ( this.geometry !== undefined ) {
  355. if ( meta.geometries[ this.geometry.uuid ] === undefined ) {
  356. meta.geometries[ this.geometry.uuid ] = this.geometry.toJSON( meta );
  357. }
  358. object.geometry = this.geometry.uuid;
  359. }
  360. if ( this.material !== undefined ) {
  361. if ( meta.materials[ this.material.uuid ] === undefined ) {
  362. meta.materials[ this.material.uuid ] = this.material.toJSON( meta );
  363. }
  364. object.material = this.material.uuid;
  365. }
  366. //
  367. if ( this.children.length > 0 ) {
  368. object.children = [];
  369. for ( var i = 0; i < this.children.length; i ++ ) {
  370. object.children.push( this.children[ i ].toJSON( meta ).object );
  371. }
  372. }
  373. if ( isRootObject ) {
  374. var geometries = extractFromCache( meta.geometries );
  375. var materials = extractFromCache( meta.materials );
  376. var textures = extractFromCache( meta.textures );
  377. var images = extractFromCache( meta.images );
  378. if ( geometries.length > 0 ) output.geometries = geometries;
  379. if ( materials.length > 0 ) output.materials = materials;
  380. if ( textures.length > 0 ) output.textures = textures;
  381. if ( images.length > 0 ) output.images = images;
  382. }
  383. output.object = object;
  384. return output;
  385. // extract data from the cache hash
  386. // remove metadata on each item
  387. // and return as array
  388. function extractFromCache ( cache ) {
  389. var values = [];
  390. for ( var key in cache ) {
  391. var data = cache[ key ];
  392. delete data.metadata;
  393. values.push( data );
  394. }
  395. return values;
  396. }
  397. },
  398. clone: function ( recursive ) {
  399. return new this.constructor().copy( this, recursive );
  400. },
  401. copy: function ( source, recursive ) {
  402. if ( recursive === undefined ) recursive = true;
  403. this.name = source.name;
  404. this.up.copy( source.up );
  405. this.position.copy( source.position );
  406. this.quaternion.copy( source.quaternion );
  407. this.scale.copy( source.scale );
  408. this.rotationAutoUpdate = source.rotationAutoUpdate;
  409. this.matrix.copy( source.matrix );
  410. this.matrixWorld.copy( source.matrixWorld );
  411. this.matrixAutoUpdate = source.matrixAutoUpdate;
  412. this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;
  413. this.visible = source.visible;
  414. this.castShadow = source.castShadow;
  415. this.receiveShadow = source.receiveShadow;
  416. this.frustumCulled = source.frustumCulled;
  417. this.renderOrder = source.renderOrder;
  418. this.userData = JSON.parse( JSON.stringify( source.userData ) );
  419. if ( recursive === true ) {
  420. for ( var i = 0; i < source.children.length; i ++ ) {
  421. var child = source.children[ i ];
  422. this.add( child.clone() );
  423. }
  424. }
  425. return this;
  426. }
  427. };
  428. THREE.EventDispatcher.prototype.apply( THREE.Object3D.prototype );
  429. THREE.Object3DIdCount = 0;
粤ICP备19079148号