|
|
@ -19,7 +19,12 @@ export default class SelectInspect implements IControls { |
|
|
/** |
|
|
/** |
|
|
* 线框材质,用于显示选中对象的包围盒 |
|
|
* 线框材质,用于显示选中对象的包围盒 |
|
|
*/ |
|
|
*/ |
|
|
material: LineMaterial = new LineMaterial({ color: 0xffff00, linewidth: 2 }) |
|
|
yellowMaterial: LineMaterial = new LineMaterial({ color: 0xffff00, linewidth: 2 }) |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 线框材质,用于显示选中对象的包围盒 |
|
|
|
|
|
*/ |
|
|
|
|
|
redMaterial: LineMaterial = new LineMaterial({ color: 0xff0000, linewidth: 2 }) |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* 矩形材质,用于显示鼠标拖拽选择的矩形区域 |
|
|
* 矩形材质,用于显示鼠标拖拽选择的矩形区域 |
|
|
@ -76,6 +81,11 @@ export default class SelectInspect implements IControls { |
|
|
this.updateSelectionBox(this.viewport.state.selectedObject) |
|
|
this.updateSelectionBox(this.viewport.state.selectedObject) |
|
|
}) |
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
EventBus.on('multiSelectedObjectsChanged', (data) => { |
|
|
|
|
|
// 如果多选对象发生变化,清除当前选中对象的包围盒线框
|
|
|
|
|
|
this.updateMultiSelectionBoxes(data.multiSelectedObjects) |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
EventBus.on('selectedObjectPropertyChanged', (data) => { |
|
|
EventBus.on('selectedObjectPropertyChanged', (data) => { |
|
|
this.updateSelectionBox(this.viewport.state.selectedObject) |
|
|
this.updateSelectionBox(this.viewport.state.selectedObject) |
|
|
}) |
|
|
}) |
|
|
@ -90,6 +100,69 @@ export default class SelectInspect implements IControls { |
|
|
}) |
|
|
}) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
redSelectionGroup = new THREE.Group() |
|
|
|
|
|
|
|
|
|
|
|
private updateMultiSelectionBoxes(multiSelectedObjects: THREE.Object3D[]) { |
|
|
|
|
|
// 为所有多选对象创建包围盒线框
|
|
|
|
|
|
this.clearRedSelectionBoxes() |
|
|
|
|
|
|
|
|
|
|
|
if (!multiSelectedObjects || multiSelectedObjects.length === 0) { |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for (const object of multiSelectedObjects) { |
|
|
|
|
|
if (object.userData.entityId) { |
|
|
|
|
|
this.createRedSelectionBox(object) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
clearRedSelectionBoxes() { |
|
|
|
|
|
// 清除之前的红色包围盒线框
|
|
|
|
|
|
if (this.redSelectionGroup.children.length > 0) { |
|
|
|
|
|
for (const child of this.redSelectionGroup.children) { |
|
|
|
|
|
this.redSelectionGroup.remove(child) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
this.viewport.scene.remove(this.redSelectionGroup) |
|
|
|
|
|
this.redSelectionGroup = new THREE.Group() |
|
|
|
|
|
this.viewport.scene.add(this.redSelectionGroup) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
createRedSelectionBox(object: THREE.Object3D) { |
|
|
|
|
|
// 如果对象没有 entityId,则不创建包围盒线框
|
|
|
|
|
|
if (!object.userData.entityId) { |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 如果选中的对象小于 0.5,要扩展包围盒
|
|
|
|
|
|
const RED_EXPAND_AMOUNT = 0.01 // 扩展包围盒的大小
|
|
|
|
|
|
// 避免某些蒙皮网格的帧延迟效应(e.g. Michelle.glb)
|
|
|
|
|
|
object.updateWorldMatrix(false, true) |
|
|
|
|
|
|
|
|
|
|
|
const box = new THREE.Box3().setFromObject(object) |
|
|
|
|
|
box.expandByScalar(RED_EXPAND_AMOUNT) |
|
|
|
|
|
|
|
|
|
|
|
const size = new THREE.Vector3() |
|
|
|
|
|
box.getSize(size) |
|
|
|
|
|
|
|
|
|
|
|
const center = new THREE.Vector3() |
|
|
|
|
|
box.getCenter(center) |
|
|
|
|
|
|
|
|
|
|
|
// 创建包围盒几何体
|
|
|
|
|
|
const helperGeometry = new THREE.BoxGeometry(size.x, size.y, size.z) |
|
|
|
|
|
const edgesGeometry = new THREE.EdgesGeometry(helperGeometry) |
|
|
|
|
|
const lineGeom = new LineGeometry() |
|
|
|
|
|
// @ts-ignore
|
|
|
|
|
|
lineGeom.setPositions(edgesGeometry.attributes.position.array) |
|
|
|
|
|
|
|
|
|
|
|
const selectionBox = new Line2(lineGeom, this.redMaterial) |
|
|
|
|
|
selectionBox.computeLineDistances() |
|
|
|
|
|
selectionBox.position.copy(center) |
|
|
|
|
|
|
|
|
|
|
|
this.redSelectionGroup.add(selectionBox) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* 更新选中对象的包围盒线框 |
|
|
* 更新选中对象的包围盒线框 |
|
|
*/ |
|
|
*/ |
|
|
@ -101,12 +174,13 @@ export default class SelectInspect implements IControls { |
|
|
} |
|
|
} |
|
|
this.selectionId = selectedObject.userData?.entityId |
|
|
this.selectionId = selectedObject.userData?.entityId |
|
|
|
|
|
|
|
|
const expandAmount = 0.2 // 扩展包围盒的大小
|
|
|
// 如果选中的对象小于 0.5,要扩展包围盒
|
|
|
|
|
|
const YELLOW_EXPAND_AMOUNT = 0.03 // 扩展包围盒的大小
|
|
|
// 避免某些蒙皮网格的帧延迟效应(e.g. Michelle.glb)
|
|
|
// 避免某些蒙皮网格的帧延迟效应(e.g. Michelle.glb)
|
|
|
selectedObject.updateWorldMatrix(false, true) |
|
|
selectedObject.updateWorldMatrix(false, true) |
|
|
|
|
|
|
|
|
const box = new THREE.Box3().setFromObject(selectedObject) |
|
|
const box = new THREE.Box3().setFromObject(selectedObject) |
|
|
box.expandByScalar(expandAmount) |
|
|
box.expandByScalar(YELLOW_EXPAND_AMOUNT) |
|
|
|
|
|
|
|
|
const size = new THREE.Vector3() |
|
|
const size = new THREE.Vector3() |
|
|
box.getSize(size) |
|
|
box.getSize(size) |
|
|
@ -117,16 +191,13 @@ export default class SelectInspect implements IControls { |
|
|
// 创建包围盒几何体
|
|
|
// 创建包围盒几何体
|
|
|
const helperGeometry = new THREE.BoxGeometry(size.x, size.y, size.z) |
|
|
const helperGeometry = new THREE.BoxGeometry(size.x, size.y, size.z) |
|
|
const edgesGeometry = new THREE.EdgesGeometry(helperGeometry) |
|
|
const edgesGeometry = new THREE.EdgesGeometry(helperGeometry) |
|
|
|
|
|
|
|
|
// 使用 LineGeometry 包装 edgesGeometry
|
|
|
|
|
|
const lineGeom = new LineGeometry() |
|
|
const lineGeom = new LineGeometry() |
|
|
//@ts-ignore
|
|
|
// @ts-ignore
|
|
|
lineGeom.setPositions(edgesGeometry.attributes.position.array) |
|
|
lineGeom.setPositions(edgesGeometry.attributes.position.array) |
|
|
|
|
|
|
|
|
const selectionBox = new Line2(lineGeom, this.material) |
|
|
const selectionBox = new Line2(lineGeom, this.yellowMaterial) |
|
|
selectionBox.computeLineDistances() |
|
|
selectionBox.computeLineDistances() |
|
|
selectionBox.position.copy(center) |
|
|
selectionBox.position.copy(center) |
|
|
selectionBox.name = 'selectionBox' |
|
|
|
|
|
this.selectionBox = selectionBox |
|
|
this.selectionBox = selectionBox |
|
|
|
|
|
|
|
|
console.log('selectedItem', this.viewport.state.selectedItem) |
|
|
console.log('selectedItem', this.viewport.state.selectedItem) |
|
|
@ -162,7 +233,7 @@ export default class SelectInspect implements IControls { |
|
|
if (this.recStartPos) { |
|
|
if (this.recStartPos) { |
|
|
// 创建矩形
|
|
|
// 创建矩形
|
|
|
this.rectangle = new THREE.Mesh( |
|
|
this.rectangle = new THREE.Mesh( |
|
|
new THREE.PlaneGeometry(1, 1), |
|
|
new THREE.PlaneGeometry(0.001, 0.001), |
|
|
this.rectMaterial |
|
|
this.rectMaterial |
|
|
) |
|
|
) |
|
|
this.rectangle.name = 'selectRectangle' |
|
|
this.rectangle.name = 'selectRectangle' |
|
|
@ -176,6 +247,7 @@ export default class SelectInspect implements IControls { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
updateRectangle(position: THREE.Vector3) { |
|
|
updateRectangle(position: THREE.Vector3) { |
|
|
if (!this.rectangle || !this.recStartPos) return |
|
|
if (!this.rectangle || !this.recStartPos) return |
|
|
// console.log('updateRectangle', this.recStartPos, position)
|
|
|
// console.log('updateRectangle', this.recStartPos, position)
|
|
|
@ -201,6 +273,8 @@ export default class SelectInspect implements IControls { |
|
|
// 记录鼠标按下位置
|
|
|
// 记录鼠标按下位置
|
|
|
this.recStartPos = this.viewport.getClosestIntersection(event) |
|
|
this.recStartPos = this.viewport.getClosestIntersection(event) |
|
|
this.createRectangle() |
|
|
this.createRectangle() |
|
|
|
|
|
this.viewport.controls.enabled = false // 禁用控制器
|
|
|
|
|
|
|
|
|
} else { |
|
|
} else { |
|
|
// 为 click 事件添加处理逻辑
|
|
|
// 为 click 事件添加处理逻辑
|
|
|
this.clickTime = Date.now() |
|
|
this.clickTime = Date.now() |
|
|
@ -220,11 +294,14 @@ export default class SelectInspect implements IControls { |
|
|
|
|
|
|
|
|
disposeRect() { |
|
|
disposeRect() { |
|
|
if (this.rectangle !== null) { |
|
|
if (this.rectangle !== null) { |
|
|
|
|
|
// 查找在这个矩形内的所有有效业务对象,并将他们添加进 viewport.state.multiSelectedObjects
|
|
|
|
|
|
this.multipleSelectedObjects() |
|
|
this.viewport.scene.remove(this.rectangle) |
|
|
this.viewport.scene.remove(this.rectangle) |
|
|
this.rectangle.geometry.dispose() |
|
|
this.rectangle.geometry.dispose() |
|
|
this.rectangle = null |
|
|
this.rectangle = null |
|
|
} |
|
|
} |
|
|
this.recStartPos = null |
|
|
this.recStartPos = null |
|
|
|
|
|
this.viewport.controls.enabled = true // 启用控制器
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
onMouseUp(event: MouseEvent) { |
|
|
onMouseUp(event: MouseEvent) { |
|
|
@ -253,7 +330,71 @@ export default class SelectInspect implements IControls { |
|
|
selectedObjectMeta: this.viewport.state.selectedObjectMeta |
|
|
selectedObjectMeta: this.viewport.state.selectedObjectMeta |
|
|
}) |
|
|
}) |
|
|
} |
|
|
} |
|
|
|
|
|
} else { |
|
|
|
|
|
// 如果没有选中任何对象,清除选中状态
|
|
|
|
|
|
this.viewport.state.selectedObject = null |
|
|
|
|
|
this.viewport.state.selectedItem = null |
|
|
|
|
|
this.viewport.state.selectedEntityId = null |
|
|
|
|
|
this.viewport.state.selectedObjectMeta = null |
|
|
|
|
|
EventBus.dispatch('selectedObjectChanged', { |
|
|
|
|
|
viewport: markRaw(this.viewport), |
|
|
|
|
|
selectedObject: null, |
|
|
|
|
|
selectedItem: null, |
|
|
|
|
|
selectedEntityId: null, |
|
|
|
|
|
selectedObjectMeta: null |
|
|
|
|
|
}) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private multipleSelectedObjects() { |
|
|
|
|
|
if (!this.rectangle || !this.recStartPos) return |
|
|
|
|
|
|
|
|
|
|
|
// 获取矩形的包围盒
|
|
|
|
|
|
const box = new THREE.Box3().setFromObject(this.rectangle) |
|
|
|
|
|
|
|
|
|
|
|
// 获取盒子的 startX, startZ, endX, endZ
|
|
|
|
|
|
const startX = box.min.x |
|
|
|
|
|
const startZ = box.min.z |
|
|
|
|
|
const endX = box.max.x |
|
|
|
|
|
const endZ = box.max.z |
|
|
|
|
|
|
|
|
|
|
|
// 查找所有在矩形内的对象
|
|
|
|
|
|
const objects = this.viewport.entityManager.getObjectsInBox(startX, startZ, endX, endZ) |
|
|
|
|
|
|
|
|
|
|
|
// 清空之前的多选对象
|
|
|
|
|
|
this.viewport.state.multiSelectedObjects = [] |
|
|
|
|
|
|
|
|
|
|
|
// 遍历找到的对象,添加到多选对象中
|
|
|
|
|
|
const multiSelectedObjects = [] |
|
|
|
|
|
const multiSelectedItems = [] |
|
|
|
|
|
const multiSelectedEntityIds = [] |
|
|
|
|
|
const multiSelectedObjectMetas = [] |
|
|
|
|
|
for (const object of objects) { |
|
|
|
|
|
if (object.userData.entityId && object.userData.t) { |
|
|
|
|
|
const item = this.viewport.entityManager.findItemById(object.userData.entityId) |
|
|
|
|
|
if (item && item.dt.protected !== true) { |
|
|
|
|
|
multiSelectedObjects.push(object) |
|
|
|
|
|
multiSelectedItems.push(item) |
|
|
|
|
|
multiSelectedEntityIds.push(object.userData.entityId) |
|
|
|
|
|
multiSelectedObjectMetas.push(getMeta(object.userData.t)) |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 触发多选对象更新事件
|
|
|
|
|
|
this.viewport.state.multiSelectedObjects = markRaw(objects) |
|
|
|
|
|
this.viewport.state.multiSelectedItems = markRaw(multiSelectedItems) |
|
|
|
|
|
this.viewport.state.multiSelectedEntityIds = multiSelectedEntityIds |
|
|
|
|
|
this.viewport.state.multiSelectedObjectMetas = multiSelectedObjectMetas |
|
|
|
|
|
EventBus.dispatch('multiSelectedObjectsChanged', { |
|
|
|
|
|
viewport: markRaw(this.viewport), |
|
|
|
|
|
multiSelectedObjects: this.viewport.state.multiSelectedObjects, |
|
|
|
|
|
multiSelectedItems: this.viewport.state.multiSelectedItems, |
|
|
|
|
|
multiSelectedEntityIds: this.viewport.state.multiSelectedEntityIds, |
|
|
|
|
|
multiSelectedObjectMetas: this.viewport.state.multiSelectedObjectMetas |
|
|
|
|
|
}) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|