|
|
|
@ -2,16 +2,22 @@ import * as THREE from 'three' |
|
|
|
import type Viewport from '@/core/engine/Viewport.ts' |
|
|
|
import { Vector3 } from 'three/src/math/Vector3' |
|
|
|
|
|
|
|
/** |
|
|
|
* 点实例管理器 |
|
|
|
*/ |
|
|
|
export default class InstancePointManager { |
|
|
|
private readonly viewport: Viewport |
|
|
|
private readonly instancedMesh: THREE.InstancedMesh |
|
|
|
public readonly viewport: Viewport |
|
|
|
public readonly instancedMesh: THREE.InstancedMesh |
|
|
|
|
|
|
|
private readonly freeIndices: number[] = [] |
|
|
|
private readonly maxInstanceCount: number |
|
|
|
private readonly geometry: THREE.BufferGeometry |
|
|
|
private readonly material: THREE.Material |
|
|
|
private readonly dummy: THREE.Object3D = new THREE.Object3D() |
|
|
|
// itemId -> instanceId
|
|
|
|
private instanceData = new Map<string, PointManageWrap>() |
|
|
|
private __uuidMap = new Map<string, PointManageWrap>() |
|
|
|
// instanceId -> itemId
|
|
|
|
private __indexIdMap = new Map<number, string>() |
|
|
|
|
|
|
|
/** |
|
|
|
* 创建点实例 |
|
|
|
@ -46,7 +52,7 @@ export default class InstancePointManager { |
|
|
|
* @param option 更新选项 |
|
|
|
*/ |
|
|
|
updatePoint(item: ItemJson, option: { position?: Vector3, rotation?: Vector3, scale?: Vector3 } = {}): void { |
|
|
|
const wrap = this.instanceData.get(item.id) |
|
|
|
const wrap = this.__uuidMap.get(item.id) |
|
|
|
if (wrap === undefined) return |
|
|
|
|
|
|
|
wrap.visible = item.v !== false |
|
|
|
@ -78,7 +84,16 @@ export default class InstancePointManager { |
|
|
|
* 获取点实例数据 |
|
|
|
*/ |
|
|
|
getObject3DLike(id: string): PointManageWrap { |
|
|
|
return this.instanceData.get(id) |
|
|
|
return this.__uuidMap.get(id) |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 获取点实例数据 |
|
|
|
*/ |
|
|
|
findByMeshInstanceId(instanceId: number): PointManageWrap { |
|
|
|
const uuid = this.__indexIdMap.get(instanceId) |
|
|
|
if (!uuid) return |
|
|
|
return this.__uuidMap.get(uuid) |
|
|
|
} |
|
|
|
|
|
|
|
syncMeshObject3D(wrap: PointManageWrap) { |
|
|
|
@ -86,7 +101,6 @@ export default class InstancePointManager { |
|
|
|
console.error('InstancePointManager: Invalid meshIndex for wrap', wrap) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
if (!wrap.visible) { |
|
|
|
this.dummy.scale.set(0, 0, 0) |
|
|
|
} else { |
|
|
|
@ -96,7 +110,11 @@ export default class InstancePointManager { |
|
|
|
} |
|
|
|
this.dummy.updateMatrix() |
|
|
|
|
|
|
|
if (!wrap.parent) { |
|
|
|
wrap.parent = this.instancedMesh |
|
|
|
this.__uuidMap.set(wrap.uuid, wrap) |
|
|
|
this.__indexIdMap.set(wrap.meshIndex, wrap.uuid) |
|
|
|
} |
|
|
|
this.instancedMesh.setMatrixAt(wrap.meshIndex, this.dummy.matrix) |
|
|
|
this.instancedMesh.instanceMatrix.needsUpdate = true |
|
|
|
} |
|
|
|
@ -106,7 +124,7 @@ export default class InstancePointManager { |
|
|
|
* @param id 点ID |
|
|
|
*/ |
|
|
|
deletePoint(id: string): void { |
|
|
|
const wrap = this.instanceData.get(id) |
|
|
|
const wrap = this.__uuidMap.get(id) |
|
|
|
if (wrap === undefined) return |
|
|
|
|
|
|
|
// 隐藏实例
|
|
|
|
@ -117,52 +135,24 @@ export default class InstancePointManager { |
|
|
|
|
|
|
|
// 回收索引
|
|
|
|
this.freeIndices.push(wrap.meshIndex) |
|
|
|
this.instanceData.delete(id) |
|
|
|
this.__uuidMap.delete(id) |
|
|
|
this.__indexIdMap.delete(wrap.meshIndex) |
|
|
|
|
|
|
|
wrap.dispose() |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 获取点实例的世界位置 |
|
|
|
* @param id 点ID |
|
|
|
* @param target 目标向量 |
|
|
|
*/ |
|
|
|
getWorldPosition(id: string, target: THREE.Vector3): void { |
|
|
|
const instanceData = this.instanceData.get(id) |
|
|
|
if (instanceData === undefined) return |
|
|
|
|
|
|
|
const matrix = new THREE.Matrix4() |
|
|
|
this.instancedMesh.getMatrixAt(instanceData.meshIndex, matrix) |
|
|
|
target.setFromMatrixPosition(matrix) |
|
|
|
} |
|
|
|
|
|
|
|
// init(viewport: Viewport): void {
|
|
|
|
// this.viewport = viewport
|
|
|
|
//
|
|
|
|
// const geometry = new THREE.PlaneGeometry(0.25, 0.25)
|
|
|
|
// const material = new THREE.MeshBasicMaterial({
|
|
|
|
// color: 0xFFFF99,
|
|
|
|
// transparent: true,
|
|
|
|
// depthWrite: false,
|
|
|
|
// side: THREE.DoubleSide
|
|
|
|
// })
|
|
|
|
//
|
|
|
|
// this.mesh = new THREE.InstancedMesh(geometry, material, this.maxInstances)
|
|
|
|
// this.mesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage)
|
|
|
|
// viewport.scene.add(this.mesh)
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
public static create( |
|
|
|
name: string, |
|
|
|
viewport: Viewport, |
|
|
|
geometry: THREE.BufferGeometry, |
|
|
|
material: THREE.Material, |
|
|
|
maxInstances: number = 1000 |
|
|
|
): InstancePointManager { |
|
|
|
return new InstancePointManager(viewport, geometry, material, maxInstances) |
|
|
|
return new InstancePointManager(name, viewport, geometry, material, maxInstances) |
|
|
|
} |
|
|
|
|
|
|
|
constructor( |
|
|
|
private constructor( |
|
|
|
name: string, |
|
|
|
viewport: Viewport, |
|
|
|
geometry: THREE.BufferGeometry, |
|
|
|
material: THREE.Material, |
|
|
|
@ -175,7 +165,13 @@ export default class InstancePointManager { |
|
|
|
|
|
|
|
this.instancedMesh = new THREE.InstancedMesh(geometry, material, maxInstances) |
|
|
|
this.instancedMesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage) |
|
|
|
this.instancedMesh.name = name |
|
|
|
console.log('InstancePointManager: [' + name + '] created with maxInstances:', maxInstances) |
|
|
|
viewport.scene.add(this.instancedMesh) |
|
|
|
this.viewport.entityManager._selectableObjects.push(this.instancedMesh) |
|
|
|
this.viewport.entityManager._draggableObjects.push(this.instancedMesh) |
|
|
|
this.instancedMesh.userData.t = name |
|
|
|
this.instancedMesh.userData.entityId = 'InstancePointManager' |
|
|
|
|
|
|
|
this.dummy.scale.set(0, 0, 0) |
|
|
|
for (let i = 0; i < maxInstances; i++) { |
|
|
|
@ -200,7 +196,8 @@ export default class InstancePointManager { |
|
|
|
} |
|
|
|
|
|
|
|
this.instancedMesh.dispose() |
|
|
|
this.instanceData.clear() |
|
|
|
this.__uuidMap.clear() |
|
|
|
this.__indexIdMap.clear() |
|
|
|
this.freeIndices.length = 0 |
|
|
|
} |
|
|
|
} |
|
|
|
@ -219,6 +216,9 @@ export class PointManageWrap { |
|
|
|
//@ts-ignore
|
|
|
|
userData: UserData = {} |
|
|
|
|
|
|
|
updateWorldMatrix() { |
|
|
|
} |
|
|
|
|
|
|
|
get type() { |
|
|
|
return 'PointManageWrap' |
|
|
|
} |
|
|
|
@ -238,4 +238,14 @@ export class PointManageWrap { |
|
|
|
this.parent = null |
|
|
|
this.meshIndex = -1 |
|
|
|
} |
|
|
|
|
|
|
|
createBox3(): THREE.Box3 { |
|
|
|
const instancedMesh = this.manager.instancedMesh |
|
|
|
const matrix = new THREE.Matrix4() |
|
|
|
instancedMesh.getMatrixAt(this.meshIndex, matrix) |
|
|
|
// 创建包围盒并应用矩阵
|
|
|
|
const geometry = instancedMesh.geometry |
|
|
|
const localBox = new THREE.Box3().setFromBufferAttribute(geometry.attributes.position) |
|
|
|
return localBox.clone().applyMatrix4(matrix) |
|
|
|
} |
|
|
|
} |
|
|
|
|