Three.js 快速入门教程【十七】射线拾取模型——射线与射线投射器Raycaster介绍

请添加图片描述

系列文章目录

Three.js 快速入门教程【一】开启你的 3D Web 开发之旅
Three.js 快速入门教程【二】透视投影相机
Three.js 快速入门教程【三】渲染器
Three.js 快速入门教程【四】三维坐标系
Three.js 快速入门教程【五】动画渲染循环
Three.js 快速入门教程【六】相机控件 OrbitControls
Three.js 快速入门教程【七】常见几何体类型
Three.js 快速入门教程【八】常见材质类型
Three.js 快速入门教程【九】光源类型
Three.js 快速入门教程【十】常见的纹理类型
Three.js 快速入门教程【十一】天空盒的多种实现方式
Three.js 快速入门教程【十二】外部模型加载
Three.js 快速入门教程【十三】外部模型加载后常见的处理操作
Three.js 快速入门教程【十四】使用Stats.js监控渲染帧率和性能优化
Three.js 快速入门教程【十五】交互神器DragControls使用详解,实现对物体或模型拖拽
Three.js 快速入门教程【十六】调试神器 gui.js使用详解,可视化面板控制场景参数提高开发效率
Three.js 快速入门教程【十七】射线拾取模型——射线与射线投射器Raycaster介绍
Three.js 快速入门教程【十八】射线拾取模型——鼠标点击屏幕选中模型或物体
Three.js 快速入门教程【十九】CSS2D渲染器介绍,实现场景中物体或设备标注标签信息
Three.js 快速入门教程【二十】三维模型优化实战:使用gltf-pipeline与Draco对模型进行压缩,提高加载速度和流畅性
Three.js 快速入门教程【二十一】CSS3D渲染器(CSS3DRenderer、CSS3DObject 、CSS3DSprite)介绍,实现场景中物体标注标签信息
Three.js 快速入门教程【二十二】动画神器Tween.js使用指南



一、前言

      在 Three.js 开发的 3D 场景中,我们经常会遇到这样的需求,如何通过鼠标控制选中目标模型,这个行为也称为拾取模型。拾取模型是一个非常实用的功能,它允许用户通过鼠标点击或者触摸屏幕来选中场景中的特定模型,为交互性的 3D 应用程序增添了更多可能性。本教程将介绍射线拾取模型的相关概念和实现方法。


二、射线拾取的核心原理

在三维场景中实现点击交互,Three.js采用射线法(Raycasting)进行碰撞检测。其核心原理是:

  • 将鼠标的2D屏幕坐标转换为三维空间坐标

  • 从摄像机位置向三维空间发射一条无限延伸的射线

  • 检测这条射线与场景中物体的交点

  • 找出最近的碰撞物体进行处理

在这里插入图片描述


三、射线(Ray)

3.1 什么是射线(Ray)

在 Three.js 中,射线(Ray)是一个表示从一个点出发,沿着特定方向无限延伸的几何对象。射线可以用来模拟光线、视线等,在射线拾取模型的场景中,我们可以将射线看作是从相机位置出发,穿过屏幕上的点击点,向场景中无限延伸的一条线。
射线由一个原点(origin)和一个方向(direction)定义。原点表示射线开始的位置,通常是相机的位置;方向表示射线延伸的方向,通常是从相机位置指向屏幕上点击点的方向。

3.2 Ray 类的基本用法

在 Three.js 中,你可以使用 Ray 类来创建射线对象,如下示例:

import * as THREE from 'three';

// 创建一个原点为 (0, 0, 0),方向为 (0, 0, -1) 的射线
const origin = new THREE.Vector3(0, 0, 0);
const direction = new THREE.Vector3(0, 0, -1);
const ray = new THREE.Ray(origin, direction);

Ray构造函数第一个入参表示射线原点(可选),第二个入参表示射线方向 (可选),都为三维向量Vector3类型

也可以通过实例属性设置射线
原点和方向

// 创建射线对象Ray
const ray = new THREE.Ray()
/ 设置射线起点
ray.origin = new THREE.Vector3(1,0,1);
// 设置射线起点
ray.origin.set(1, 0, 1);

3.3 射线投射器Raycaster

射线投射器(Raycaster)是个强大的工具,它能帮助我们在 3D 场景里实现射线拾取功能,也就是判断射线和场景中的物体是否相交

3.3.1 初始化射线投射器

import * as THREE from 'three';

// 创建一个原点为 (0, 0, 0),方向为 (0, 0, -1) 的射线
const origin = new THREE.Vector3(0, 0, 0);
const direction = new THREE.Vector3(0, 0, -1);

// 创建射线投射器实例
const raycaster = new THREE.Raycaster(origin ,direction );

Raycaster构造函和Ray类似第一个入参表示射线原点(可选),第二个入参表示射线方向 (可选),都为三维向量Vector3类型

射线投射器实例有个.ray属性就是3.2 所讲的射线Ray
所以同样也可以通过实例属性设置射线原点和方向

// 创建射线投射器实例
const raycaster = new THREE.Raycaster();
const ray = raycaster.ray;
ray.origin.set(1, 1, 1);//设置原点
ray.direction.set(0, 0, -1).normalize();//设置方向

3.3.2 射线交叉计算

射线投射器实例有个intersectObject方法用于检测射线与单个物体是否相交,返回一个包含所有相交信息的数组。
同时有个intersectObjects方法用于检测射线与多个物体是否相交,返回一个包含所有相交信息的数组

(1)intersectObject方法 (单物体相交判断)

构造函数:

intersectObject(object: Object3D, recursive?: boolean, optionalTarget?: Intersection[])

功能:检测射线与单个物体是否相交,返回一个包含所有相交信息的数组。

参数:

  • object:要检测的物体,类型为 THREE.Object3D。
  • recursive:是否递归检测物体的子物体,类型为 boolean,默认值是 false。
  • optionalTarget:可选参数,用于存储相交信息的数组,类型为 THREE.Intersection[]。

返回值:包含相交信息的数组,数组元素类型为 THREE.Intersection。

示例:

const cube = new THREE.Mesh(
    new THREE.BoxGeometry(),
    new THREE.MeshBasicMaterial({ color: 0x00ff00 })
);
const intersects = raycaster.intersectObject(cube, true);
if (intersects.length > 0) {
    console.log('射线与立方体相交');
}

(2)intersectObjecst方法 (多物体相交判断)

构造函数

intersectObjects(objects: Object3D[], recursive?: boolean, optionalTarget?: Intersection[])

功能:检测射线与多个物体是否相交,返回一个包含所有相交信息的数组。

参数:

  • objects:要检测的物体数组,类型为 THREE.Object3D[]。
  • recursive:是否递归检测物体的子物体,类型为 boolean,默认值是 false。
  • optionalTarget:可选参数,用于存储相交信息的数组,类型为 THREE.Intersection[]。

返回值:包含相交信息的数组,数组元素类型为 THREE.Intersection。

示例:

const cube = new THREE.Mesh(
    new THREE.BoxGeometry(),
    new THREE.MeshBasicMaterial({ color: 0x00ff00 })
);
const sphere = new THREE.Mesh(
    new THREE.SphereGeometry(),
    new THREE.MeshBasicMaterial({ color: 0xff0000 })
);
const objects = [cube, sphere];
const intersects = raycaster.intersectObjects(objects, true);
if (intersects.length > 0) {
    console.log('射线与物体相交');
}

返回值 THREE.Intersection 对象

当射线与物体相交时,intersectObject 和 intersectObjects 方法会返回一个包含 THREE.Intersection 对象的数组。

THREE.Intersection 对象包含以下属性:

  • distance:射线原点到相交点的距离,类型为 number。
  • point:相交点的位置,类型为 THREE.Vector3。
  • face:相交的面,类型为 THREE.Face3 或 THREE.Face4。
  • faceIndex:相交面的索引,类型为 number。
  • object:相交的物体,类型为 THREE.Object3D。
  • uv:相交点的纹理坐标,类型为 THREE.Vector2。

示例:

const cube = new THREE.Mesh(
    new THREE.BoxGeometry(),
    new THREE.MeshBasicMaterial({ color: 0x00ff00 })
);
const sphere = new THREE.Mesh(
    new THREE.SphereGeometry(),
    new THREE.MeshBasicMaterial({ color: 0xff0000 })
);
const objects = [cube, sphere];
const intersects = raycaster.intersectObjects(objects, true);
if (intersects.length > 0) {
    console.log( intersects[0].point,"相交坐标点");
    console.log(intersects[0].object,"相交物体");
    console.log(intersects[0].distance,"射线原点和相交点距离");
}

通过这些属性,你可以获取射线与物体相交的详细信息,进而实现诸如选中物体、高亮显示、修改材质颜色等交互效果。


四、总结

       以上便是 Three.js 中射线投射器Raycaster最基本的 API 介绍。从构造函数、属性到各方法的功能与参数,以及相交检测后THREE.Intersection对象的相关属性,都为我们在 3D 场景中实现射线拾取模型提供了有力的支持。合理运用这些 API,能够为 Three.js 项目增添丰富的交互体验,让用户与 3D 场景实现更具趣味性和实用性的互动。通过以上介绍我们掌握了如何判断射线是否与物体(模型相交),但是模型拾取本质是通过鼠标点击屏幕,如何将这动作转换为射线将在下一篇博文继续介绍。

更多three.js入门知识点请关注该系列教程后续的更新。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

pixle0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值