three.js -- 光线投射,鼠标事件监听

626 阅读2分钟

光线相交部分,光线投射用于进行鼠标拾取(在三维空间中计算出鼠标移过了什么物体)。

知识点:

  1. const raycaster = new THREE.Raycaster()
  2. raycaster.set(rayOrigin, rayDirection)
  3. raycaster.intersectObject([a,b,c, 经过光线的物体数组])
  4. raycaster.setFromCamera(mouse, camera)
// 创建一个光线投射
const raycaster = new THREE.Raycaster()

// 在动画函数中将处在光线上的物体变色
const clock = new THREE.Clock()
const tick = () => {
  // 三个小球做不同速度的运动
  const elapsedTime = clock.getElapsedTime()
  object1.position.y = Math.sin(elapsedTime * 0.3) * 1.5
  object2.position.y = Math.sin(elapsedTime * 0.3) * 1.5
  object3.position.y = Math.sin(elapsedTime * 0.3) * 1.5
  
  // 定义光线方向的两个点 创建向量
  const rayOrigin = new THREE.Vector3(-3, 0, 0)
  const rayDirection = new THREE.Vector3(1, 0, 0)
  rayDirection.normalize() /* 三维向量处理成同方向 */
  
  // 使用一个新的原点和方向来更新射线。
  raycaster.set(rayOrigin, rayDirection)
  
  // 将三个几个球体合并到一个数组中
  const objectsToTest = [object1, object2, object3]
  // 该方法返回一个包含有交叉部分的数组
  const intersects = raycaster.intersectObject(objectsToTest)
  
  // 先将所有的变为初始色
  for(const object of objectsToTest) {
    object.material.color.set('#ff0000')
  }
  // 将交叉部分的颜色变蓝
  for(const intersect of intersects) {
    intersect.object.material.color.set('#0000fff')
  }
  
}

判断鼠标事件

// 监听鼠标事件,并将鼠标的移动值规范在-1——1之间
const mouse = new THREE.Vector2() /* 创建二维向量保存鼠标值 */
const currentIntersect = null /* 控制鼠标是否进入几何体的开关 */

// 鼠标移动
window.addEventListener('mousemove', (event) => {
  mouse.x = event.clientX / window.innerWidth * 2 -1
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1
})

// 点击事件
window.addEventListener('click', () => {
    if(currentIntersect) {
        switch(currentIntersect.object) {
          case object1:
            console.log('点击了第一个小球')
            break
          case object2:
            console.log('点击了第二个小球')
            break
          case object3:
            console.log('点击了第三个小球')
            break
        }
    }
})

// 动画函数
const tick = () => {
  // 三个小球做不同速度的运动
  const elapsedTime = clock.getElapsedTime()
  object1.position.y = Math.sin(elapsedTime * 0.3) * 1.5
  object2.position.y = Math.sin(elapsedTime * 0.3) * 1.5
  object3.position.y = Math.sin(elapsedTime * 0.3) * 1.5
  
  // 使用一个新的原点和方向来更新射线。
  raycaster.setFromCamera(mouse, camera)
  
  const objectsToTest = [object1, object2, object3]
  const intersects = raycaster.intersectObject(objectsToTest)
  
  for(const object of objectsToTest) {
  	object.material.color.set('#ff0000')
  }
  for(const intersect of intersects) {
  	intersect.object.material.color.set('#0000fff')
  }
  
  // 通过光线是否有相交的物体判断光标是否在物体上
  if(intersects.length) {
    if(currentIntersect === null) {
    	console.log('鼠标进入')
    }else {
    	console.log('鼠标悬停')
    }
    currentIntersect = intersects[0]
  }else {
    if(currentIntersect) {
    	console.log('鼠标离开')
    }
    currentIntersect = null
  }
}