Browse Source

InstancePointManager / LineSegmentManager 重构

master
修宁 6 months ago
parent
commit
1b56e8d084
  1. 6
      src/core/ModelUtils.ts
  2. 8
      src/core/base/BaseRenderer.ts
  3. 17
      src/core/controls/DragControl.ts
  4. 20
      src/core/controls/SelectInspect.ts
  5. 5
      src/core/engine/Viewport.ts
  6. 6
      src/core/manager/EntityManager.ts
  7. 94
      src/core/manager/InstancePointManager.ts
  8. 10
      src/core/manager/LineSegmentManager.ts
  9. 6
      src/example/example1.js
  10. 8
      src/modules/measure/MeasureRenderer.ts

6
src/core/ModelUtils.ts

@ -133,15 +133,17 @@ export function getLineId(startId: string, endId: string, type: LinkType): strin
/** /**
* Object3D Object3D * Object3D Object3D
* @param object
*/ */
export function getClosestObject(object: THREE.Object3D) { export function getClosestObject(viewport: Viewport, object: THREE.Object3D, instanceId: number = -1): Object3DLike {
if (!object) { if (!object) {
return undefined return undefined
} }
while (object) { while (object) {
if (object.userData && object.userData.t && object.userData.entityId) { if (object.userData && object.userData.t && object.userData.entityId) {
// 找到第一个有效的业务 Object3D // 找到第一个有效的业务 Object3D
if (object instanceof THREE.InstancedMesh && instanceId >= 0) {
return viewport.pointManagerMap.get(object.userData.t)?.findByMeshInstanceId(instanceId)
}
return object return object
} }
// 向上查找父级 // 向上查找父级

8
src/core/base/BaseRenderer.ts

@ -4,7 +4,7 @@ import { getLineId, setUserDataForItem, setUserDataForLine } from '@/core/ModelU
import { Line2 } from 'three/examples/jsm/lines/Line2' import { Line2 } from 'three/examples/jsm/lines/Line2'
import InstancePointManager, { PointManageWrap } from '@/core/manager/InstancePointManager.ts' import InstancePointManager, { PointManageWrap } from '@/core/manager/InstancePointManager.ts'
import Constract from '@/core/Constract.ts' import Constract from '@/core/Constract.ts'
import type LineSegmentManager from '@/core/manager/LineSegmentManager.ts' import LineSegmentManager, { LineManageWrap } from '@/core/manager/LineSegmentManager.ts'
import type { Object3DLike } from '@/types/ModelTypes.ts' import type { Object3DLike } from '@/types/ModelTypes.ts'
/** /**
@ -234,6 +234,9 @@ export default abstract class BaseRenderer {
) )
point.scale.set(item.tf[2][0], item.tf[2][1], item.tf[2][2]) point.scale.set(item.tf[2][0], item.tf[2][1], item.tf[2][2])
if (point instanceof PointManageWrap) {
point.manager.syncMeshObject3D(point)
}
return point return point
} }
@ -282,6 +285,9 @@ export default abstract class BaseRenderer {
if (line instanceof Line2) { if (line instanceof Line2) {
const geom = line.geometry const geom = line.geometry
geom.setFromPoints([startPoint.position, endPoint.position]) geom.setFromPoints([startPoint.position, endPoint.position])
} else if (line instanceof LineManageWrap) {
line.manager.updateLine(lineId, startPoint.position, endPoint.position, line.color)
} }
this.afterCreateOrUpdateLine(start, end, type, option, line) this.afterCreateOrUpdateLine(start, end, type, option, line)

17
src/core/controls/DragControl.ts

@ -3,6 +3,9 @@ import type Viewport from '@/core/engine/Viewport.ts'
import type IControls from '@/core/controls/IControls.ts' import type IControls from '@/core/controls/IControls.ts'
import { getClosestObject } from '@/core/ModelUtils.ts' import { getClosestObject } from '@/core/ModelUtils.ts'
import EventBus from '@/runtime/EventBus.ts' import EventBus from '@/runtime/EventBus.ts'
import type { Object3DLike } from '@/types/ModelTypes.ts'
import InstancePointManager, { PointManageWrap } from '@/core/manager/InstancePointManager.ts'
import { LineManageWrap } from '@/core/manager/LineSegmentManager.ts'
/** /**
* ThreeJS X/Z * ThreeJS X/Z
@ -171,7 +174,7 @@ export default class DragControl implements IControls {
/** /**
* 线 * 线
*/ */
private getIntersectedDraggableObject(mouse: THREE.Vector2): THREE.Object3D | null { private getIntersectedDraggableObject(mouse: THREE.Vector2): Object3DLike | undefined {
const raycaster = new THREE.Raycaster() const raycaster = new THREE.Raycaster()
raycaster.setFromCamera(mouse, this.viewport.camera) raycaster.setFromCamera(mouse, this.viewport.camera)
@ -179,7 +182,7 @@ export default class DragControl implements IControls {
const intersects = raycaster.intersectObjects(draggableObjects, true) const intersects = raycaster.intersectObjects(draggableObjects, true)
if (intersects.length > 0) { if (intersects.length > 0) {
return getClosestObject(intersects[0].object) return getClosestObject(this.viewport, intersects[0].object, intersects[0].instanceId)
} }
} }
@ -187,7 +190,7 @@ export default class DragControl implements IControls {
/** /**
* *
*/ */
private createShadows(objects: THREE.Object3D[]): void { private createShadows(objects: Object3DLike[]): void {
this.removeShadows() this.removeShadows()
this.dragShadowsGroup = new THREE.Group() this.dragShadowsGroup = new THREE.Group()
@ -199,8 +202,12 @@ export default class DragControl implements IControls {
// 克隆对象的几何体和材质 // 克隆对象的几何体和材质
// const shadowBox = obj.clone() // const shadowBox = obj.clone()
let box: THREE.Box3
const box = new THREE.Box3().setFromObject(obj) if (obj instanceof THREE.Object3D) {
box = new THREE.Box3().setFromObject(obj)
} else if (obj instanceof PointManageWrap) {
box = obj.createBox3()
}
const size = new THREE.Vector3() const size = new THREE.Vector3()
box.getSize(size) box.getSize(size)
const geometry = new THREE.PlaneGeometry(size.x, size.z) const geometry = new THREE.PlaneGeometry(size.x, size.z)

20
src/core/controls/SelectInspect.ts

@ -8,6 +8,8 @@ import EventBus from '@/runtime/EventBus'
import { markRaw } from 'vue' import { markRaw } from 'vue'
import { getSetter } from '@/core/manager/ModuleManager.ts' import { getSetter } from '@/core/manager/ModuleManager.ts'
import Constract from '@/core/Constract.ts' import Constract from '@/core/Constract.ts'
import type { Object3DLike } from '@/types/ModelTypes.ts'
import { PointManageWrap } from '@/core/manager/InstancePointManager.ts'
/** /**
* *
@ -206,7 +208,12 @@ export default class SelectInspect implements IControls {
if (!object.userData.entityId) { if (!object.userData.entityId) {
return return
} }
const box = new THREE.Box3().setFromObject(object) let box: THREE.Box3
if (object instanceof PointManageWrap) {
box = object.createBox3()
} else if (object instanceof THREE.Object3D) {
box = new THREE.Box3().setFromObject(object)
}
const min = box.min const min = box.min
const max = box.max const max = box.max
@ -250,7 +257,14 @@ export default class SelectInspect implements IControls {
// 避免某些蒙皮网格的帧延迟效应(e.g. Michelle.glb) // 避免某些蒙皮网格的帧延迟效应(e.g. Michelle.glb)
selectedObject.updateWorldMatrix(false, true) selectedObject.updateWorldMatrix(false, true)
const box = new THREE.Box3().setFromObject(selectedObject)
let box: THREE.Box3
if (selectedObject instanceof THREE.Object3D) {
box = new THREE.Box3().setFromObject(selectedObject)
} else if (selectedObject instanceof PointManageWrap) {
box = selectedObject.createBox3()
}
const min = box.min const min = box.min
const max = box.max const max = box.max
@ -376,7 +390,7 @@ export default class SelectInspect implements IControls {
this.clickTime = null this.clickTime = null
if (Date.now() - clickTime < 200) { if (Date.now() - clickTime < 200) {
// 如果是点击事件,触发选中逻辑 // 如果是点击事件,触发选中逻辑
const objects: THREE.Object3D[] = this.viewport.entityManager.getObjectByCanvasMouse(event) const objects: Object3DLike[] = this.viewport.entityManager.getObjectByCanvasMouse(event)
if (objects.length > 0 && objects[0]?.userData?.entityId && objects[0]?.userData?.createType !== 'line') { if (objects.length > 0 && objects[0]?.userData?.entityId && objects[0]?.userData?.createType !== 'line') {
console.log('mouseClick', objects) console.log('mouseClick', objects)
const object = objects[0] const object = objects[0]

5
src/core/engine/Viewport.ts

@ -25,6 +25,7 @@ import type { PropertySetter } from '@/core/base/PropertyTypes.ts'
import LabelManager from '@/core/manager/LabelManager.ts' import LabelManager from '@/core/manager/LabelManager.ts'
import type InstancePointManager from '@/core/manager/InstancePointManager.ts' import type InstancePointManager from '@/core/manager/InstancePointManager.ts'
import type LineSegmentManager from '@/core/manager/LineSegmentManager.ts' import type LineSegmentManager from '@/core/manager/LineSegmentManager.ts'
import type { Object3DLike } from '@/types/ModelTypes.ts'
/** /**
* *
@ -595,7 +596,7 @@ export interface ViewportState {
/** /**
* *
*/ */
selectedObject: THREE.Object3D | undefined selectedObject: Object3DLike | undefined
selectedItem: ItemJson | undefined selectedItem: ItemJson | undefined
selectedEntityId: string | undefined selectedEntityId: string | undefined
selectedObjectSetter: PropertySetter | undefined selectedObjectSetter: PropertySetter | undefined
@ -603,7 +604,7 @@ export interface ViewportState {
/** /**
* *
*/ */
multiSelectedObjects: THREE.Object3D[] multiSelectedObjects: Object3DLike[]
multiSelectedItems: ItemJson[] multiSelectedItems: ItemJson[]
multiSelectedEntityIds: string[] multiSelectedEntityIds: string[]

6
src/core/manager/EntityManager.ts

@ -460,7 +460,7 @@ export default class EntityManager {
return getFreezeDeep(this.___entityMap.get(linkStartPointId)) return getFreezeDeep(this.___entityMap.get(linkStartPointId))
} }
getObjectByCanvasMouse(event: MouseEvent): THREE.Object3D[] { getObjectByCanvasMouse(event: MouseEvent): Object3DLike[] {
const _domElement = this.viewport.renderer.domElement const _domElement = this.viewport.renderer.domElement
const rect = _domElement.getBoundingClientRect() const rect = _domElement.getBoundingClientRect()
const _pointer = new Vector2() const _pointer = new Vector2()
@ -476,8 +476,8 @@ export default class EntityManager {
// 根据距离排序射线命中的对象集 // 根据距离排序射线命中的对象集
return _.map( return _.map(
_intersections.sort((a, b) => a.distance - b.distance), _intersections.sort((a, b) => a.distance - b.distance),
r => getClosestObject(r.object) r => getClosestObject(this.viewport, r.object, r.instanceId)
).filter(obj => obj?.userData && obj.userData.selectable !== false) ).filter((obj: Object3DLike) => obj?.userData && obj.userData.selectable !== false)
} }
/** /**

94
src/core/manager/InstancePointManager.ts

@ -2,16 +2,22 @@ import * as THREE from 'three'
import type Viewport from '@/core/engine/Viewport.ts' import type Viewport from '@/core/engine/Viewport.ts'
import { Vector3 } from 'three/src/math/Vector3' import { Vector3 } from 'three/src/math/Vector3'
/**
*
*/
export default class InstancePointManager { export default class InstancePointManager {
private readonly viewport: Viewport public readonly viewport: Viewport
private readonly instancedMesh: THREE.InstancedMesh public readonly instancedMesh: THREE.InstancedMesh
private readonly freeIndices: number[] = [] private readonly freeIndices: number[] = []
private readonly maxInstanceCount: number private readonly maxInstanceCount: number
private readonly geometry: THREE.BufferGeometry private readonly geometry: THREE.BufferGeometry
private readonly material: THREE.Material private readonly material: THREE.Material
private readonly dummy: THREE.Object3D = new THREE.Object3D() private readonly dummy: THREE.Object3D = new THREE.Object3D()
// itemId -> instanceId // 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 * @param option
*/ */
updatePoint(item: ItemJson, option: { position?: Vector3, rotation?: Vector3, scale?: Vector3 } = {}): void { 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 if (wrap === undefined) return
wrap.visible = item.v !== false wrap.visible = item.v !== false
@ -78,7 +84,16 @@ export default class InstancePointManager {
* *
*/ */
getObject3DLike(id: string): PointManageWrap { 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) { syncMeshObject3D(wrap: PointManageWrap) {
@ -86,7 +101,6 @@ export default class InstancePointManager {
console.error('InstancePointManager: Invalid meshIndex for wrap', wrap) console.error('InstancePointManager: Invalid meshIndex for wrap', wrap)
return return
} }
if (!wrap.visible) { if (!wrap.visible) {
this.dummy.scale.set(0, 0, 0) this.dummy.scale.set(0, 0, 0)
} else { } else {
@ -96,7 +110,11 @@ export default class InstancePointManager {
} }
this.dummy.updateMatrix() this.dummy.updateMatrix()
if (!wrap.parent) {
wrap.parent = this.instancedMesh 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.setMatrixAt(wrap.meshIndex, this.dummy.matrix)
this.instancedMesh.instanceMatrix.needsUpdate = true this.instancedMesh.instanceMatrix.needsUpdate = true
} }
@ -106,7 +124,7 @@ export default class InstancePointManager {
* @param id ID * @param id ID
*/ */
deletePoint(id: string): void { deletePoint(id: string): void {
const wrap = this.instanceData.get(id) const wrap = this.__uuidMap.get(id)
if (wrap === undefined) return if (wrap === undefined) return
// 隐藏实例 // 隐藏实例
@ -117,52 +135,24 @@ export default class InstancePointManager {
// 回收索引 // 回收索引
this.freeIndices.push(wrap.meshIndex) this.freeIndices.push(wrap.meshIndex)
this.instanceData.delete(id) this.__uuidMap.delete(id)
this.__indexIdMap.delete(wrap.meshIndex)
wrap.dispose() 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( public static create(
name: string,
viewport: Viewport, viewport: Viewport,
geometry: THREE.BufferGeometry, geometry: THREE.BufferGeometry,
material: THREE.Material, material: THREE.Material,
maxInstances: number = 1000 maxInstances: number = 1000
): InstancePointManager { ): InstancePointManager {
return new InstancePointManager(viewport, geometry, material, maxInstances) return new InstancePointManager(name, viewport, geometry, material, maxInstances)
} }
constructor( private constructor(
name: string,
viewport: Viewport, viewport: Viewport,
geometry: THREE.BufferGeometry, geometry: THREE.BufferGeometry,
material: THREE.Material, material: THREE.Material,
@ -175,7 +165,13 @@ export default class InstancePointManager {
this.instancedMesh = new THREE.InstancedMesh(geometry, material, maxInstances) this.instancedMesh = new THREE.InstancedMesh(geometry, material, maxInstances)
this.instancedMesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage) this.instancedMesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage)
this.instancedMesh.name = name
console.log('InstancePointManager: [' + name + '] created with maxInstances:', maxInstances)
viewport.scene.add(this.instancedMesh) 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) this.dummy.scale.set(0, 0, 0)
for (let i = 0; i < maxInstances; i++) { for (let i = 0; i < maxInstances; i++) {
@ -200,7 +196,8 @@ export default class InstancePointManager {
} }
this.instancedMesh.dispose() this.instancedMesh.dispose()
this.instanceData.clear() this.__uuidMap.clear()
this.__indexIdMap.clear()
this.freeIndices.length = 0 this.freeIndices.length = 0
} }
} }
@ -219,6 +216,9 @@ export class PointManageWrap {
//@ts-ignore //@ts-ignore
userData: UserData = {} userData: UserData = {}
updateWorldMatrix() {
}
get type() { get type() {
return 'PointManageWrap' return 'PointManageWrap'
} }
@ -238,4 +238,14 @@ export class PointManageWrap {
this.parent = null this.parent = null
this.meshIndex = -1 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)
}
} }

10
src/core/manager/LineSegmentManager.ts

@ -248,11 +248,11 @@ export default class LineSegmentManager {
/** /**
* 线 * 线
*/ */
public static create(viewport: Viewport, lineMaterial: LineMaterial): LineSegmentManager { public static create(name: string, viewport: Viewport, lineMaterial: LineMaterial): LineSegmentManager {
return new LineSegmentManager(viewport, lineMaterial) return new LineSegmentManager(name, viewport, lineMaterial)
} }
private constructor(viewport: Viewport, lineMaterial: LineMaterial) { private constructor(name: string, viewport: Viewport, lineMaterial: LineMaterial) {
this.viewport = viewport this.viewport = viewport
this.lineMaterial = lineMaterial this.lineMaterial = lineMaterial
@ -260,7 +260,7 @@ export default class LineSegmentManager {
// 创建线段的渲染对象 // 创建线段的渲染对象
this.lineSegments = new LineSegments2(this.lineGeometry, this.lineMaterial) this.lineSegments = new LineSegments2(this.lineGeometry, this.lineMaterial)
this.lineSegments.name = 'batch_line_segments' this.lineSegments.name = name
this.lineSegments.frustumCulled = false this.lineSegments.frustumCulled = false
this.viewport.scene.add(this.lineSegments) this.viewport.scene.add(this.lineSegments)
} }
@ -309,6 +309,8 @@ export class LineManageWrap {
return false return false
} }
updateWorldMatrix(){}
constructor(lineManager: LineSegmentManager, data: any, start: THREE.Vector3, end: THREE.Vector3, color: THREE.Color) { constructor(lineManager: LineSegmentManager, data: any, start: THREE.Vector3, end: THREE.Vector3, color: THREE.Color) {
this.manager = lineManager this.manager = lineManager
_.extend(this, data) _.extend(this, data)

6
src/example/example1.js

@ -66,13 +66,15 @@ export default {
v: true, v: true,
tf: [[-4, 0.1, 4], [90, 0, 0], [0.25, 0.25, 0.1]], tf: [[-4, 0.1, 4], [90, 0, 0], [0.25, 0.25, 0.1]],
dt: { in: [], out: [], center: ['P2'] } dt: { in: [], out: [], center: ['P2'] }
}, { },
{
id: 'P2', id: 'P2',
t: 'measure', t: 'measure',
v: true, v: true,
tf: [[5, 0.1, 4], [90, 0, 0], [0.25, 0.25, 0.1]], tf: [[5, 0.1, 4], [90, 0, 0], [0.25, 0.25, 0.1]],
dt: { in: [], out: [], center: ['P1', 'P3'] } dt: { in: [], out: [], center: ['P1', 'P3'] }
}, { },
{
id: 'P3', id: 'P3',
t: 'measure', t: 'measure',
v: true, v: true,

8
src/modules/measure/MeasureRenderer.ts

@ -37,15 +37,15 @@ export default class MeasureRenderer extends BaseRenderer {
dashed: false dashed: false
}) })
readonly defulePositionY = Constract.HEIGHT_MEASURE readonly defulePositionY = Constract.HEIGHT_MEASURE
readonly defaultScale: THREE.Vector3 = new THREE.Vector3(0.25, 0.1, 0.25) readonly defaultScale: THREE.Vector3 = new THREE.Vector3(0.25, 0.25, 0.1)
readonly defaultRotation: THREE.Vector3 = new THREE.Vector3(0, 0, 0) readonly defaultRotation: THREE.Vector3 = new THREE.Vector3(90, 0, 0)
createPointManager(): InstancePointManager { createPointManager(): InstancePointManager {
return InstancePointManager.create(this.tempViewport, this.pointGeometry, this.pointMaterial, Constract.MAX_MEASURE_INSTANCES) return InstancePointManager.create(this.itemTypeName, this.tempViewport, this.pointGeometry, this.pointMaterial, Constract.MAX_MEASURE_INSTANCES)
} }
createLineSegmentManager(): LineSegmentManager { createLineSegmentManager(): LineSegmentManager {
return LineSegmentManager.create(this.tempViewport, this.lineMaterial) return LineSegmentManager.create(this.itemTypeName, this.tempViewport, this.lineMaterial)
} }
/** /**

Loading…
Cancel
Save