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

相关推荐
小行星125几秒前
前端把dom页面转为pdf文件下载和弹窗预览
前端·javascript·vue.js·pdf
Lysun00110 分钟前
[less] Operation on an invalid type
前端·vue·less·sass·scss
J总裁的小芒果25 分钟前
Vue3 el-table 默认选中 传入的数组
前端·javascript·elementui·typescript
Lei_zhen9628 分钟前
记录一次electron-builder报错ENOENT: no such file or directory, rename xxxx的问题
前端·javascript·electron
咖喱鱼蛋30 分钟前
Electron一些概念理解
前端·javascript·electron
yqcoder32 分钟前
Vue3 + Vite + Electron + TS 项目构建
前端·javascript·vue.js
鑫宝Code1 小时前
【React】React Router:深入理解前端路由的工作原理
前端·react.js·前端框架
Mr_Xuhhh2 小时前
重生之我在学环境变量
linux·运维·服务器·前端·chrome·算法
永乐春秋3 小时前
WEB攻防-通用漏洞&文件上传&js验证&mime&user.ini&语言特性
前端
鸽鸽程序猿3 小时前
【前端】CSS
前端·css