You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
170 lines
5.0 KiB
170 lines
5.0 KiB
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<string, InstanceMeshWrap>()
|
|
|
|
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
|
|
}
|
|
}
|
|
|