feat: add main feature module selection
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
import * as THREE from "three";
|
||||
|
||||
interface ExplodedPart {
|
||||
object: THREE.Object3D;
|
||||
originalPosition: THREE.Vector3;
|
||||
targetPosition: THREE.Vector3;
|
||||
}
|
||||
|
||||
interface ExplodedModelOptions {
|
||||
distance?: number;
|
||||
speed?: number;
|
||||
}
|
||||
|
||||
const _center = new THREE.Vector3();
|
||||
const _direction = new THREE.Vector3();
|
||||
|
||||
export class ExplodedModel {
|
||||
private readonly parts: ExplodedPart[] = [];
|
||||
private readonly distance: number;
|
||||
private readonly speed: number;
|
||||
private progress = 0;
|
||||
private targetProgress = 0;
|
||||
|
||||
constructor(model: THREE.Object3D, options: ExplodedModelOptions = {}) {
|
||||
this.distance = options.distance ?? 1.2;
|
||||
this.speed = options.speed ?? 6;
|
||||
this.parts = this.createParts(model);
|
||||
}
|
||||
|
||||
setSplit(split: boolean): void {
|
||||
this.targetProgress = split ? 1 : 0;
|
||||
}
|
||||
|
||||
update(delta: number): void {
|
||||
const diff = this.targetProgress - this.progress;
|
||||
if (Math.abs(diff) < 0.001) {
|
||||
this.progress = this.targetProgress;
|
||||
} else {
|
||||
this.progress += diff * Math.min(delta * this.speed, 1);
|
||||
}
|
||||
|
||||
this.parts.forEach((part) => {
|
||||
part.object.position.lerpVectors(
|
||||
part.originalPosition,
|
||||
part.targetPosition,
|
||||
this.progress,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private createParts(model: THREE.Object3D): ExplodedPart[] {
|
||||
const root = model.children.length === 1 ? model.children[0] : model;
|
||||
const directChildren = root.children.filter((child) => hasMesh(child));
|
||||
const sourceObjects =
|
||||
directChildren.length > 1 ? directChildren : getMeshes(root);
|
||||
|
||||
if (sourceObjects.length === 0) return [];
|
||||
|
||||
_center.set(0, 0, 0);
|
||||
sourceObjects.forEach((object) => _center.add(object.position));
|
||||
_center.divideScalar(sourceObjects.length);
|
||||
|
||||
return sourceObjects.map((object, index) => {
|
||||
const originalPosition = object.position.clone();
|
||||
_direction.subVectors(originalPosition, _center);
|
||||
|
||||
if (_direction.lengthSq() < 0.0001) {
|
||||
const angle = (index / sourceObjects.length) * Math.PI * 2;
|
||||
_direction.set(Math.cos(angle), 0.25, Math.sin(angle));
|
||||
}
|
||||
|
||||
_direction.normalize();
|
||||
|
||||
return {
|
||||
object,
|
||||
originalPosition,
|
||||
targetPosition: originalPosition
|
||||
.clone()
|
||||
.addScaledVector(_direction, this.distance),
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function hasMesh(object: THREE.Object3D): boolean {
|
||||
let found = false;
|
||||
object.traverse((child) => {
|
||||
if (child instanceof THREE.Mesh) {
|
||||
found = true;
|
||||
}
|
||||
});
|
||||
return found;
|
||||
}
|
||||
|
||||
function getMeshes(object: THREE.Object3D): THREE.Object3D[] {
|
||||
const meshes: THREE.Object3D[] = [];
|
||||
object.traverse((child) => {
|
||||
if (child instanceof THREE.Mesh) {
|
||||
meshes.push(child);
|
||||
}
|
||||
});
|
||||
return meshes;
|
||||
}
|
||||
Reference in New Issue
Block a user