Browse Source

InstancePointManager 采用 block 计算,不需要给定最大值

master
修宁 6 months ago
parent
commit
c5386dc41d
  1. 6
      src/core/Constract.ts
  2. 2
      src/core/ModelUtils.ts
  3. 70
      src/core/manager/InstanceMeshBlock.ts
  4. 157
      src/core/manager/InstancePointManager.ts
  5. 1
      src/example/ExampleUtil.js
  6. 2
      src/example/example1.js
  7. 2
      src/modules/carton/CartonRenderer.ts
  8. 2
      src/modules/gstore/GstoreRenderer.ts
  9. 2
      src/modules/measure/MeasureRenderer.ts
  10. 2
      src/modules/pallet/PalletRenderer.ts
  11. 2
      src/modules/tote/ToteRenderer.ts
  12. 6
      src/modules/way/WayRenderer.ts

6
src/core/Constract.ts

@ -32,11 +32,5 @@ const Constract = Object.freeze({
HEIGHT_WAY: 0.01,
HEIGHT_WAY_LABEL: 0.03,
HEIGHT_WAY_LINE: 0.02,
MAX_WAY_INSTANCES: 10000,
MAX_WAY_LINE_INSTANCES: 40000,
MAX_MEASURE_INSTANCES: 1000,
MAX_GSTORE_INSTANCES: 10000,
MAX_PALLET_INSTANCES: 10000
})
export default Constract

2
src/core/ModelUtils.ts

@ -147,7 +147,7 @@ export function getClosestObject(viewport: Viewport, object: THREE.Object3D, ins
if (object.userData && object.userData.t && object.userData.entityId) {
// 找到第一个有效的业务 Object3D
if (object instanceof THREE.InstancedMesh && instanceId >= 0) {
return viewport.pointManagerMap.get(object.userData.t)?.findByMeshInstanceId(instanceId)
return viewport.pointManagerMap.get(object.userData.t)?.findByMeshInstanceId(object.userData.blockIndex, instanceId)
}
return object
}

70
src/core/manager/InstanceMeshBlock.ts

@ -0,0 +1,70 @@
import * as THREE from 'three'
import type Viewport from '@/core/engine/Viewport.ts'
export default class InstanceMeshBlock {
public readonly name: string
public readonly blockIndex: number
public readonly viewport: Viewport
public readonly instancedMesh: THREE.InstancedMesh
public readonly freeIndices: number[] = []
// instanceId -> itemId
public readonly __indexIdMap = new Map<number, string>()
getFreeMeshIndex(): number {
if (this.freeIndices.length === 0) {
return -1 // No free index available
}
return this.freeIndices.pop() // Return the last free index
}
constructor(name: string, allowSelect: boolean, allowDrag: boolean, viewport: Viewport,
geometry: THREE.BufferGeometry, material: THREE.Material,
blockIndex: number, capacity: number) {
this.name = name
this.blockIndex = blockIndex
this.viewport = viewport
this.instancedMesh = new THREE.InstancedMesh(geometry, material, capacity)
this.instancedMesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage)
console.log('createBlock: [' + blockIndex + '] created with capacity:', capacity)
viewport.scene.add(this.instancedMesh)
if (allowSelect) {
this.viewport.entityManager._selectableObjects.push(this.instancedMesh)
}
if (allowDrag) {
this.viewport.entityManager._draggableObjects.push(this.instancedMesh)
}
this.instancedMesh.userData.t = name
this.instancedMesh.userData.entityId = 'InstanceMeshBlock_' + name + '_' + blockIndex
const dummy = new THREE.Object3D()
dummy.scale.set(0, 0, 0)
dummy.updateMatrix()
for (let i = 0; i < capacity; i++) {
this.instancedMesh.setMatrixAt(i, dummy.matrix)
this.freeIndices.push(i)
}
this.instancedMesh.instanceMatrix.needsUpdate = true
}
dispose() {
this.viewport.scene.remove(this.instancedMesh)
this.instancedMesh.geometry.dispose()
if (this.instancedMesh.material) {
if (Array.isArray(this.instancedMesh.material)) {
this.instancedMesh.material.forEach(mat => mat.dispose())
} else {
this.instancedMesh.material.dispose()
}
}
this.instancedMesh.dispose()
this.__indexIdMap.clear()
this.freeIndices.length = 0
}
}

157
src/core/manager/InstancePointManager.ts

@ -1,23 +1,25 @@
import * as THREE from 'three'
import type Viewport from '@/core/engine/Viewport.ts'
import { Vector3 } from 'three/src/math/Vector3'
import InstanceMeshBlock from '@/core/manager/InstanceMeshBlock.ts'
/**
*
* 使 InstanceMesh
*/
export default class InstancePointManager {
public readonly name: string
public readonly viewport: Viewport
public readonly instancedMesh: THREE.InstancedMesh
public readonly allowSelect: boolean
public readonly allowDrag: boolean
public readonly blockCapacity: number = 1000 // 每个 block 的容量
private readonly freeIndices: number[] = []
private readonly maxInstanceCount: number
public readonly blocks: InstanceMeshBlock[] = []
private readonly geometry: THREE.BufferGeometry
private readonly material: THREE.Material
private readonly dummy: THREE.Object3D = new THREE.Object3D()
// itemId -> instanceId
// itemId -> data
private __uuidMap = new Map<string, PointManageWrap>()
// instanceId -> itemId
private __indexIdMap = new Map<number, string>()
createPointSimple(id: string): PointManageWrap {
//@ts-ignore
@ -38,21 +40,39 @@ export default class InstancePointManager {
* @returns ID (-1)
*/
createPoint(item: ItemJson): PointManageWrap {
if (this.freeIndices.length === 0) {
system.showErrorDialog('InstancePointManager is full')
// Try existing blocks
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
}
const meshIndex = this.freeIndices.pop()!
return new PointManageWrap(this, {
return new PointManageWrap(this, blockIndex, meshIndex, {
uuid: item.id,
name: item.name,
blockIndex: blockIndex,
meshIndex: meshIndex,
visible: item.v !== false,
//@ts-ignore
userData: {
t: item.t,
createType: 'point',
blockIndex: blockIndex,
meshIndex: meshIndex,
entityId: item.id
}
})
@ -103,8 +123,12 @@ export default class InstancePointManager {
/**
*
*/
findByMeshInstanceId(instanceId: number): PointManageWrap {
const uuid = this.__indexIdMap.get(instanceId)
findByMeshInstanceId(blockIndex: number, instanceId: number): PointManageWrap {
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)
}
@ -123,13 +147,14 @@ export default class InstancePointManager {
}
this.dummy.updateMatrix()
const block = this.blocks[wrap.blockIndex]
if (!wrap.parent) {
wrap.parent = this.instancedMesh
wrap.parent = block.instancedMesh
this.__uuidMap.set(wrap.uuid, wrap)
this.__indexIdMap.set(wrap.meshIndex, wrap.uuid)
block.__indexIdMap.set(wrap.meshIndex, wrap.uuid)
}
this.instancedMesh.setMatrixAt(wrap.meshIndex, this.dummy.matrix)
this.instancedMesh.instanceMatrix.needsUpdate = true
block.instancedMesh.setMatrixAt(wrap.meshIndex, this.dummy.matrix)
block.instancedMesh.instanceMatrix.needsUpdate = true
}
/**
@ -140,16 +165,18 @@ export default class InstancePointManager {
const wrap = this.__uuidMap.get(id)
if (wrap === undefined) return
const block = this.blocks[wrap.blockIndex]
// 隐藏实例
this.dummy.scale.set(0, 0, 0)
this.dummy.updateMatrix()
this.instancedMesh.setMatrixAt(wrap.meshIndex, this.dummy.matrix)
this.instancedMesh.instanceMatrix.needsUpdate = true
block.instancedMesh.setMatrixAt(wrap.meshIndex, this.dummy.matrix)
block.instancedMesh.instanceMatrix.needsUpdate = true
// 回收索引
this.freeIndices.push(wrap.meshIndex)
block.freeIndices.push(wrap.meshIndex)
this.__uuidMap.delete(id)
this.__indexIdMap.delete(wrap.meshIndex)
block.__indexIdMap.delete(wrap.meshIndex)
wrap.dispose()
}
@ -159,59 +186,70 @@ export default class InstancePointManager {
viewport: Viewport,
geometry: THREE.BufferGeometry,
material: THREE.Material,
maxInstances: number = 20000
allowSelect: boolean, allowDrag: boolean
): InstancePointManager {
return new InstancePointManager(name, viewport, geometry, material, maxInstances)
return new InstancePointManager(name, allowSelect, allowDrag, viewport, geometry, material)
}
private createBlock(): InstanceMeshBlock {
const block = new InstanceMeshBlock(
this.name, this.allowSelect, this.allowDrag, this.viewport,
this.geometry,
this.material, this.blocks.length, this.blockCapacity
)
this.blocks.push(block)
return block
}
private constructor(name: string, viewport: Viewport, geometry: THREE.BufferGeometry, material: THREE.Material, maxInstances: number) {
private constructor(name: string, allowSelect: boolean, allowDrag: boolean, viewport: Viewport, geometry: THREE.BufferGeometry, material: THREE.Material) {
this.name = name
this.allowSelect = allowSelect
this.allowDrag = allowDrag
this.viewport = viewport
this.geometry = geometry
this.material = material
this.maxInstanceCount = maxInstances
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++) {
this.dummy.updateMatrix()
this.instancedMesh.setMatrixAt(i, this.dummy.matrix)
this.freeIndices.push(i)
}
this.instancedMesh.instanceMatrix.needsUpdate = true
// 创建第一个 block
this.createBlock()
// 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)
// if (allowSelect) {
// this.viewport.entityManager._selectableObjects.push(this.instancedMesh)
// }
// if (allowDrag) {
// 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++) {
// this.dummy.updateMatrix()
// this.instancedMesh.setMatrixAt(i, this.dummy.matrix)
// this.freeIndices.push(i)
// }
//
// this.instancedMesh.instanceMatrix.needsUpdate = true
}
dispose() {
this.viewport.scene.remove(this.instancedMesh)
this.instancedMesh.geometry.dispose()
if (this.instancedMesh.material) {
if (Array.isArray(this.instancedMesh.material)) {
this.instancedMesh.material.forEach(mat => mat.dispose())
} else {
this.instancedMesh.material.dispose()
}
for (const block of this.blocks) {
block.dispose()
}
this.instancedMesh.dispose()
this.__uuidMap.clear()
this.__indexIdMap.clear()
this.freeIndices.length = 0
this.blocks.length = 0
}
}
export class PointManageWrap {
readonly manager: InstancePointManager
meshIndex: number = -1
readonly blockIndex: number = -1
readonly meshIndex: number = -1
parent: THREE.Object3D | null = null
uuid: string
@ -234,8 +272,9 @@ export class PointManageWrap {
return false
}
constructor(pointManager: InstancePointManager, data: any, meshIndex: number = -1) {
constructor(pointManager: InstancePointManager, blockIndex: number, meshIndex: number, data: any) {
this.manager = pointManager
this.blockIndex = blockIndex
this.meshIndex = meshIndex
_.extend(this, data)
}
@ -243,7 +282,6 @@ export class PointManageWrap {
dispose() {
this.manager.deletePoint(this.uuid)
this.parent = null
this.meshIndex = -1
}
applyMatrix4(matrix: THREE.Matrix4): PointManageWrap {
@ -260,7 +298,8 @@ export class PointManageWrap {
}
createBox3(): THREE.Box3 {
const instancedMesh = this.manager.instancedMesh
const instancedMesh = this.manager.blocks[this.blockIndex]?.instancedMesh
const matrix = new THREE.Matrix4()
instancedMesh.getMatrixAt(this.meshIndex, matrix)
// 创建包围盒并应用矩阵

1
src/example/ExampleUtil.js

@ -83,7 +83,6 @@ export function buildRackPerformanceData(rows, cols) {
}
}
debugger
return Array.from(data.values())
}

2
src/example/example1.js

@ -395,7 +395,7 @@ export default {
},
{
catalogCode: '__f2', t: 'floor',
items: buildPointPerformanceData('carton', 100, 100)
items: buildPointPerformanceData('carton', 200, 500)
},
{
catalogCode: '__f3', t: 'floor',

2
src/modules/carton/CartonRenderer.ts

@ -69,7 +69,7 @@ export default class PalletRenderer extends BaseRenderer {
this.tempViewport,
this.cartonGeometry,
this.cartonMaterial,
Constract.MAX_PALLET_INSTANCES)
true, true)
)
}

2
src/modules/gstore/GstoreRenderer.ts

@ -55,7 +55,7 @@ export default class GstoreRenderer extends BaseRenderer {
this.tempViewport,
this.pointGeometry,
this.pointMaterial,
Constract.MAX_GSTORE_INSTANCES)
true, true)
)
}

2
src/modules/measure/MeasureRenderer.ts

@ -93,7 +93,7 @@ export default class MeasureRenderer extends BaseRenderer {
this.tempViewport,
this.pointGeometry,
this.pointMaterial,
Constract.MAX_MEASURE_INSTANCES)
true, true)
)
}

2
src/modules/pallet/PalletRenderer.ts

@ -57,7 +57,7 @@ export default class PalletRenderer extends BaseRenderer {
this.tempViewport,
this.palletGeometry,
this.palletMaterial,
Constract.MAX_PALLET_INSTANCES)
true, true)
)
}

2
src/modules/tote/ToteRenderer.ts

@ -59,7 +59,7 @@ export default class PalletRenderer extends BaseRenderer {
this.tempViewport,
this.toteGeometry,
this.toteMaterial,
Constract.MAX_PALLET_INSTANCES)
true, true)
)
}

6
src/modules/way/WayRenderer.ts

@ -206,7 +206,7 @@ export default class WayRenderer extends BaseRenderer {
this.tempViewport,
this.lineGeometry,
this.lineMaterial,
Constract.MAX_WAY_LINE_INSTANCES)
false, false)
)
}
@ -220,7 +220,7 @@ export default class WayRenderer extends BaseRenderer {
this.tempViewport,
this.pointGeometry,
this.pointMaterial,
Constract.MAX_WAY_INSTANCES)
true, true)
)
}
@ -234,7 +234,7 @@ export default class WayRenderer extends BaseRenderer {
this.tempViewport,
this.dirGeometry,
this.dirMaterial,
Constract.MAX_WAY_LINE_INSTANCES)
false, false)
)
}
}

Loading…
Cancel
Save