news 2026/5/25 14:37:46

Raycaster(鼠标点击选中模型)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Raycaster(鼠标点击选中模型)

Three.js Raycaster(射线投射器)鼠标点击选中模型笔记

一、Raycaster 简介

Raycaster(射线投射器)是Three.js中用于实现**鼠标拾取(3D对象选择)**的核心类。它通过从相机位置发射一条射线,检测与哪些3D对象相交,从而实现点击选中功能。

二、实现步骤详解

1. 监听点击事件

addEventListener("click",(e)=>{// 获取鼠标在浏览器窗口中的像素坐标constpx=e.offsetX;// 鼠标X坐标constpy=e.offsetY;// 鼠标Y坐标});

2. 坐标转换(关键步骤)

将屏幕像素坐标转换为Three.js的归一化设备坐标(NDC)

  • NDC范围:X轴[-1, 1],Y轴[-1, 1],原点在屏幕中心
  • 屏幕坐标范围:X轴[0, window.innerWidth],Y轴[0, window.innerHeight],原点在左上角
constx=(px/window.innerWidth)*2-1;// 转换到[-1, 1]consty=-(py/window.innerHeight)*2+1;// 转换到[-1, 1],Y轴需要取反

3. 创建并设置Raycaster

// 创建射线投射器constraycaster=newTHREE.Raycaster();// 设置射线的起点和方向// setFromCamera()方法:从相机位置发射射线,方向指向鼠标点击的3D空间点raycaster.setFromCamera(newTHREE.Vector2(x,y),camera);

4. 检测相交物体

// intersectObjects()方法检测射线与哪些物体相交// 参数:要检测的物体数组constintersects=raycaster.intersectObjects([cube,cube2,cube3]);// intersects返回一个数组,包含所有相交的物体信息,按距离从近到远排序

5. 处理选中结果

if(intersects.length>0){// 获取第一个(最近)相交的物体constselectedObject=intersects[0].object;// 修改物体材质颜色selectedObject.material.color.set(Math.random()*0xffffff);}console.log(intersects);// 查看详细的相交信息

三、intersects 对象详解

intersects数组中的每个元素包含以下属性:

{distance:距离相机的距离,point:相交点的3D坐标(Vector3),face:相交的面(Face3),faceIndex:面的索引,object:相交的3D对象,uv:纹理坐标}

四、完整代码流程

  1. 事件监听→ 监听鼠标点击事件
  2. 坐标获取→ 获取鼠标在屏幕上的像素位置
  3. 坐标转换→ 像素坐标 → 归一化设备坐标(NDC)
  4. 射线创建→ 实例化Raycaster
  5. 射线设置→ 从相机向鼠标点击的3D方向发射射线
  6. 相交检测→ 检测射线与指定物体的交点
  7. 结果处理→ 处理选中的物体(如改变颜色)

五、注意事项

  1. 坐标转换:Y轴需要取反,因为屏幕坐标原点在左上角,而Three.js坐标原点在中心
  2. 性能优化:如果场景中有大量物体,应避免检测所有物体,可以:
    • 分组检测
    • 使用BVH(包围盒层次结构)加速
  3. 多物体选择intersects数组包含所有相交物体,可以支持多选功能
  4. 相机类型:适用于PerspectiveCamera(透视相机)和OrthographicCamera(正交相机)

六、实际应用场景

  • 3D编辑器中的对象选择
  • 游戏中的物品拾取
  • 交互式3D可视化
  • VR/AR中的手势选择

七、示例代码片段

// 简化的Raycaster使用示例functiononMouseClick(event){// 1. 获取鼠标位置constmouse=newTHREE.Vector2();mouse.x=(event.clientX/window.innerWidth)*2-1;mouse.y=-(event.clientY/window.innerHeight)*2+1;// 2. 创建射线constraycaster=newTHREE.Raycaster();raycaster.setFromCamera(mouse,camera);// 3. 检测相交constintersects=raycaster.intersectObjects(scene.children);// 4. 处理结果if(intersects.length>0){constselectedObject=intersects[0].object;// 执行选中操作...}}<template><divclass="container"ref="containerRef"></div></template><script setup>import{onMounted,ref}from"vue";import*asTHREEfrom"three";import{OrbitControls}from"three/examples/jsm/controls/OrbitControls";constcontainerRef=ref(null);// 创建3D场景对象Sceneconstscene=newTHREE.Scene();// 实例化一个透视投影相机对象constcamera=newTHREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,1000);// 实例化一个WebGL渲染器constrenderer=newTHREE.WebGLRenderer({antialias:true});//设置Canvas画布尺寸.setSize()renderer.setSize(window.innerWidth,window.innerHeight);//创建一个长方体几何对象Geometryconstgeometry=newTHREE.BoxGeometry(0.5,0.5,0.5);//材质Materialconstmaterial=newTHREE.MeshLambertMaterial({color:0x0000ff,//设置材质颜色});//物体:网格模型Meshconstcube=newTHREE.Mesh(geometry,material);//设置网格模型在三维空间中的位置坐标,默认是坐标原点cube.position.set(0,0,0);//在threejs中你创建了一个表示物体的虚拟对象Mesh,需要通过.add()方法,把网格模型mesh添加到三维场景scene中。scene.add(cube);//再创建两个立方体constgeometry2=newTHREE.BoxGeometry(0.5,0.5,0.5);constmaterial2=newTHREE.MeshLambertMaterial({color:0x00ff00,});constcube2=newTHREE.Mesh(geometry2,material2);cube2.position.set(0.5,0.5,0.5);scene.add(cube2);constgeometry3=newTHREE.BoxGeometry(0.5,0.5,0.5);constmaterial3=newTHREE.MeshLambertMaterial({color:0xff0000,});constcube3=newTHREE.Mesh(geometry3,material3);cube3.position.set(0.5,-0.5,-0.5);scene.add(cube3);//环境光constAmbientLight=newTHREE.AmbientLight(0xffffff,0.4)// 创建环境光scene.add(AmbientLight)// 将环境光添加到场景//Directional LightconstdirectionalLight=newTHREE.DirectionalLight(0xffffff,0.8);// 设置光源的方向:通过光源position属性和目标指向对象的position属性计算directionalLight.position.set(100,75,30);// 方向光指向对象网格模型mesh,可以不设置,默认的位置是0,0,0scene.add(directionalLight);//相机在Three.js三维坐标系中的位置camera.position.set(0,0,2);camera.lookAt(0,0,2);constaxesHelper=newTHREE.AxesHelper(150);scene.add(axesHelper);functionanimate(){requestAnimationFrame(animate);//.x是围绕X转cube.rotation.x+=0.01;//.y是围绕X转cube.rotation.y+=0.01;renderer.render(scene,camera);}animate();addEventListener("click",(e)=>{// 获取鼠标位置constpx=e.offsetXconstpy=e.offsetY// 转换坐标 归一化设备坐标NDCconstx=(px/window.innerWidth)*2-1consty=-(py/window.innerHeight)*2+1// 创建射线投射器 Raycasterconstraycaster=newTHREE.Raycaster()// 设置射线投射位置和方向raycaster.setFromCamera(newTHREE.Vector2(x,y),camera)// 获取射线选中的物体constintersects=raycaster.intersectObjects([cube,cube2,cube3])if(intersects.length>0){// 改变颜色intersects[0].object.material.color.set(Math.random()*0xffffff)}console.log(intersects)});// 挂载完毕 获取domonMounted(()=>{// 相机控间constcontros=newOrbitControls(camera,containerRef.value);contros.enableDamping=true;containerRef.value.appendChild(renderer.domElement);});</script>
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/25 2:30:50

文理分科选对学习机:主流机型的适配指南

一、文理分科下&#xff0c;学习机选择的核心逻辑高中文科重知识体系构建、材料分析与表达输出&#xff0c;理科强逻辑拆解、错题闭环与实验理解&#xff0c;二者对学习机的需求存在本质差异&#xff1a;文科刚需&#xff1a;教材同步讲解的细致度、海量题库的分类检索&#xf…

作者头像 李华
网站建设 2026/5/25 12:18:20

深入探索 Spring Boot3 中 Profiles 多环境配置

前言在当今复杂的软件开发领域&#xff0c;一个应用往往需要在开发、测试、生产等多个环境中运行&#xff0c;每个环境的配置需求大相径庭。想象一下&#xff0c;在开发环境中&#xff0c;你可能需要频繁调试&#xff0c;所以希望日志更加详细&#xff0c;数据库连接到本地易于…

作者头像 李华
网站建设 2026/5/24 22:04:22

Wan2.2-T2V-A14B能否理解隐喻性语言?‘心如刀割’如何呈现?

Wan2.2-T2V-A14B能否理解“心如刀割”&#xff1f;当AI开始读懂你心里的痛 &#x1f494; 你有没有试过把一句诗、一段情绪&#xff0c;丢进AI视频生成器里&#xff0c;然后期待它“懂你”&#xff1f; 比如输入“心如刀割”——不是字面意思的心脏被刀切开&#xff0c;而是一种…

作者头像 李华
网站建设 2026/5/23 7:05:24

spRAG开源项目:5分钟快速安装与使用终极指南

spRAG开源项目&#xff1a;5分钟快速安装与使用终极指南 【免费下载链接】spRAG RAG framework for challenging queries over dense unstructured data 项目地址: https://gitcode.com/gh_mirrors/sp/spRAG spRAG开源项目是一个专为处理复杂非结构化数据设计的检索增强…

作者头像 李华
网站建设 2026/5/23 22:25:36

【运维】StarRocks 跨集群数据迁移工具 - 基于快照进行的快速迁移

文章目录一、整体迁移逻辑1.1 架构概览1.2 核心工作流程阶段 1&#xff1a;初始化阶段 2&#xff1a;启动工作线程阶段 3&#xff1a;周期性执行1.3 任务生成逻辑1.3.1 元数据同步1.3.2 DDL 任务生成1.3.3 数据复制任务生成1.4 任务执行流程1.4.1 DDL 任务执行1.4.2 数据复制任…

作者头像 李华
网站建设 2026/5/24 14:44:54

8 个继续教育答辩工具,AI PPT优化推荐

8 个继续教育答辩工具&#xff0c;AI PPT优化推荐 论文路上的“三座大山”&#xff1a;时间、重复率与效率 对于继续教育的学生来说&#xff0c;毕业答辩不仅是学术生涯的重要节点&#xff0c;更是对个人综合能力的一次全面检验。然而&#xff0c;在这个过程中&#xff0c;论文…

作者头像 李华