公司之前有个绘制大量点和矢量的编辑平台是一个外包开发的,外包写的很粗糙,导致点线数据一朵卡顿频繁,fps骤降至3,因此决定用InstanceMesh改造一番。外包写的逻辑密密麻麻,可读性有些略差,在用InstanceMesh渲染物体时遇到了一个框选问题。记录一番。
以下是一个简单的SelectionBox实现案例
import * as THREE from 'three';
import { SelectionBox } from 'three/examples/jsm/interactive/SelectionBox.js';
import { SelectionHelper } from 'three/examples/jsm/interactive/SelectionHelper.js';
// 创建场景、相机、渲染器
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 添加多个立方体作为可选对象
const objects = [];
for (let i = 0; i < 10; i++) {
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
cube.position.set(Math.random() * 5, Math.random() * 5, Math.random() * 5);
scene.add(cube);
objects.push(cube);
}
// 创建 SelectionBox 和 SelectionHelper
const selectionBox = new SelectionBox(camera, scene);
const selectionHelper = new SelectionHelper(selectionBox, renderer, 'selectBox');
// 监听鼠标事件
document.addEventListener('pointerdown', (event) => {
selectionBox.startPoint.set(
(event.clientX / window.innerWidth) * 2 - 1,
-(event.clientY / window.innerHeight) * 2 + 1,
0.5
);
}, false);
document.addEventListener('pointermove', (event) => {
if (selectionHelper.isDown) {
selectionBox.endPoint.set(
(event.clientX / window.innerWidth) * 2 - 1,
-(event.clientY / window.innerHeight) * 2 + 1,
0.5
);
const allSelected = selectionBox.select();
for (const obj of allSelected) {
if (obj.material) obj.material.color.set(0xff0000); // 改变选中对象的颜色
}
}
});
document.addEventListener('pointerup', (event) => {
if (selectionHelper.isDown) {
selectionBox.endPoint.set(
(event.clientX / window.innerWidth) * 2 - 1,
-(event.clientY / window.innerHeight) * 2 + 1,
0.5
);
const allSelected = selectionBox.select();
for (const obj of objects) {
if (obj.material) obj.material.color.set(0x00ff00); // 重置所有对象颜色
}
for (const obj of allSelected) {
if (obj.material) obj.material.color.set(0xff0000); // 改变选中对象的颜色
}
}
selectionHelper.isDown = false;
});
// 渲染循环
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
在使用上面的方法去框选时会存在一个问题,执行select后选不中instanceMesh这是为什么呢?直接看源码。
在执行select的时候主要关注searchChildInFrustum,可以发现哈select方法返回的事collection而我们需要的instanceMesh在instances,这时候你可以将instances返回就可以拿到想要的instanceId了。