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

相关推荐
四喜花露水17 分钟前
Vue 自定义icon组件封装SVG图标
前端·javascript·vue.js
前端Hardy27 分钟前
HTML&CSS: 实现可爱的冰墩墩
前端·javascript·css·html·css3
web Rookie1 小时前
JS类型检测大全:从零基础到高级应用
开发语言·前端·javascript
Au_ust1 小时前
css:基础
前端·css
帅帅哥的兜兜1 小时前
css基础:底部固定,导航栏浮动在顶部
前端·css·css3
yi碗汤园1 小时前
【一文了解】C#基础-集合
开发语言·前端·unity·c#
就是个名称1 小时前
购物车-多元素组合动画css
前端·css
编程一生2 小时前
回调数据丢了?
运维·服务器·前端
丶21362 小时前
【鉴权】深入了解 Cookie:Web 开发中的客户端存储小数据
前端·安全·web
Missmiaomiao3 小时前
npm install慢
前端·npm·node.js