1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024 |
- import { Quaternion } from '../math/Quaternion.js';
- import { Vector3 } from '../math/Vector3.js';
- import { Matrix4 } from '../math/Matrix4.js';
- import { EventDispatcher } from './EventDispatcher.js';
- import { Euler } from '../math/Euler.js';
- import { Layers } from './Layers.js';
- import { Matrix3 } from '../math/Matrix3.js';
- import * as MathUtils from '../math/MathUtils.js';
- let _object3DId = 0;
- const _v1 = /*@__PURE__*/ new Vector3();
- const _q1 = /*@__PURE__*/ new Quaternion();
- const _m1 = /*@__PURE__*/ new Matrix4();
- const _target = /*@__PURE__*/ new Vector3();
- const _position = /*@__PURE__*/ new Vector3();
- const _scale = /*@__PURE__*/ new Vector3();
- const _quaternion = /*@__PURE__*/ new Quaternion();
- const _xAxis = /*@__PURE__*/ new Vector3( 1, 0, 0 );
- const _yAxis = /*@__PURE__*/ new Vector3( 0, 1, 0 );
- const _zAxis = /*@__PURE__*/ new Vector3( 0, 0, 1 );
- const _addedEvent = { type: 'added' };
- const _removedEvent = { type: 'removed' };
- const _childaddedEvent = { type: 'childadded', child: null };
- const _childremovedEvent = { type: 'childremoved', child: null };
- class Object3D extends EventDispatcher {
- constructor() {
- super();
- this.isObject3D = true;
- Object.defineProperty( this, 'id', { value: _object3DId ++ } );
- this.uuid = MathUtils.generateUUID();
- this.name = '';
- this.type = 'Object3D';
- this.parent = null;
- this.children = [];
- this.up = Object3D.DEFAULT_UP.clone();
- const position = new Vector3();
- const rotation = new Euler();
- const quaternion = new Quaternion();
- const scale = new Vector3( 1, 1, 1 );
- function onRotationChange() {
- quaternion.setFromEuler( rotation, false );
- }
- function onQuaternionChange() {
- rotation.setFromQuaternion( quaternion, undefined, false );
- }
- rotation._onChange( onRotationChange );
- quaternion._onChange( onQuaternionChange );
- Object.defineProperties( this, {
- position: {
- configurable: true,
- enumerable: true,
- value: position
- },
- rotation: {
- configurable: true,
- enumerable: true,
- value: rotation
- },
- quaternion: {
- configurable: true,
- enumerable: true,
- value: quaternion
- },
- scale: {
- configurable: true,
- enumerable: true,
- value: scale
- },
- modelViewMatrix: {
- value: new Matrix4()
- },
- normalMatrix: {
- value: new Matrix3()
- }
- } );
- this.matrix = new Matrix4();
- this.matrixWorld = new Matrix4();
- this.matrixAutoUpdate = Object3D.DEFAULT_MATRIX_AUTO_UPDATE;
- this.matrixWorldAutoUpdate = Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE; // checked by the renderer
- this.matrixWorldNeedsUpdate = false;
- this.layers = new Layers();
- this.visible = true;
- this.castShadow = false;
- this.receiveShadow = false;
- this.frustumCulled = true;
- this.renderOrder = 0;
- this.animations = [];
- this.userData = {};
- }
- onBeforeShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {}
- onAfterShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {}
- onBeforeRender( /* renderer, scene, camera, geometry, material, group */ ) {}
- onAfterRender( /* renderer, scene, camera, geometry, material, group */ ) {}
- applyMatrix4( matrix ) {
- if ( this.matrixAutoUpdate ) this.updateMatrix();
- this.matrix.premultiply( matrix );
- this.matrix.decompose( this.position, this.quaternion, this.scale );
- }
- applyQuaternion( q ) {
- this.quaternion.premultiply( q );
- return this;
- }
- setRotationFromAxisAngle( axis, angle ) {
- // assumes axis is normalized
- this.quaternion.setFromAxisAngle( axis, angle );
- }
- setRotationFromEuler( euler ) {
- this.quaternion.setFromEuler( euler, true );
- }
- setRotationFromMatrix( m ) {
- // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
- this.quaternion.setFromRotationMatrix( m );
- }
- setRotationFromQuaternion( q ) {
- // assumes q is normalized
- this.quaternion.copy( q );
- }
- rotateOnAxis( axis, angle ) {
- // rotate object on axis in object space
- // axis is assumed to be normalized
- _q1.setFromAxisAngle( axis, angle );
- this.quaternion.multiply( _q1 );
- return this;
- }
- rotateOnWorldAxis( axis, angle ) {
- // rotate object on axis in world space
- // axis is assumed to be normalized
- // method assumes no rotated parent
- _q1.setFromAxisAngle( axis, angle );
- this.quaternion.premultiply( _q1 );
- return this;
- }
- rotateX( angle ) {
- return this.rotateOnAxis( _xAxis, angle );
- }
- rotateY( angle ) {
- return this.rotateOnAxis( _yAxis, angle );
- }
- rotateZ( angle ) {
- return this.rotateOnAxis( _zAxis, angle );
- }
- translateOnAxis( axis, distance ) {
- // translate object by distance along axis in object space
- // axis is assumed to be normalized
- _v1.copy( axis ).applyQuaternion( this.quaternion );
- this.position.add( _v1.multiplyScalar( distance ) );
- return this;
- }
- translateX( distance ) {
- return this.translateOnAxis( _xAxis, distance );
- }
- translateY( distance ) {
- return this.translateOnAxis( _yAxis, distance );
- }
- translateZ( distance ) {
- return this.translateOnAxis( _zAxis, distance );
- }
- localToWorld( vector ) {
- this.updateWorldMatrix( true, false );
- return vector.applyMatrix4( this.matrixWorld );
- }
- worldToLocal( vector ) {
- this.updateWorldMatrix( true, false );
- return vector.applyMatrix4( _m1.copy( this.matrixWorld ).invert() );
- }
- lookAt( x, y, z ) {
- // This method does not support objects having non-uniformly-scaled parent(s)
- if ( x.isVector3 ) {
- _target.copy( x );
- } else {
- _target.set( x, y, z );
- }
- const parent = this.parent;
- this.updateWorldMatrix( true, false );
- _position.setFromMatrixPosition( this.matrixWorld );
- if ( this.isCamera || this.isLight ) {
- _m1.lookAt( _position, _target, this.up );
- } else {
- _m1.lookAt( _target, _position, this.up );
- }
- this.quaternion.setFromRotationMatrix( _m1 );
- if ( parent ) {
- _m1.extractRotation( parent.matrixWorld );
- _q1.setFromRotationMatrix( _m1 );
- this.quaternion.premultiply( _q1.invert() );
- }
- }
- add( object ) {
- if ( arguments.length > 1 ) {
- for ( let i = 0; i < arguments.length; i ++ ) {
- this.add( arguments[ i ] );
- }
- return this;
- }
- if ( object === this ) {
- console.error( 'THREE.Object3D.add: object can\'t be added as a child of itself.', object );
- return this;
- }
- if ( object && object.isObject3D ) {
- object.removeFromParent();
- object.parent = this;
- this.children.push( object );
- object.dispatchEvent( _addedEvent );
- _childaddedEvent.child = object;
- this.dispatchEvent( _childaddedEvent );
- _childaddedEvent.child = null;
- } else {
- console.error( 'THREE.Object3D.add: object not an instance of THREE.Object3D.', object );
- }
- return this;
- }
- remove( object ) {
- if ( arguments.length > 1 ) {
- for ( let i = 0; i < arguments.length; i ++ ) {
- this.remove( arguments[ i ] );
- }
- return this;
- }
- const index = this.children.indexOf( object );
- if ( index !== - 1 ) {
- object.parent = null;
- this.children.splice( index, 1 );
- object.dispatchEvent( _removedEvent );
- _childremovedEvent.child = object;
- this.dispatchEvent( _childremovedEvent );
- _childremovedEvent.child = null;
- }
- return this;
- }
- removeFromParent() {
- const parent = this.parent;
- if ( parent !== null ) {
- parent.remove( this );
- }
- return this;
- }
- clear() {
- return this.remove( ... this.children );
- }
- attach( object ) {
- // adds object as a child of this, while maintaining the object's world transform
- // Note: This method does not support scene graphs having non-uniformly-scaled nodes(s)
- this.updateWorldMatrix( true, false );
- _m1.copy( this.matrixWorld ).invert();
- if ( object.parent !== null ) {
- object.parent.updateWorldMatrix( true, false );
- _m1.multiply( object.parent.matrixWorld );
- }
- object.applyMatrix4( _m1 );
- object.removeFromParent();
- object.parent = this;
- this.children.push( object );
- object.updateWorldMatrix( false, true );
- object.dispatchEvent( _addedEvent );
- _childaddedEvent.child = object;
- this.dispatchEvent( _childaddedEvent );
- _childaddedEvent.child = null;
- return this;
- }
- getObjectById( id ) {
- return this.getObjectByProperty( 'id', id );
- }
- getObjectByName( name ) {
- return this.getObjectByProperty( 'name', name );
- }
- getObjectByProperty( name, value ) {
- if ( this[ name ] === value ) return this;
- for ( let i = 0, l = this.children.length; i < l; i ++ ) {
- const child = this.children[ i ];
- const object = child.getObjectByProperty( name, value );
- if ( object !== undefined ) {
- return object;
- }
- }
- return undefined;
- }
- getObjectsByProperty( name, value, result = [] ) {
- if ( this[ name ] === value ) result.push( this );
- const children = this.children;
- for ( let i = 0, l = children.length; i < l; i ++ ) {
- children[ i ].getObjectsByProperty( name, value, result );
- }
- return result;
- }
- getWorldPosition( target ) {
- this.updateWorldMatrix( true, false );
- return target.setFromMatrixPosition( this.matrixWorld );
- }
- getWorldQuaternion( target ) {
- this.updateWorldMatrix( true, false );
- this.matrixWorld.decompose( _position, target, _scale );
- return target;
- }
- getWorldScale( target ) {
- this.updateWorldMatrix( true, false );
- this.matrixWorld.decompose( _position, _quaternion, target );
- return target;
- }
- getWorldDirection( target ) {
- this.updateWorldMatrix( true, false );
- const e = this.matrixWorld.elements;
- return target.set( e[ 8 ], e[ 9 ], e[ 10 ] ).normalize();
- }
- raycast( /* raycaster, intersects */ ) {}
- traverse( callback ) {
- callback( this );
- const children = this.children;
- for ( let i = 0, l = children.length; i < l; i ++ ) {
- children[ i ].traverse( callback );
- }
- }
- traverseVisible( callback ) {
- if ( this.visible === false ) return;
- callback( this );
- const children = this.children;
- for ( let i = 0, l = children.length; i < l; i ++ ) {
- children[ i ].traverseVisible( callback );
- }
- }
- traverseAncestors( callback ) {
- const parent = this.parent;
- if ( parent !== null ) {
- callback( parent );
- parent.traverseAncestors( callback );
- }
- }
- updateMatrix() {
- this.matrix.compose( this.position, this.quaternion, this.scale );
- this.matrixWorldNeedsUpdate = true;
- }
- updateMatrixWorld( force ) {
- if ( this.matrixAutoUpdate ) this.updateMatrix();
- if ( this.matrixWorldNeedsUpdate || force ) {
- if ( this.matrixWorldAutoUpdate === true ) {
- if ( this.parent === null ) {
- this.matrixWorld.copy( this.matrix );
- } else {
- this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
- }
- }
- this.matrixWorldNeedsUpdate = false;
- force = true;
- }
- // make sure descendants are updated if required
- const children = this.children;
- for ( let i = 0, l = children.length; i < l; i ++ ) {
- const child = children[ i ];
- child.updateMatrixWorld( force );
- }
- }
- updateWorldMatrix( updateParents, updateChildren ) {
- const parent = this.parent;
- if ( updateParents === true && parent !== null ) {
- parent.updateWorldMatrix( true, false );
- }
- if ( this.matrixAutoUpdate ) this.updateMatrix();
- if ( this.matrixWorldAutoUpdate === true ) {
- if ( this.parent === null ) {
- this.matrixWorld.copy( this.matrix );
- } else {
- this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
- }
- }
- // make sure descendants are updated
- if ( updateChildren === true ) {
- const children = this.children;
- for ( let i = 0, l = children.length; i < l; i ++ ) {
- const child = children[ i ];
- child.updateWorldMatrix( false, true );
- }
- }
- }
- toJSON( meta ) {
- // meta is a string when called from JSON.stringify
- const isRootObject = ( meta === undefined || typeof meta === 'string' );
- const output = {};
- // meta is a hash used to collect geometries, materials.
- // not providing it implies that this is the root object
- // being serialized.
- if ( isRootObject ) {
- // initialize meta obj
- meta = {
- geometries: {},
- materials: {},
- textures: {},
- images: {},
- shapes: {},
- skeletons: {},
- animations: {},
- nodes: {}
- };
- output.metadata = {
- version: 4.6,
- type: 'Object',
- generator: 'Object3D.toJSON'
- };
- }
- // standard Object3D serialization
- const object = {};
- object.uuid = this.uuid;
- object.type = this.type;
- if ( this.name !== '' ) object.name = this.name;
- if ( this.castShadow === true ) object.castShadow = true;
- if ( this.receiveShadow === true ) object.receiveShadow = true;
- if ( this.visible === false ) object.visible = false;
- if ( this.frustumCulled === false ) object.frustumCulled = false;
- if ( this.renderOrder !== 0 ) object.renderOrder = this.renderOrder;
- if ( Object.keys( this.userData ).length > 0 ) object.userData = this.userData;
- object.layers = this.layers.mask;
- object.matrix = this.matrix.toArray();
- object.up = this.up.toArray();
- if ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false;
- // object specific properties
- if ( this.isInstancedMesh ) {
- object.type = 'InstancedMesh';
- object.count = this.count;
- object.instanceMatrix = this.instanceMatrix.toJSON();
- if ( this.instanceColor !== null ) object.instanceColor = this.instanceColor.toJSON();
- }
- if ( this.isBatchedMesh ) {
- object.type = 'BatchedMesh';
- object.perObjectFrustumCulled = this.perObjectFrustumCulled;
- object.sortObjects = this.sortObjects;
- object.drawRanges = this._drawRanges;
- object.reservedRanges = this._reservedRanges;
- object.visibility = this._visibility;
- object.active = this._active;
- object.bounds = this._bounds.map( bound => ( {
- boxInitialized: bound.boxInitialized,
- boxMin: bound.box.min.toArray(),
- boxMax: bound.box.max.toArray(),
- sphereInitialized: bound.sphereInitialized,
- sphereRadius: bound.sphere.radius,
- sphereCenter: bound.sphere.center.toArray()
- } ) );
- object.maxGeometryCount = this._maxGeometryCount;
- object.maxVertexCount = this._maxVertexCount;
- object.maxIndexCount = this._maxIndexCount;
- object.geometryInitialized = this._geometryInitialized;
- object.geometryCount = this._geometryCount;
- object.matricesTexture = this._matricesTexture.toJSON( meta );
- if ( this._colorsTexture !== null ) object.colorsTexture = this._colorsTexture.toJSON( meta );
- if ( this.boundingSphere !== null ) {
- object.boundingSphere = {
- center: object.boundingSphere.center.toArray(),
- radius: object.boundingSphere.radius
- };
- }
- if ( this.boundingBox !== null ) {
- object.boundingBox = {
- min: object.boundingBox.min.toArray(),
- max: object.boundingBox.max.toArray()
- };
- }
- }
- //
- function serialize( library, element ) {
- if ( library[ element.uuid ] === undefined ) {
- library[ element.uuid ] = element.toJSON( meta );
- }
- return element.uuid;
- }
- if ( this.isScene ) {
- if ( this.background ) {
- if ( this.background.isColor ) {
- object.background = this.background.toJSON();
- } else if ( this.background.isTexture ) {
- object.background = this.background.toJSON( meta ).uuid;
- }
- }
- if ( this.environment && this.environment.isTexture && this.environment.isRenderTargetTexture !== true ) {
- object.environment = this.environment.toJSON( meta ).uuid;
- }
- } else if ( this.isMesh || this.isLine || this.isPoints ) {
- object.geometry = serialize( meta.geometries, this.geometry );
- const parameters = this.geometry.parameters;
- if ( parameters !== undefined && parameters.shapes !== undefined ) {
- const shapes = parameters.shapes;
- if ( Array.isArray( shapes ) ) {
- for ( let i = 0, l = shapes.length; i < l; i ++ ) {
- const shape = shapes[ i ];
- serialize( meta.shapes, shape );
- }
- } else {
- serialize( meta.shapes, shapes );
- }
- }
- }
- if ( this.isSkinnedMesh ) {
- object.bindMode = this.bindMode;
- object.bindMatrix = this.bindMatrix.toArray();
- if ( this.skeleton !== undefined ) {
- serialize( meta.skeletons, this.skeleton );
- object.skeleton = this.skeleton.uuid;
- }
- }
- if ( this.material !== undefined ) {
- if ( Array.isArray( this.material ) ) {
- const uuids = [];
- for ( let i = 0, l = this.material.length; i < l; i ++ ) {
- uuids.push( serialize( meta.materials, this.material[ i ] ) );
- }
- object.material = uuids;
- } else {
- object.material = serialize( meta.materials, this.material );
- }
- }
- //
- if ( this.children.length > 0 ) {
- object.children = [];
- for ( let i = 0; i < this.children.length; i ++ ) {
- object.children.push( this.children[ i ].toJSON( meta ).object );
- }
- }
- //
- if ( this.animations.length > 0 ) {
- object.animations = [];
- for ( let i = 0; i < this.animations.length; i ++ ) {
- const animation = this.animations[ i ];
- object.animations.push( serialize( meta.animations, animation ) );
- }
- }
- if ( isRootObject ) {
- const geometries = extractFromCache( meta.geometries );
- const materials = extractFromCache( meta.materials );
- const textures = extractFromCache( meta.textures );
- const images = extractFromCache( meta.images );
- const shapes = extractFromCache( meta.shapes );
- const skeletons = extractFromCache( meta.skeletons );
- const animations = extractFromCache( meta.animations );
- const nodes = extractFromCache( meta.nodes );
- if ( geometries.length > 0 ) output.geometries = geometries;
- if ( materials.length > 0 ) output.materials = materials;
- if ( textures.length > 0 ) output.textures = textures;
- if ( images.length > 0 ) output.images = images;
- if ( shapes.length > 0 ) output.shapes = shapes;
- if ( skeletons.length > 0 ) output.skeletons = skeletons;
- if ( animations.length > 0 ) output.animations = animations;
- if ( nodes.length > 0 ) output.nodes = nodes;
- }
- output.object = object;
- return output;
- // extract data from the cache hash
- // remove metadata on each item
- // and return as array
- function extractFromCache( cache ) {
- const values = [];
- for ( const key in cache ) {
- const data = cache[ key ];
- delete data.metadata;
- values.push( data );
- }
- return values;
- }
- }
- clone( recursive ) {
- return new this.constructor().copy( this, recursive );
- }
- copy( source, recursive = true ) {
- this.name = source.name;
- this.up.copy( source.up );
- this.position.copy( source.position );
- this.rotation.order = source.rotation.order;
- this.quaternion.copy( source.quaternion );
- this.scale.copy( source.scale );
- this.matrix.copy( source.matrix );
- this.matrixWorld.copy( source.matrixWorld );
- this.matrixAutoUpdate = source.matrixAutoUpdate;
- this.matrixWorldAutoUpdate = source.matrixWorldAutoUpdate;
- this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;
- this.layers.mask = source.layers.mask;
- this.visible = source.visible;
- this.castShadow = source.castShadow;
- this.receiveShadow = source.receiveShadow;
- this.frustumCulled = source.frustumCulled;
- this.renderOrder = source.renderOrder;
- this.animations = source.animations.slice();
- this.userData = JSON.parse( JSON.stringify( source.userData ) );
- if ( recursive === true ) {
- for ( let i = 0; i < source.children.length; i ++ ) {
- const child = source.children[ i ];
- this.add( child.clone() );
- }
- }
- return this;
- }
- }
- Object3D.DEFAULT_UP = /*@__PURE__*/ new Vector3( 0, 1, 0 );
- Object3D.DEFAULT_MATRIX_AUTO_UPDATE = true;
- Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE = true;
- export { Object3D };
|