feat(All):Initial

This commit is contained in:
2025-10-04 23:36:07 +08:00
commit 2b4e5d2668
1321 changed files with 415958 additions and 0 deletions
+130
View File
@@ -0,0 +1,130 @@
/**
* 模型爆炸展开
*/
import * as THREE from 'three';
import {useDispatchSignal} from "@/hooks";
interface IModelExplodeData {
// 爆炸方向
worldDir: THREE.Vector3;
// 爆炸距离:mesh中心点到爆炸中心的距离
worldDistance:THREE.Vector3;
// 原始坐标
originPosition:THREE.Vector3;
// mesh中心
meshCenter:THREE.Vector3;
// 爆炸中心
explodeCenter:THREE.Vector3;
}
class ModelExplode{
// 模型爆炸的展开数据
meshExplodeData = new Map<string,Map<string,IModelExplodeData>>();
// 已执行模型爆炸未还原的模型
unrestoredModel:THREE.Object3D[] = [];
constructor() {
}
/**
* 计算模型爆炸的展开数据
*/
computedExplodeData(model:THREE.Object3D):void{
if(!model) return;
// 计算模型中心
const modelBox = new THREE.Box3();
modelBox.setFromObject(model);
const explodeCenter = this.getWorldCenterPosition(modelBox);
const meshBox = new THREE.Box3();
const dataMap:Map<string,IModelExplodeData> = new Map();
model.traverse((child) => {
if(!child || !child.isMesh || child.isLine || child.isSprite) return;
meshBox.setFromObject(child);
const meshCenter = this.getWorldCenterPosition(meshBox);
const worldDistance = new THREE.Vector3().subVectors(meshCenter,explodeCenter)
const meshExplodeData:IModelExplodeData = {
worldDir: worldDistance.clone().normalize(),
worldDistance:worldDistance,
originPosition:child.getWorldPosition(new THREE.Vector3()),
meshCenter:meshCenter.clone(),
explodeCenter:explodeCenter.clone(),
}
dataMap.set(child.uuid,meshExplodeData);
})
this.meshExplodeData.set(model.uuid,dataMap);
}
getWorldCenterPosition(box:THREE.Box3,scalar = 0.5){
return new THREE.Vector3().addVectors(box.max,box.min).multiplyScalar(scalar);
}
explodeModel(model:THREE.Object3D,scalar:number = 0.5){
if(!this.meshExplodeData.has(model.uuid)){
this.computedExplodeData(model);
}
const dataMap = this.meshExplodeData.get(model.uuid);
if(!dataMap) return;
model.traverse((child) => {
if(!dataMap.has(child.uuid)) return;
const data = dataMap.get(child.uuid);
if(!data) return;
const distance = data.worldDir.clone().multiplyScalar(data.worldDistance.length() * scalar);
const offset = new THREE.Vector3().subVectors(data.meshCenter,data.originPosition);
const center = data.explodeCenter;
const newPosition = new THREE.Vector3().copy(center).add(distance).sub(offset);
const localPosition = child.parent?.worldToLocal(newPosition);
if(localPosition){
child.position.copy(localPosition);
}
})
useDispatchSignal("sceneGraphChanged");
this.unrestoredModel.push(model);
}
// 还原
restore(){
this.unrestoredModel.forEach(model=>{
const dataMap = this.meshExplodeData.get(model.uuid);
if(!dataMap) return;
model.traverse((child) => {
if(!dataMap.has(child.uuid)) return;
const data = dataMap.get(child.uuid);
if(!data) return;
const _originPosition = child.parent?.worldToLocal(data.originPosition);
if(_originPosition){
child.position.copy(_originPosition);
}
})
useDispatchSignal("sceneGraphChanged");
})
this.unrestoredModel = [];
this.clear();
}
clear(){
this.meshExplodeData.clear();
}
}
export {ModelExplode};