鼠标选中网格高亮
要实现的效果是:
网格上的高亮块时刻跟踪鼠标的移动。
可以分成三步实现:
- 获取鼠标在网格上的坐标A
- 根据坐标A获取网格上方块的坐标B
- 高亮平面的坐标移动到坐标B位置
实际显示的网格是THREE.GridHelper(网格助手),
需要创建一个不可见的辅助平面Plane,
Plane的尺寸和位置和grid完全一致,
鼠标在移动时,计算相机-鼠标raycaster射线和Plane的交点point。
point需要经过偏移得到高亮块绘制位置:
- floor() 向下取整
- addScale(num) xz轴正向偏移0.5
- y轴为0
创建辅助平面和高亮平面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| const plane = new THREE.Mesh( new THREE.PlaneGeometry(12, 12), new THREE.MeshBasicMaterial({ visible:false, }) ) plane.rotateX(-Math.PI/2) scene.add(plane)
const highLight = new THREE.Mesh( new THREE.PlaneGeometry(1, 1), new THREE.MeshBasicMaterial({ color: 0xffffff }) ) highLight.rotateX(-Math.PI/2) highLight.position.set(0.5, 0, 0.5) scene.add(highLight)
|
选中移动高亮块:
1 2 3 4 5 6 7 8 9 10 11 12 13
| const mousePosition = new THREE.Vector2() const raycaster = new THREE.Raycaster()
window.onmousemove = e => { mousePosition.x = e.offsetX / window.innerWidth * 2 - 1 mousePosition.y = 1 - e.offsetY / window.innerHeight * 2 raycaster.setFromCamera(mousePosition, camera) const interSections = raycaster.intersectObject(plane) if (interSections[0]) { const position = interSections[0].point.floor().addScalar(0.5) highLight.position.set(position.x, 0, position.z) } }
|
创建物体
鼠标点击事件中添加创建物体逻辑,
但是在物体创建之前需要先判断当前网格内是否已经存在物体:
使用的是坐标匹配的方式。
为了做提示,鼠标移动到已经存在物体的网格中时,需要将网格标红。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| const mousePosition = new THREE.Vector2() const raycaster = new THREE.Raycaster() const objects = [] const isExist = () => objects.find(obj => obj.position.x === highLight.position.x && obj.position.z === highLight.position.z) window.onmousemove = e => { mousePosition.x = e.offsetX / window.innerWidth * 2 - 1 mousePosition.y = 1 - e.offsetY / window.innerHeight * 2 raycaster.setFromCamera(mousePosition, camera) const interSections = raycaster.intersectObject(plane) if (interSections[0]) { const position = interSections[0].point.floor().addScalar(0.5) highLight.position.set(position.x, 0, position.z) highLight.material.color.set( isExist()?0xff0000:0xffffff ) } }
const sphereMesh = new THREE.Mesh( new THREE.SphereGeometry(0.4, 4, 2), new THREE.MeshBasicMaterial({ color: 0xFFEF00, wireframe:true }) ) window.onmousedown = e => { if (!isExist()) { const sphere = sphereMesh.clone() sphere.position.copy(highLight.position) scene.add(sphere) objects.push(sphere) highLight.material.color.set(0xff0000) } }
|
动画效果
1 2 3 4 5 6 7 8 9
| function animate(time) { highLight.material.opacity = 1 + Math.sin(time / 120) objects.forEach(obj => { obj.rotation.x = time / 1000 obj.rotation.z = time / 1000 obj.position.y = 0.5 + 0.5 * Math.abs(Math.sin(time/1000)) }) renderer.render(scene, camera); }
|