import * as THREE from 'three' import type Viewport from '@/core/engine/Viewport.ts' import InstanceMeshBlock from '@/core/manager/InstanceMeshBlock.ts' import { PointManageWrap } from '@/core/manager/InstancePointManager.ts' export default class InstanceMeshManager { private __uuidMap = new Map() public readonly name: string public readonly viewport: Viewport public readonly allowSelect: boolean public readonly allowDrag: boolean public readonly blockCapacity: number public readonly blocks: InstanceMeshBlock[] = [] private readonly geometry: THREE.BufferGeometry private readonly material: THREE.Material private readonly dummy: THREE.Object3D = new THREE.Object3D() constructor(name: string, viewport: Viewport, geometry: THREE.BufferGeometry, material: THREE.Material, allowSelect: boolean, allowDrag: boolean, blockCapacity: number = 1000) { this.name = name this.viewport = viewport this.allowSelect = allowSelect this.allowDrag = allowDrag this.geometry = geometry this.material = material this.blockCapacity = blockCapacity } /** * 获取点实例数据 */ findByMeshInstanceId(blockIndex: number, instanceId: number): InstanceMeshWrap { if (!this.blocks[blockIndex]) { console.error('InstancePointManager: Invalid blockIndex', blockIndex) return null } const uuid = this.blocks[blockIndex].__indexIdMap.get(instanceId) if (!uuid) return return this.__uuidMap.get(uuid) } create(entityId: string): InstanceMeshWrap { let meshIndex = -1 let blockIndex = -1 for (const block of this.blocks) { meshIndex = block.getFreeMeshIndex() if (meshIndex >= 0) { blockIndex = block.blockIndex break } } // 所有 block 都没有空闲索引,创建新的 block if (meshIndex < 0) { const block = this.createBlock() meshIndex = block.getFreeMeshIndex() blockIndex = block.blockIndex } if (meshIndex < 0) { system.showErrorDialog('InstancePointManager: No free index available after creating new block') return null } return new InstanceMeshWrap(entityId, this, blockIndex, meshIndex) } delete(wrapOrId: InstanceMeshWrap | string) { let wrap: InstanceMeshWrap if (typeof wrapOrId === 'string') { wrap = this.__uuidMap.get(wrapOrId) if (!wrap) { console.warn(`InstanceMeshManager: Wrap with UUID ${wrapOrId} not found`) return } } else { wrap = wrapOrId if (!wrap || !this.__uuidMap.has(wrap.uuid)) { console.warn(`InstanceMeshManager: Wrap ${wrap.uuid} not found`) return } } const block = this.blocks[wrap.blockIndex] if (!block) { console.warn(`InstanceMeshManager: Block ${wrap.blockIndex} not found for wrap ${wrap.uuid}`) return } // 隐藏实例 this.dummy.scale.set(0, 0, 0) this.dummy.updateMatrix() block.instancedMesh.setMatrixAt(wrap.meshIndex, this.dummy.matrix) block.instancedMesh.instanceMatrix.needsUpdate = true // 回收索引 block.freeIndices.push(wrap.meshIndex) this.__uuidMap.delete(wrap.uuid) block.__indexIdMap.delete(wrap.meshIndex) wrap.dispose() } // 创建新的 InstanceMeshBlock createBlock(): InstanceMeshBlock { const blockIndex = this.blocks.length const block = new InstanceMeshBlock(this.name, this.allowSelect, this.allowDrag, this.viewport, this.geometry, this.material, blockIndex, this.blockCapacity) this.blocks.push(block) return block } setBlockMatrixAt(wrap: InstanceMeshWrap, matrix: THREE.Matrix4) { const block = this.blocks[wrap.blockIndex] if (!block) { console.warn(`InstanceMeshManager: Block ${wrap.blockIndex} not found!`) return } if (!block.__indexIdMap.has(wrap.meshIndex)) { this.__uuidMap.set(wrap.uuid, wrap) wrap.parent = block.instancedMesh } block.instancedMesh.setMatrixAt(wrap.meshIndex, matrix) block.instancedMesh.instanceMatrix.needsUpdate = true } dispose() { for (const block of this.blocks) { block.dispose() } this.blocks.length = 0 // 清空 blocks 数组 this.geometry.dispose() // 释放几何体资源 this.material.dispose() // 释放材质资源 console.log(`InstanceMeshManager ${this.name} disposed.`) } } export class InstanceMeshWrap { readonly entityId: string readonly manager: InstanceMeshManager readonly blockIndex: number readonly meshIndex: number uuid: string parent: THREE.Object3D | null = null name: string visible: boolean constructor(entityId: string, manager: InstanceMeshManager, blockIndex: number, meshIndex: number) { this.uuid = system.createUUID() this.entityId = entityId this.manager = manager this.meshIndex = meshIndex this.blockIndex = blockIndex } setMatrix4(matrix: THREE.Matrix4): InstanceMeshWrap { this.manager.setBlockMatrixAt(this, matrix) return this } dispose() { this.manager.delete(this) this.parent = null } }