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会从该点向场景发射一条虚拟的射线,然后检查这条射线与场景中哪些对象相交,从而判断用户点击了哪个对象。

这个类用于进行raycasting(光线投射)。 光线投射用于进行鼠标拾取(在三维空间中计算出鼠标移过了什么物体)。
Three.js中的Raycaster
在Three.js中,Raycaster类是实现这一功能的关键。它允许你创建一个射线,并提供方法来检测这个射线与场景中对象的交点。以下是使用Raycaster的基本步骤:
Raycaster实例解释
new THREE.Raycaster(origin, direction, near, far)
参数说明:
origin- 光线投射的原点,Vector3类型。
direction- 射线的方向,Vector3类型。
near- 投射近点,不能为负值,应该小于far,其默认值为0。
far投射远点,不能小于near,其默认值为无穷大。
射线交叉对象
创建的光线投射对象有一个intersectObject()方法用来获取射线交叉的对象,使用方法如下
const raycaster = new THREE.Raycaster(origin, direction, near, far)
const arr= raycaster.intersectObjects(object, recursive,optionalTarget)
raycaster.intersectObjects()参数
object- 要检查的是否与射线相交的对象,Object3D类型。
recursive- 是否检查所有后代,可选默认为false,Boolean类型。
optionalTarget- 可选参数,放置结果的目标数组。Array类型。若使用这个参数返回检查结果则在每次调用之前必须清空这个数组。
raycaster.intersectObjects()的返回值

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

示例步骤
步骤一、创建射线
const raycaster = new THREE.Raycaster()
步骤二、用一个二维向量保存鼠标点击画布上的位置
const mouse = new THREE.Vector2(1, 1)
步骤三、监听窗口事件,将x,y轴归一化坐标,通过摄像机和鼠标的位置更新色线,计算物体和射线的焦点能不能碰到物体,碰到物体后随机改变射线照射物体的颜色。
window.addEventListener("click",(e)=>{//设置鼠标向量的x,y值,将XY轴归一化,X从-1到1,Y为从-1到1,所以除以2mouse.x = (e.clientX/window.innerWidth)*2-1mouse.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的中心处。

归一化坐标公式:
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 * as THREE from '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"
export default {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 = new THREE.Scene()//透视摄像机this.camera = new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,700)//创建渲染器this.renderer = new THREE.WebGLRenderer();//渲染器尺寸this.renderer.setSize( window.innerWidth, window.innerHeight ); // 创建三个球const sphere1 = new THREE.Mesh(new THREE.SphereGeometry(1,32,32),new THREE.MeshBasicMaterial({color:0x00ff00}))sphere1.position.x = -3this.scene.add(sphere1)const sphere2 = new THREE.Mesh(new THREE.SphereGeometry(1,32,32),new THREE.MeshBasicMaterial({color:0xff0000}))sphere2.position.x = 0this.scene.add(sphere2)const sphere3 = new THREE.Mesh(new THREE.SphereGeometry(1,32,32),new THREE.MeshBasicMaterial({color:0x0000ff})) sphere3.position.x = 3this.scene.add(sphere3)//创建射线const raycaster = new THREE.Raycaster()//用一个二维向量保存鼠标点击画布上的位置const mouse = new THREE.Vector2(1, 1) window.addEventListener("click",(e)=>{//设置鼠标向量的x,y值,将XY轴归一化,X从-1到1,Y为从-1到1,所以除以2mouse.x = (e.clientX/window.innerWidth)*2-1mouse.y = -(e.clientY/window.innerHeight)*2+1console.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=new THREE.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 = new THREE.AxesHelper(3) this.scene.add( axesHelper );//添加轨道控制器this.controls = new OrbitControls(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项目更加生动有趣。
相关文章:
Three.js中的Raycasting技术:实现3D场景交互事件的Raycaster详解
前言 在Web开发中,Three.js是一个极为强大的库,它让开发者能够轻松地在浏览器中创建和展示3D图形。随着3D技术在网页设计、游戏开发、数据可视化等领域的广泛应用,用户与3D场景的交互变得日益重要。而要实现这种交互,一个核心的技…...
5 分钟内构建一个简单的基于 Python 的 GAN
文章目录 一、说明二、代码三、训练四、后记 一、说明 生成对抗网络(GAN)因其能力而在学术界引起轩然大波。机器能够创作出新颖、富有灵感的作品,这让每个人都感到敬畏和恐惧。因此,人们开始好奇,如何构建一个这样的网…...
智能硬件产品中常用的参数存储和管理方案
一、有哪些参数需要管理? 在智能硬件产品中,一般有三类数据需要存储并管理: 1. 系统设置数据 系统设置数据是指产品自身正常工作所依赖的一些参数。 这类数据的特点:只能在生产过程中修改,出厂后用户无权限修改。 比如:产品SN、产品密钥/token/license、传感器校准值…...
SwiftUI中Mask修饰符的理解与使用
Mask是一种用于控制图形元素可见性的图形技术,使用给定视图的alpha通道掩码该视图。在SwiftUI中,它类似于创建一个只显示视图的特定部分的模板。 Mask修饰符的定义: func mask<Mask>(alignment: Alignment .center,ViewBuilder _ ma…...
全光网络与传统网络架构的对比分析
随着信息技术的飞速发展,网络已经成为我们日常生活中不可或缺的一部分。在这个信息爆炸的时代,全光网络和传统网络架构作为两种主流的网络技术,各有其特点和适用范围。本文将对这两种网络架构进行详细的对比分析,帮助读者更好地了…...
stack overflow复现
当你在内存的栈中,存放了太多元素,就有可能在造成 stack overflow这个问题。 今天看看如何复现这个问题。 下图,是我写的程序,不断的创造1KB的栈,来看看执行了多少次,无限循环。 最后结果是7929kB时, 发…...
mybatis使用笔记
文章目录 打印sql日志mybatis-config.xml方式application.yml里面配置配置类配置方式 其他扫描方式官网文档 mybatis用了那么久,实际一直不明白,做个笔记吧。 打印sql日志 实测,mybatis-config.xml方式好用(记得注掉yml里的相关配置) mybat…...
学习笔记——路由网络基础——路由概述
一、路由概述 1、路由定义与作用 路由(routing)是指导报文转发路径信息,通过路由可以确认转发IP报文的路径。 路由:是指路由器从一个接口上收到数据包,根据数据包的目的地址进行定向并转发到另一个接口的过程。 路由(routing)的定义是指分…...
在量子计算时代,大数据技术将面临哪些挑战和机遇?
在量子计算时代,大数据技术将面临以下挑战和机遇: 挑战: 处理速度:量子计算机具有极高的计算速度,大数据技术需要适应和充分利用这种速度。现有的大数据算法和架构可能需要重新设计和优化,以充分发挥量子计…...
怎么换自己手机的ip地址
在互联网时代,IP地址已经成为了我们数字身份的一部分。无论是浏览网页、下载文件还是进行在线交流,我们的IP地址都在默默发挥着作用。然而,有时出于安全或隐私保护的考虑,我们可能需要更换手机的IP地址。那么,如何轻松…...
搭建 Langchain-Chatchat 详细过程
前言 本文参考官网和其他多方教程,将搭建 Langchain-Chatchat 的详细步骤进行了整理,供大家参考。 我的硬件 4090 显卡win10 专业版本 搭建环境使用 chatglm2-6b 模型 1. 创建虚拟环境 chatchat ,python 3.9 以上 conda create -n chat…...
C++期末复习
目录 1.基本函数 2.浅拷贝和深拷贝 3.初始化列表 4.const关键字的使用 5.静态成员变量和成员函数 6.C对象模型 7.友元 8.自动类型转换 9.继承 1.基本函数 (1)构造函数,这个需要注意的就是我们如果使用类名加括号,括号里面…...
2005-2022年各省居民人均消费支出数据(无缺失)
2005-2022年各省居民人均消费支出数据(无缺失) 1、时间:2005-2022年 2、来源:国家统计局、统计年鉴 3、指标:全体居民人均消费支出 4、范围:31省 5、缺失情况:无缺失 6、指标解释 居民人…...
swaggerHole:针对swaggerHub的公共API安全扫描工具
关于swaggerHole swaggerHole是一款针对swaggerHub的API安全扫描工具,该工具基于纯Python 3开发,可以帮助广大研究人员检索swaggerHub上公共API的相关敏感信息,整个任务过程均以自动化形式实现,且具备多线程特性和管道模式。 工具…...
【Rust】——面向对象设计模式的实现
🎼个人主页:【Y小夜】 😎作者简介:一位双非学校的大二学生,编程爱好者, 专注于基础和实战分享,欢迎私信咨询! 🎆入门专栏:🎇【MySQL࿰…...
C#朗读语音
最近有个需求,需要在C#程序发生异常时候,朗读文字,C#提供了.net framework可以提供简单的语音朗读功能。 引入依赖 using System.Media; using System.Speech.Synthesis; using System.Runtime.InteropServices; //报警音量 SystemSounds.…...
c++ 简单的日志类 CCLog
此日志类,简单地实现了向标准输出控制台和文件输出日志信息的功能,并能在这两者之间进行切换输出,满足输出日志的不同需求。 代码如下: /** CCLog.h* c_common_codes** Created by xichen on 12-1-12.* Copyright 2012 cc_te…...
一文读懂 Compose 支持 Accessibility 无障碍的原理
前言 众所周知,Compose 作为一种 UI 工具包,向开发者提供了实现 UI 的基本功能。但其实它还默默提供了很多其他能力,其中之一便是今天需要讨论的:Android 特色的 Accessibility 功能。 采用 Compose 搭建的界面,完美…...
Redis到底支不支持事务?
文章目录 一、概述二、使用1、正常执行:2、主动放弃事务3、全部回滚:4、部分支持事务:5、WATCH: 三、事务三阶段四、小结 redis是支持事务的,但是它与传统的关系型数据库中的事务是有所不同的 一、概述 概念: 可以一次执行多个命令,本质是一…...
美颜相机「BeautyCam」v12.0.80 祛广告解索会员版(美妆相机功能,展现女神魅力)
软件介绍 美颜相机,一款由知名移动互联网企业Meitu Inc.开发的移动设备照片编辑与美化应用,起初主要针对娱乐消费市场,随后集成了商业营销功能。目前,它已跻身全球最受欢迎的手机摄影应用程序之列。在中国,美颜相机和…...
第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...
从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...
NPOI Excel用OLE对象的形式插入文件附件以及插入图片
static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...
R 语言科研绘图第 55 期 --- 网络图-聚类
在发表科研论文的过程中,科研绘图是必不可少的,一张好看的图形会是文章很大的加分项。 为了便于使用,本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中,获取方式: R 语言科研绘图模板 --- sciRplothttps://mp.…...
【堆垛策略】设计方法
堆垛策略的设计是积木堆叠系统的核心,直接影响堆叠的稳定性、效率和容错能力。以下是分层次的堆垛策略设计方法,涵盖基础规则、优化算法和容错机制: 1. 基础堆垛规则 (1) 物理稳定性优先 重心原则: 大尺寸/重量积木在下…...
【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...
自定义线程池1.2
自定义线程池 1.2 1. 简介 上次我们实现了 1.1 版本,将线程池中的线程数量交给使用者决定,并且将线程的创建延迟到任务提交的时候,在本文中我们将对这个版本进行如下的优化: 在新建线程时交给线程一个任务。让线程在某种情况下…...
iOS 项目怎么构建稳定性保障机制?一次系统性防错经验分享(含 KeyMob 工具应用)
崩溃、内存飙升、后台任务未释放、页面卡顿、日志丢失——稳定性问题,不一定会立刻崩,但一旦积累,就是“上线后救不回来的代价”。 稳定性保障不是某个工具的功能,而是一套贯穿开发、测试、上线全流程的“观测分析防范”机制。 …...
