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

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
}
}