You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
215 lines
3.1 KiB
JavaScript
215 lines
3.1 KiB
JavaScript
import { Vector3 } from '../math/Vector3.js';
|
|
import { Object3D } from '../core/Object3D.js';
|
|
|
|
const _v1 = /*@__PURE__*/ new Vector3();
|
|
const _v2 = /*@__PURE__*/ new Vector3();
|
|
|
|
class LOD extends Object3D {
|
|
|
|
constructor() {
|
|
|
|
super();
|
|
|
|
this._currentLevel = 0;
|
|
|
|
this.type = 'LOD';
|
|
|
|
Object.defineProperties( this, {
|
|
levels: {
|
|
enumerable: true,
|
|
value: []
|
|
},
|
|
isLOD: {
|
|
value: true,
|
|
}
|
|
} );
|
|
|
|
this.autoUpdate = true;
|
|
|
|
}
|
|
|
|
copy( source ) {
|
|
|
|
super.copy( source, false );
|
|
|
|
const levels = source.levels;
|
|
|
|
for ( let i = 0, l = levels.length; i < l; i ++ ) {
|
|
|
|
const level = levels[ i ];
|
|
|
|
this.addLevel( level.object.clone(), level.distance, level.hysteresis );
|
|
|
|
}
|
|
|
|
this.autoUpdate = source.autoUpdate;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
addLevel( object, distance = 0, hysteresis = 0 ) {
|
|
|
|
distance = Math.abs( distance );
|
|
|
|
const levels = this.levels;
|
|
|
|
let l;
|
|
|
|
for ( l = 0; l < levels.length; l ++ ) {
|
|
|
|
if ( distance < levels[ l ].distance ) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
levels.splice( l, 0, { distance: distance, hysteresis: hysteresis, object: object } );
|
|
|
|
this.add( object );
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
getCurrentLevel() {
|
|
|
|
return this._currentLevel;
|
|
|
|
}
|
|
|
|
|
|
|
|
getObjectForDistance( distance ) {
|
|
|
|
const levels = this.levels;
|
|
|
|
if ( levels.length > 0 ) {
|
|
|
|
let i, l;
|
|
|
|
for ( i = 1, l = levels.length; i < l; i ++ ) {
|
|
|
|
let levelDistance = levels[ i ].distance;
|
|
|
|
if ( levels[ i ].object.visible ) {
|
|
|
|
levelDistance -= levelDistance * levels[ i ].hysteresis;
|
|
|
|
}
|
|
|
|
if ( distance < levelDistance ) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return levels[ i - 1 ].object;
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
raycast( raycaster, intersects ) {
|
|
|
|
const levels = this.levels;
|
|
|
|
if ( levels.length > 0 ) {
|
|
|
|
_v1.setFromMatrixPosition( this.matrixWorld );
|
|
|
|
const distance = raycaster.ray.origin.distanceTo( _v1 );
|
|
|
|
this.getObjectForDistance( distance ).raycast( raycaster, intersects );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
update( camera ) {
|
|
|
|
const levels = this.levels;
|
|
|
|
if ( levels.length > 1 ) {
|
|
|
|
_v1.setFromMatrixPosition( camera.matrixWorld );
|
|
_v2.setFromMatrixPosition( this.matrixWorld );
|
|
|
|
const distance = _v1.distanceTo( _v2 ) / camera.zoom;
|
|
|
|
levels[ 0 ].object.visible = true;
|
|
|
|
let i, l;
|
|
|
|
for ( i = 1, l = levels.length; i < l; i ++ ) {
|
|
|
|
let levelDistance = levels[ i ].distance;
|
|
|
|
if ( levels[ i ].object.visible ) {
|
|
|
|
levelDistance -= levelDistance * levels[ i ].hysteresis;
|
|
|
|
}
|
|
|
|
if ( distance >= levelDistance ) {
|
|
|
|
levels[ i - 1 ].object.visible = false;
|
|
levels[ i ].object.visible = true;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this._currentLevel = i - 1;
|
|
|
|
for ( ; i < l; i ++ ) {
|
|
|
|
levels[ i ].object.visible = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
toJSON( meta ) {
|
|
|
|
const data = super.toJSON( meta );
|
|
|
|
if ( this.autoUpdate === false ) data.object.autoUpdate = false;
|
|
|
|
data.object.levels = [];
|
|
|
|
const levels = this.levels;
|
|
|
|
for ( let i = 0, l = levels.length; i < l; i ++ ) {
|
|
|
|
const level = levels[ i ];
|
|
|
|
data.object.levels.push( {
|
|
object: level.object.uuid,
|
|
distance: level.distance,
|
|
hysteresis: level.hysteresis
|
|
} );
|
|
|
|
}
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
export { LOD };
|