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