Three.js第九课-光影投射Raycaster

光影投射

  • 定义:光影投射(Raycaster)是一个用来进行射线投射和交叉检测的类
  • 原理:通过射线,来判断能不能击中对应的物体,拿到对应的交点
  • 作用:它可以用于鼠标拾取、碰撞检测等多种场景
  • 使用场景:当我们想要获取到场景内的某个物体时,我们就需要使用光影投射技术
  • 应用举例:比如说,屏幕中有三个汽车,当我点击某个汽车时,其材质颜色就变为红色

图解

使用

创建物体
php 复制代码
const ball1=new Three.Mesh(new Three.SphereGeometry(1,16,16),new Three.MeshBasicMaterial({color:'blue'}))
const ball2=new Three.Mesh(new Three.SphereGeometry(1,16,16),new Three.MeshBasicMaterial({color:'yellow'}))
const ball3=new Three.Mesh(new Three.SphereGeometry(1,16,16),new Three.MeshBasicMaterial({color:'green'}))
ball1.position.x=-2
ball2.position.x=0
ball3.position.x=2
scene.add(ball1)
scene.add(ball2)
scene.add(ball3)
scene.background=new Three.Color('white')
创建射线
arduino 复制代码
const raycaster=new Three.Raycaster()
创建鼠标向量
arduino 复制代码
const mouse=new Three.Vector2()
监听点击事件
scss 复制代码
window.addEventListener('click',(event)=>{
    // 获取屏幕的x,y
    // console.log(event.clientX,event.clientY);
    // 计算出坐标中的x,y
    mouse.x=(event.clientX/window.innerWidth)*2-1
    mouse.y=-((event.clientY/window.innerHeight)*2-1)
    // 设置射线setFromCamera(坐标点,相机位置)
    raycaster.setFromCamera(mouse,camera)
    // 检测射线是否碰到物体intersectObjects(物体)
    const intersect=raycaster.intersectObjects([ball1,ball2,ball3])
    console.log(intersect);
    if(intersect.length>0){
        if(intersect[0].object._isSelect){
            intersect[0].object._isSelect=false
            intersect[0].object.material.color.set(intersect[0].object._originColor)
        }else{
        // 标识是否被选中
        intersect[0].object._isSelect=true
        // 存储颜色值color.getHex()
        intersect[0].object._originColor=intersect[0].object.material.color.getHex()
        // 设置颜色
        intersect[0].object.material.color.set("red")
        } 
    }
})
计算坐标的X和Y
javascript 复制代码
window.addEventListener('click',(event)=>{
    // 获取屏幕的x,y
    // console.log(event.clientX,event.clientY);
    // 计算出坐标中的x,y
    mouse.x=(event.clientX/window.innerWidth)*2-1
    mouse.y=-((event.clientY/window.innerHeight)*2-1)
})
设置射线

设置射线setFromCamera(坐标点,相机位置)

scss 复制代码
raycaster.setFromCamera(mouse,camera)
检测射线是否碰到物体

检测射线焦点intersectObjects(物体)

ini 复制代码
const intersect=raycaster.intersectObjects([ball1,ball2,ball3])
console.log(intersect);
  • distance为相机到物体的距离
  • face为射线照射到的面
  • object为射线照射到的物体
  • normal为射中点的法向向量
  • point为射中的点的坐标
  • uv为映射关系,对应着纹理坐标系中的横轴和纵轴
设置点击换色
csharp 复制代码
    if(intersect.length>0){
        if(intersect[0].object._isSelect){
            intersect[0].object._isSelect=false
            intersect[0].object.material.color.set(intersect[0].object._originColor)
        }else{
        // 标识是否被选中
        intersect[0].object._isSelect=true
        // 存储颜色值color.getHex()
        intersect[0].object._originColor=intersect[0].object.material.color.getHex()
        // 设置颜色
        intersect[0].object.material.color.set("red")
        } 
    }
全代码
php 复制代码
import * as Three from 'three'
 // 导入轨道控制器
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls'

const scene=new Three.Scene()
const camera=new Three.PerspectiveCamera(
    45,
    window.innerWidth/window.innerHeight,
    0.1,
    1000
)
const render=new Three.WebGLRenderer()
render.setSize(window.innerWidth,window.innerHeight)
document.body.appendChild(render.domElement)

// 创建物体
const ball1=new Three.Mesh(new Three.SphereGeometry(1,16,16),new Three.MeshBasicMaterial({color:'blue'}))
const ball2=new Three.Mesh(new Three.SphereGeometry(1,16,16),new Three.MeshBasicMaterial({color:'yellow'}))
const ball3=new Three.Mesh(new Three.SphereGeometry(1,16,16),new Three.MeshBasicMaterial({color:'green'}))
ball1.position.x=-2
ball2.position.x=0
ball3.position.x=2
scene.add(ball1)
scene.add(ball2)
scene.add(ball3)
scene.background=new Three.Color('white')
// 创建射线
const raycaster=new Three.Raycaster()
// 创建鼠标向量
const mouse=new Three.Vector2()
// 获取点击事件
window.addEventListener('click',(event)=>{
    // 获取屏幕的x,y
    // console.log(event.clientX,event.clientY);
    // 计算出坐标中的x,y
    mouse.x=(event.clientX/window.innerWidth)*2-1
    mouse.y=-((event.clientY/window.innerHeight)*2-1)
    // 设置射线setFromCamera(坐标点,相机位置)
    raycaster.setFromCamera(mouse,camera)
    // 检测射线是否碰到物体intersectObjects(物体)
    const intersect=raycaster.intersectObjects([ball1,ball2,ball3])
    console.log(intersect);
    if(intersect.length>0){
        if(intersect[0].object._isSelect){
            intersect[0].object._isSelect=false
            intersect[0].object.material.color.set(intersect[0].object._originColor)
        }else{
        // 标识是否被选中
        intersect[0].object._isSelect=true
        // 存储颜色值color.getHex()
        intersect[0].object._originColor=intersect[0].object.material.color.getHex()
        // 设置颜色
        intersect[0].object.material.color.set("red")
        } 
    }
})
// 设置相机位置
camera.position.set(2, 2, 5);
camera.lookAt(0, 0, 0)
const axesHelper=new Three.AxesHelper(6)
// 添加到场景中
scene.add(axesHelper)

// 添加轨道控制器
const controls=new OrbitControls(camera,render.domElement)
controls.enableDamping=true
controls.dampingFactor=0.05


// 渲染函数
function animate() {
    controls.update()
    requestAnimationFrame(animate)
    render.render(scene, camera)
}
animate()

// 响应式窗口
window.addEventListener('resize',()=>{
    render.setSize(window.innerWidth,window.innerHeight)
    camera.aspect=window.innerWidth/window.innerHeight
    camera.updateProjectionMatrix();
})

借助Raycaster技术,我们可以实现一些交互效果,比如点击选中物体、拖拽物体、碰撞检测等。通过不断更新射线的起点和方向,配合相交检测,我们可以实现丰富的光影投射效果,提升三维场景的交互性和真实感.

相关推荐
让开,我要吃人了2 小时前
HarmonyOS开发实战(5.0)实现二楼上划进入首页效果详解
前端·华为·程序员·移动开发·harmonyos·鸿蒙·鸿蒙系统
everyStudy3 小时前
前端五种排序
前端·算法·排序算法
甜兒.4 小时前
鸿蒙小技巧
前端·华为·typescript·harmonyos
Jiaberrr8 小时前
前端实战:使用JS和Canvas实现运算图形验证码(uniapp、微信小程序同样可用)
前端·javascript·vue.js·微信小程序·uni-app
everyStudy8 小时前
JS中判断字符串中是否包含指定字符
开发语言·前端·javascript
城南云小白8 小时前
web基础+http协议+httpd详细配置
前端·网络协议·http
前端小趴菜、8 小时前
Web Worker 简单使用
前端
web_learning_3218 小时前
信息收集常用指令
前端·搜索引擎
tabzzz8 小时前
Webpack 概念速通:从入门到掌握构建工具的精髓
前端·webpack
200不是二百8 小时前
Vuex详解
前端·javascript·vue.js