0


Three.js中的Raycasting技术:实现3D场景交互事件的Raycaster详解

前言

Web

开发中,

Three.js

是一个极为强大的库,它让开发者能够轻松地在浏览器中创建和展示

3D

图形。随着

3D

技术在网页设计、游戏开发、数据可视化等领域的广泛应用,用户与3D场景的交互变得日益重要。而要实现这种交互,一个核心的技术就是光线投射(

Raycasting

)。通过

Three.js

提供的

Raycaster

类,我们可以检测鼠标或触摸事件在

3D

空间中的对应位置,进而实现点击、悬停等交互效果。本文将深入探讨如何使用

Three.js

Raycaster

来实现

3D

场景的交互事件。
光线投射原理及其属性介绍

通过Raycaster拾取模型进行轮廓高亮走这里>>>

什么是Raycasting?

Raycasting

是一种计算机图形学技术,用于确定从一个点(通常是观察者的位置或屏幕上的某一点)发射出的光线与场景中物体的交点。在

3D

应用中,这一技术常用于模拟光照效果、碰撞检测以及用户交互。简单来说,当你在屏幕上点击或触摸时,

Three.js

会从该点向场景发射一条虚拟的射线,然后检查这条射线与场景中哪些对象相交,从而判断用户点击了哪个对象。
Three.js中的Raycasting技术:实现3D场景交互事件的Raycaster详解
这个类用于进行

raycasting

(光线投射)。 光线投射用于进行鼠标拾取(在三维空间中计算出鼠标移过了什么物体)。

Three.js

中的

Raycaster

Three.js

中,

Raycaster

类是实现这一功能的关键。它允许你创建一个射线,并提供方法来检测这个射线与场景中对象的交点。以下是使用

Raycaster

的基本步骤:

Raycaster

实例解释

newTHREE.Raycaster(origin, direction, near, far)

参数说明:

origin
  • 光线投射的原点,
    Vector3
    
    类型。
direction
  • 射线的方向,
    Vector
    
    3类型。
near
  • 投射近点,不能为负值,应该小于
    far
    
    ,其默认值为
    0
    
far

投射远点,不能小于

near

,其默认值为无穷大。

射线交叉对象

创建的光线投射对象有一个

intersectObject()

方法用来获取射线交叉的对象,使用方法如下

const raycaster =newTHREE.Raycaster(origin, direction, near, far)const arr= raycaster.intersectObjects(object, recursive,optionalTarget)
raycaster.intersectObjects()

参数

object
  • 要检查的是否与射线相交的对象,
    Object3D
    
    类型。
recursive
  • 是否检查所有后代,可选默认为
    false
    
    Boolean
    
    类型。
optionalTarget
  • 可选参数,放置结果的目标数组。
    Array
    
    类型。若使用这个参数返回检查结果则在每次调用之前必须清空这个数组。

raycaster.intersectObjects()

的返回值

Three.js中的Raycasting技术:实现3D场景交互事件的Raycaster详解

distance
  • 射线投射原点和相交部分之间的距离。
point
  • 相交部分的坐标。
face
  • 相交的面。
faceIndex
  • 相交的面的索引。
object
  • 相交的物体。
uv
  • 相交部分的点的UV坐标。

光线投射示例

Three.js中的Raycasting技术:实现3D场景交互事件的Raycaster详解

示例步骤

步骤一、创建射线

const raycaster =newTHREE.Raycaster()

步骤二、用一个二维向量保存鼠标点击画布上的位置

const mouse =newTHREE.Vector2(1,1)

步骤三、监听窗口事件,将

x

,

y

轴归一化坐标,通过摄像机和鼠标的位置更新色线,计算物体和射线的焦点能不能碰到物体,碰到物体后随机改变射线照射物体的颜色。

window.addEventListener("click",(e)=>{//设置鼠标向量的x,y值,将XY轴归一化,X从-1到1,Y为从-1到1,所以除以2
  mouse.x =(e.clientX/window.innerWidth)*2-1
  mouse.y =-(e.clientY/window.innerHeight)*2+1// 通过摄像机和鼠标的位置,更新射线
  raycaster.setFromCamera(mouse,this.camera)//计算物体和射线的焦点能不能碰到物体const intersects = raycaster.intersectObjects([sphere1,sphere2,sphere3])if(intersects.length>0){
    intersects[0].object.material.color.set(this.color16())}})
代码解释:
raycaster.setFromCamera(mouse,this.camera)

每次渲染循环中,你需要更新射线的起点(通常是相机的位置)和方向(通常是基于鼠标坐标计算出的向量):这里,

mouse

是归一化设备坐标(即范围在

(-1, -1)

(1, 1)

之间的坐标),可以通过监听鼠标或触摸事件并使用

THREE.Vector2和renderer.domElement.clientWidth/Height

进行转换得到。

const intersects = raycaster.intersectObjects(scene.children,true);

使用

raycaster.intersectObjects()

方法来检测射线与场景中对象的交点:此方法返回一个数组,包含了所有与射线相交的对象信息。如果数组不为空,说明有对象被选中,你可以根据需要处理这些交点信息。

什么是归一化坐标:归一化坐标,是一个二维坐标,仅有X/Y两个维度,且X和Y的取值范围均为

[-1, 1]

,坐标原点位于

three.js

所创建的

canvas

的中心处。 ​
Three.js中的Raycasting技术:实现3D场景交互事件的Raycaster详解
归一化坐标公式:

mouse.x =((event.clientX - container.getBoundingClientRect().left)/ container.getBoundingClientRect().width)*2-1;
mouse.y =-((event.clientY - container.getBoundingClientRect().top)/ container.getBoundingClientRect().height)*2+1;

以上示例完整代码:

<template><div id="container"></div></template><script>import*asTHREEfrom'three'// webGL兼容import WebGL from'three/examples/jsm/capabilities/WebGL.js';import{GUI}from'three/examples/jsm/libs/lil-gui.module.min.js';// 轨道控制器import{ OrbitControls }from"three/examples/jsm/controls/OrbitControls.js"//导入RGBRload加载器import{ RGBELoader }from"three/examples/jsm/loaders/RGBELoader.js"//导入场景模型加载器import{GLTFLoader}from"three/examples/jsm/loaders/GLTFLoader.js"//导入模型解压器import{DRACOLoader}from"three/examples/jsm/loaders/DRACOLoader.js"exportdefault{name:'HomeView',components:{},mounted(){this.init()},data(){return{camera:null,//相机对象scene:null,//场景对象renderer:null,//渲染器对象mesh:null,//网格模型对象Meshmesh2:null,controls:null,//轨道控制器material2:null,//父元素planeMesh:null,//平面rgbeLoacer:null,}},methods:{//随机生成十六进制颜色color16(){//十六进制颜色随机var r = Math.floor(Math.random()*256);var g = Math.floor(Math.random()*256);var b = Math.floor(Math.random()*256);var color ='#'+r.toString(16)+g.toString(16)+b.toString(16);return color;},init(){let container = document.body;//创建一个场景this.scene =newTHREE.Scene()//透视摄像机this.camera =newTHREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,700)//创建渲染器this.renderer =newTHREE.WebGLRenderer();//渲染器尺寸this.renderer.setSize( window.innerWidth,  window.innerHeight );// 创建三个球const sphere1 =newTHREE.Mesh(newTHREE.SphereGeometry(1,32,32),newTHREE.MeshBasicMaterial({color:0x00ff00}))
      sphere1.position.x =-3this.scene.add(sphere1)const sphere2 =newTHREE.Mesh(newTHREE.SphereGeometry(1,32,32),newTHREE.MeshBasicMaterial({color:0xff0000}))
      sphere2.position.x =0this.scene.add(sphere2)const sphere3 =newTHREE.Mesh(newTHREE.SphereGeometry(1,32,32),newTHREE.MeshBasicMaterial({color:0x0000ff}))      
      sphere3.position.x =3this.scene.add(sphere3)//创建射线const raycaster =newTHREE.Raycaster()//用一个二维向量保存鼠标点击画布上的位置const mouse =newTHREE.Vector2(1,1)   
      window.addEventListener("click",(e)=>{//设置鼠标向量的x,y值,将XY轴归一化,X从-1到1,Y为从-1到1,所以除以2
        mouse.x =(e.clientX/window.innerWidth)*2-1
        mouse.y =-(e.clientY/window.innerHeight)*2+1
        console.log(mouse.x,mouse.y)// 通过摄像机和鼠标的位置,更新涉嫌
        raycaster.setFromCamera(mouse,this.camera)//计算物体和射线的焦点能不能碰到物体const intersects = raycaster.intersectObjects([sphere1,sphere2,sphere3])
        console.log("intersects",intersects)if(intersects.length>0){
          intersects[0].object.material.color.set(this.color16())}})this.scene.background=newTHREE.Color(0x999999)// 设置相机位置this.camera.position.z =15;this.camera.position.y =2;this.camera.position.x =2;// 看的方向 this.camera.lookAt(0,0,0)//添加世界坐标辅助器const axesHelper =newTHREE.AxesHelper(3)this.scene.add( axesHelper );//添加轨道控制器this.controls =newOrbitControls(this.camera,this.renderer.domElement)//添加阻尼带有惯性this.controls.enableDamping =true//设置阻尼系数this.controls.dampingFactor =0.05//元素中插入canvas对象
      container.appendChild(this.renderer.domElement);if( WebGL.isWebGLAvailable()){this.animate();}else{const warning = WebGL.getWebGLErrorMessage();
        document.getElementById( document.body ).appendChild( warning );}},//旋转起来animate(){this.controls.update()requestAnimationFrame(this.animate );// this.mesh.rotation.x += 0.01;// this.mesh.rotation.y += 0.01;this.renderer.render(this.scene,this.camera );}}}</script>

总结

通过

Three.js

Raycaster

,我们能够以直观且高效的方式实现

3D

场景中的交互事件。无论是简单的点击反馈,还是复杂的拖拽操作,

Raycasting

都是构建互动式

3D

体验不可或缺的一部分。掌握这项技术,无疑能极大提升你的

3D

应用或游戏的用户体验。希望本文能为你开启探索

Three.js

交互世界的大门,让你的

3D

项目更加生动有趣。

标签: javascript 3d 交互

本文转载自: https://blog.csdn.net/qq_42696432/article/details/139458149
版权归原作者 天生我材必有用_吴用 所有, 如有侵权,请联系我们删除。

“Three.js中的Raycasting技术:实现3D场景交互事件的Raycaster详解”的评论:

还没有评论