如何实现双击删除画布上的对应物体?
思路:
首先捕捉到鼠标在画布内的WEBGL设备坐标 [-1,1],我们虽然可以通过鼠标事件获取鼠标相对于浏览器的位置,但无法直接获取到WEBGL的对应坐标,我们可以通过数学换算一下:
- 设备坐标X = (e.clientX/画布宽度)* 2 - 1
- 设备坐标Y = -(e.clientY/画布宽度)* 2 + 1
第二步:创建一个光线投射器 Raycaster
,光线投射器可以为我们建立相机与鼠标之间的射线,相机鼠标,两点一线。这样我们就可以获取到这个射线穿过的所有实体了。
- 创建 Raycaster 实例
- 创建二维向量(Vector2)实例,将二维向量的X和Y设置为设备坐标
- 使用光线投射器的
setFromCamera
方法,更新摄像机和鼠标之间连线的位置 - 使用光线投射器的
intersectObjects
方法,获取这条射线穿过的所有物体,收集为数组 - 由于我们只需要删除一个物体,我们直接取数组中第一个元素即可(数组中第一个元素就是离我们(相机)最近的那个物体)
- 执行删除方法,删除几何图形,材质对象,然后再删除物体本身,整个删除操作就完成了
代码示例:
.... 创建相机创建场景代码省略
const raycaster = new THREE.Raycaster()//创建一个光线投射器
const pointer = new THREE.Vector2() //创建一个二维向量
window.addEventListener('dblclick' /*双击是dblclick*/, (e) => {
if (!cubes.length) return
// 设备坐标X = (e.clientX/画布宽度)* 2 - 1
// 设备坐标Y = -(e.clientY/画布宽度)* 2 + 1
pointer.x = (e.clientX / window.innerWidth) * 2 - 1
pointer.y = -(e.clientY / window.innerHeight) * 2 + 1
//更新摄像机和鼠标之间的连线(位置)
raycaster.setFromCamera(pointer, camera)
//获取这条线穿过了哪些物体,收集成一个数组
const list = raycaster.intersectObjects(cubes)
if (!list[0]) return
//找到这个cube
const cubeIndex = cubes.findIndex(cube => cube === list[0].object)
if (cubeIndex === -1) return
//要删除物体自身的几何图形,和材质对象,再删除物体本身
cubes[cubeIndex].geometry.dispose()//删除几何图形对象(释放内存)
for (const material of cubes[cubeIndex].material) {
//删除几何图形对象(释放内存)
material.dispose()
}
//从场景中删除立方体
scene.remove(cubes[cubeIndex])
//拿掉
cubes.splice(cubeIndex, 1)
})