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

相关推荐
huabuyu13 分钟前
基于 React + MarkdownIt 的 Markdown 渲染器实践:支持地图标签和长按复制
前端
芦苇Z15 分钟前
HTML <a> 标签的 rel 属性全解析:安全、隐私与 SEO 最佳实践
前端·html
在这儿不行19 分钟前
Android 15边到边模式
前端
源猿人22 分钟前
企业级文件浏览系统的Vue实现:架构设计与最佳实践
前端·javascript·数据可视化
红红大虾22 分钟前
Defold引擎中关于CollectionProxy的使用
前端·游戏开发
最后一个农民工27 分钟前
vue3实现仿豆包模版式智能输入框
前端·vue.js
xw51 小时前
uni-app中v-if使用”异常”
前端·uni-app
!win !1 小时前
uni-app中v-if使用”异常”
前端·uni-app
IT_陈寒2 小时前
Java 性能优化:5个被低估的JVM参数让你的应用吞吐量提升50%
前端·人工智能·后端