当前位置: 首页 > news >正文

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

前言

Web开发中,Three.js是一个极为强大的库,它让开发者能够轻松地在浏览器中创建和展示3D图形。随着3D技术在网页设计、游戏开发、数据可视化等领域的广泛应用,用户与3D场景的交互变得日益重要。而要实现这种交互,一个核心的技术就是光线投射(Raycasting)。通过Three.js提供的Raycaster类,我们可以检测鼠标或触摸事件在3D空间中的对应位置,进而实现点击、悬停等交互效果。本文将深入探讨如何使用Three.jsRaycaster来实现3D场景的交互事件。
光线投射原理及其属性介绍

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

什么是Raycasting?

Raycasting是一种计算机图形学技术,用于确定从一个点(通常是观察者的位置或屏幕上的某一点)发射出的光线与场景中物体的交点。在3D应用中,这一技术常用于模拟光照效果、碰撞检测以及用户交互。简单来说,当你在屏幕上点击或触摸时,Three.js会从该点向场景发射一条虚拟的射线,然后检查这条射线与场景中哪些对象相交,从而判断用户点击了哪个对象。
Three.js中的Raycasting技术:实现3D场景交互事件的Raycaster详解
这个类用于进行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 - 是否检查所有后代,可选默认为falseBoolean类型。
optionalTarget - 可选参数,放置结果的目标数组。Array类型。若使用这个参数返回检查结果则在每次调用之前必须清空这个数组。

raycaster.intersectObjects()的返回值

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

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

光线投射示例

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

示例步骤

步骤一、创建射线

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的中心处。 ​
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 * 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.jsRaycaster,我们能够以直观且高效的方式实现3D场景中的交互事件。无论是简单的点击反馈,还是复杂的拖拽操作,Raycasting都是构建互动式3D体验不可或缺的一部分。掌握这项技术,无疑能极大提升你的3D应用或游戏的用户体验。希望本文能为你开启探索Three.js交互世界的大门,让你的3D项目更加生动有趣。

相关文章:

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

前言 在Web开发中&#xff0c;Three.js是一个极为强大的库&#xff0c;它让开发者能够轻松地在浏览器中创建和展示3D图形。随着3D技术在网页设计、游戏开发、数据可视化等领域的广泛应用&#xff0c;用户与3D场景的交互变得日益重要。而要实现这种交互&#xff0c;一个核心的技…...

5 分钟内构建一个简单的基于 Python 的 GAN

文章目录 一、说明二、代码三、训练四、后记 一、说明 生成对抗网络&#xff08;GAN&#xff09;因其能力而在学术界引起轩然大波。机器能够创作出新颖、富有灵感的作品&#xff0c;这让每个人都感到敬畏和恐惧。因此&#xff0c;人们开始好奇&#xff0c;如何构建一个这样的网…...

智能硬件产品中常用的参数存储和管理方案

一、有哪些参数需要管理? 在智能硬件产品中,一般有三类数据需要存储并管理: 1. 系统设置数据 系统设置数据是指产品自身正常工作所依赖的一些参数。 这类数据的特点:只能在生产过程中修改,出厂后用户无权限修改。 比如:产品SN、产品密钥/token/license、传感器校准值…...

SwiftUI中Mask修饰符的理解与使用

Mask是一种用于控制图形元素可见性的图形技术&#xff0c;使用给定视图的alpha通道掩码该视图。在SwiftUI中&#xff0c;它类似于创建一个只显示视图的特定部分的模板。 Mask修饰符的定义&#xff1a; func mask<Mask>(alignment: Alignment .center,ViewBuilder _ ma…...

全光网络与传统网络架构的对比分析

随着信息技术的飞速发展&#xff0c;网络已经成为我们日常生活中不可或缺的一部分。在这个信息爆炸的时代&#xff0c;全光网络和传统网络架构作为两种主流的网络技术&#xff0c;各有其特点和适用范围。本文将对这两种网络架构进行详细的对比分析&#xff0c;帮助读者更好地了…...

stack overflow复现

当你在内存的栈中&#xff0c;存放了太多元素&#xff0c;就有可能在造成 stack overflow这个问题。 今天看看如何复现这个问题。 下图&#xff0c;是我写的程序&#xff0c;不断的创造1KB的栈&#xff0c;来看看执行了多少次&#xff0c;无限循环。 最后结果是7929kB时, 发…...

mybatis使用笔记

文章目录 打印sql日志mybatis-config.xml方式application.yml里面配置配置类配置方式 其他扫描方式官网文档 mybatis用了那么久&#xff0c;实际一直不明白&#xff0c;做个笔记吧。 打印sql日志 实测&#xff0c;mybatis-config.xml方式好用(记得注掉yml里的相关配置) mybat…...

学习笔记——路由网络基础——路由概述

一、路由概述 1、路由定义与作用 路由(routing)是指导报文转发路径信息&#xff0c;通过路由可以确认转发IP报文的路径。 路由&#xff1a;是指路由器从一个接口上收到数据包&#xff0c;根据数据包的目的地址进行定向并转发到另一个接口的过程。 路由(routing)的定义是指分…...

在量子计算时代,大数据技术将面临哪些挑战和机遇?

在量子计算时代&#xff0c;大数据技术将面临以下挑战和机遇&#xff1a; 挑战&#xff1a; 处理速度&#xff1a;量子计算机具有极高的计算速度&#xff0c;大数据技术需要适应和充分利用这种速度。现有的大数据算法和架构可能需要重新设计和优化&#xff0c;以充分发挥量子计…...

怎么换自己手机的ip地址

在互联网时代&#xff0c;IP地址已经成为了我们数字身份的一部分。无论是浏览网页、下载文件还是进行在线交流&#xff0c;我们的IP地址都在默默发挥着作用。然而&#xff0c;有时出于安全或隐私保护的考虑&#xff0c;我们可能需要更换手机的IP地址。那么&#xff0c;如何轻松…...

搭建 Langchain-Chatchat 详细过程

前言 本文参考官网和其他多方教程&#xff0c;将搭建 Langchain-Chatchat 的详细步骤进行了整理&#xff0c;供大家参考。 我的硬件 4090 显卡win10 专业版本 搭建环境使用 chatglm2-6b 模型 1. 创建虚拟环境 chatchat &#xff0c;python 3.9 以上 conda create -n chat…...

C++期末复习

目录 1.基本函数 2.浅拷贝和深拷贝 3.初始化列表 4.const关键字的使用 5.静态成员变量和成员函数 6.C对象模型 7.友元 8.自动类型转换 9.继承 1.基本函数 &#xff08;1&#xff09;构造函数&#xff0c;这个需要注意的就是我们如果使用类名加括号&#xff0c;括号里面…...

2005-2022年各省居民人均消费支出数据(无缺失)

2005-2022年各省居民人均消费支出数据&#xff08;无缺失&#xff09; 1、时间&#xff1a;2005-2022年 2、来源&#xff1a;国家统计局、统计年鉴 3、指标&#xff1a;全体居民人均消费支出 4、范围&#xff1a;31省 5、缺失情况&#xff1a;无缺失 6、指标解释 居民人…...

swaggerHole:针对swaggerHub的公共API安全扫描工具

关于swaggerHole swaggerHole是一款针对swaggerHub的API安全扫描工具&#xff0c;该工具基于纯Python 3开发&#xff0c;可以帮助广大研究人员检索swaggerHub上公共API的相关敏感信息&#xff0c;整个任务过程均以自动化形式实现&#xff0c;且具备多线程特性和管道模式。 工具…...

【Rust】——面向对象设计模式的实现

&#x1f3bc;个人主页&#xff1a;【Y小夜】 &#x1f60e;作者简介&#xff1a;一位双非学校的大二学生&#xff0c;编程爱好者&#xff0c; 专注于基础和实战分享&#xff0c;欢迎私信咨询&#xff01; &#x1f386;入门专栏&#xff1a;&#x1f387;【MySQL&#xff0…...

C#朗读语音

最近有个需求&#xff0c;需要在C#程序发生异常时候&#xff0c;朗读文字&#xff0c;C#提供了.net framework可以提供简单的语音朗读功能。 引入依赖 using System.Media; using System.Speech.Synthesis; using System.Runtime.InteropServices; //报警音量 SystemSounds.…...

c++ 简单的日志类 CCLog

此日志类&#xff0c;简单地实现了向标准输出控制台和文件输出日志信息的功能&#xff0c;并能在这两者之间进行切换输出&#xff0c;满足输出日志的不同需求。 代码如下&#xff1a; /** CCLog.h* c_common_codes** Created by xichen on 12-1-12.* Copyright 2012 cc_te…...

一文读懂 Compose 支持 Accessibility 无障碍的原理

前言 众所周知&#xff0c;Compose 作为一种 UI 工具包&#xff0c;向开发者提供了实现 UI 的基本功能。但其实它还默默提供了很多其他能力&#xff0c;其中之一便是今天需要讨论的&#xff1a;Android 特色的 Accessibility 功能。 采用 Compose 搭建的界面&#xff0c;完美…...

Redis到底支不支持事务?

文章目录 一、概述二、使用1、正常执行&#xff1a;2、主动放弃事务3、全部回滚:4、部分支持事务:5、WATCH: 三、事务三阶段四、小结 redis是支持事务的&#xff0c;但是它与传统的关系型数据库中的事务是有所不同的 一、概述 概念: 可以一次执行多个命令&#xff0c;本质是一…...

美颜相机「BeautyCam」v12.0.80 祛广告解索会员版(美妆相机功能,展现女神魅力)

软件介绍 美颜相机&#xff0c;一款由知名移动互联网企业Meitu Inc.开发的移动设备照片编辑与美化应用&#xff0c;起初主要针对娱乐消费市场&#xff0c;随后集成了商业营销功能。目前&#xff0c;它已跻身全球最受欢迎的手机摄影应用程序之列。在中国&#xff0c;美颜相机和…...

Linux 文件类型,目录与路径,文件与目录管理

文件类型 后面的字符表示文件类型标志 普通文件&#xff1a;-&#xff08;纯文本文件&#xff0c;二进制文件&#xff0c;数据格式文件&#xff09; 如文本文件、图片、程序文件等。 目录文件&#xff1a;d&#xff08;directory&#xff09; 用来存放其他文件或子目录。 设备…...

服务器硬防的应用场景都有哪些?

服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式&#xff0c;避免服务器受到各种恶意攻击和网络威胁&#xff0c;那么&#xff0c;服务器硬防通常都会应用在哪些场景当中呢&#xff1f; 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...

MVC 数据库

MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级

在互联网的快速发展中&#xff0c;高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司&#xff0c;近期做出了一个重大技术决策&#xff1a;弃用长期使用的 Nginx&#xff0c;转而采用其内部开发…...

解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错

出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上&#xff0c;所以报错&#xff0c;到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本&#xff0c;cu、torch、cp 的版本一定要对…...

MySQL 8.0 OCP 英文题库解析(十三)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

多模态大语言模型arxiv论文略读(108)

CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题&#xff1a;CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者&#xff1a;Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

【JavaWeb】Docker项目部署

引言 之前学习了Linux操作系统的常见命令&#xff0c;在Linux上安装软件&#xff0c;以及如何在Linux上部署一个单体项目&#xff0c;大多数同学都会有相同的感受&#xff0c;那就是麻烦。 核心体现在三点&#xff1a; 命令太多了&#xff0c;记不住 软件安装包名字复杂&…...

Rapidio门铃消息FIFO溢出机制

关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系&#xff0c;以下是深入解析&#xff1a; 门铃FIFO溢出的本质 在RapidIO系统中&#xff0c;门铃消息FIFO是硬件控制器内部的缓冲区&#xff0c;用于临时存储接收到的门铃消息&#xff08;Doorbell Message&#xff09;。…...

管理学院权限管理系统开发总结

文章目录 &#x1f393; 管理学院权限管理系统开发总结 - 现代化Web应用实践之路&#x1f4dd; 项目概述&#x1f3d7;️ 技术架构设计后端技术栈前端技术栈 &#x1f4a1; 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 &#x1f5c4;️ 数据库设…...