首页 > 其他分享 >Threejs之光线投射Raycaster

Threejs之光线投射Raycaster

时间:2024-09-11 21:49:22浏览次数:10  
标签:Raycaster Threejs const THREE camera renderer 投射 new

本文目录

前言

Three.js中的光线投射(Raycaster)是一个功能强大的类,用于在三维场景中执行射线投射和交叉检测。它广泛应用于鼠标拾取、碰撞检测等场景,使用户能够与3D对象进行交互。

一、简要介绍

1.1 定义与原理

  • 定义:光线投射(Raycaster)是Three.js中用于进行射线投射和交叉检测的类。
  • 原理:通过从特定点(如相机位置或屏幕上的某一点)发射一条射线,并检测这条射线是否与场景中的物体相交,从而确定用户与哪些物体进行了交互。

1.2 构造器

构造器:Raycaster(origin : Vector3, direction : Vector3, near : Float, far : Float)
origin:光线投射的原点向量。
direction:向射线提供方向的方向向量,应当被标准化。
near:返回的所有结果比此值远。默认为0。
far:返回的所有结果都比此值近。默认为Infinity(正无穷)。

1.3 常用属性

far:远距离因数,表示哪些对象可以基于该距离而被Raycaster所考虑。
near:近距离因数,表示哪些对象可以基于该距离而被Raycaster所忽略。
camera:对依赖于视图的对象(如Sprites等)进行光线投射时使用的相机。
layers:用于控制Raycaster在执行相交测试时忽略哪些3D对象。

1.4 常用方法

  1. set(origin : Vector3, direction : Vector3)
    origin —— 光线投射的原点向量。
    direction —— 为光线提供方向的标准化方向向量。
    使用新的原点和方向来更新射线。
  2. setFromCamera(coords : Vector2, camera : Camera)
    coords—— 在标准化设备坐标中鼠标的二维坐标 —— X分量与Y分量应当在-1到1之间。
    camera—— 射线所来源的摄像机。根据鼠标在屏幕上的位置(归一化设备坐标)和相机位置来更新射线的原点和方向。
  3. intersectObject(object : Object3D, recursive : Boolean, optionalTarget : Array):检测射线与单个物体的相交情况。
  4. intersectObjects(objects : Array, recursive : Boolean, optionalTarget : Array)
    objects —— 检测和射线相交的一组物体。
    recursive —— 若为true,则同时也会检测所有物体的后代。否则将只会检测对象本身的相交部分。默认值为true
    optionalTarget —— (可选)设置结果的目标数组。如果不设置这个值,则一个新的Array会被实例化;如果设置了这个值,则在每次调用之前必须清空这个数组(例如:array.length = 0;)。检测射线与一组物体的相交情况。

二、代码准备及效果

2.1 演示代码准备

我们首先在场景添加三个甜甜圈,代码如下:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        html,
        body {
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100%;
        }
    </style>
</head>

<body>
    <script type="module">
        // 倒入轨道控制器
        import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
        import * as THREE from "three";
        // 创建场景
        const scene = new THREE.Scene();

        // 创建相机
        const camera = new THREE.PerspectiveCamera( // 透视相机
            45, // 视角 角度数
            window.innerWidth / window.innerHeight, // 宽高比 占据屏幕
            0.1, // 近平面(相机最近能看到物体)
            1000, // 远平面(相机最远能看到物体)
        );
        camera.position.set(0, 2, 20);
        // camera.lookAt(0, 0, 0);

        // 创建渲染器
        const renderer = new THREE.WebGLRenderer({
            antialias: true, // 抗锯齿
        });
        // 设置渲染器宽高
        renderer.setSize(window.innerWidth, window.innerHeight)
        // renderer(渲染器)的dom元素添加到我们的HTML文档中
        document.body.appendChild(renderer.domElement)

        // 开启坐标轴辅助器
        const axesHelper = new THREE.AxesHelper(5);
        scene.add(axesHelper);

		const geometry = new THREE.TorusGeometry( 1, 0.5, 20, 25 );
        const geometry1 = new THREE.TorusGeometry( 1, 0.5, 20, 25 );
        const geometry2 = new THREE.TorusGeometry( 1, 0.5, 20, 25 );

		const material = new THREE.MeshBasicMaterial({color: 0xff0000});
		const material1 = new THREE.MeshBasicMaterial({color: 0xff0000});
		const material2 = new THREE.MeshBasicMaterial({color: 0xff0000});

		const torus = new THREE.Mesh( geometry, material );
		const torus1 = new THREE.Mesh( geometry1, material1 );
		const torus2 = new THREE.Mesh( geometry2, material2 );

        torus1.position.x = 3;
        torus2.position.x = -3;


        torus.rotation.y = Math.PI / 2;
        torus1.rotation.y = Math.PI / 2;
        torus2.rotation.y = Math.PI / 2;


		scene.add(torus, torus1, torus2);

        // 控制器
        const control = new OrbitControls(camera, renderer.domElement)
        // 开启阻尼惯性,默认值为0.05
        control.enableDamping = true

        // 渲染循环动画
        function animate() {
            // 在这里我们创建了一个使渲染器能够在每次屏幕刷新时对场景进行绘制的循环(在大多数屏幕上,刷新率一般是60次/秒)
            requestAnimationFrame(animate);
            // 更新控制器。如果没在动画里加上,那必须在摄像机的变换发生任何手动改变后调用
            control.update();
            renderer.render(scene, camera);
        };

        // 执行动画
        animate();
    </script>
</body>

</html>

2.2 效果

在这里插入图片描述
在这里插入图片描述
可以看到场景中就有了三个甜甜圈以及坐标轴辅助器。


三、创建射线Raycaster及效果

3.1 代码

在上述代码的基础上添加:

        // 添加光线投射
        const raycaster = new THREE.Raycaster();
        const rcOrigin = new THREE.Vector3(-5, 0, 0);
        const rcDirection = new THREE.Vector3(1, 0, 0);
        rcDirection.normalize(); // 标准化

        // 第一种构造方法设置
        // const raycaster = new THREE.Raycaster(rcOrigin, rcDirection);
        
        // 第二种方法设置
        raycaster.set(rcOrigin, rcDirection);

        let torusObjects = [torus, torus1, torus2];
        // 渲染循环动画
        function animate() {
            // 获取自时钟启动后的秒数
            const elapsedTime = clock.getElapsedTime();
            // 在这里我们创建了一个使渲染器能够在每次屏幕刷新时对场景进行绘制的循环(在大多数屏幕上,刷新率一般是60次/秒)
            requestAnimationFrame(animate);
            // 一开始先将物体遍历设置颜色,如果不设置的话,下面判断相交的射线一开始会判定为相交
            for(const key in torusObjects){
                torusObjects[key].material.color.set(0xff0000);
                torusObjects[key].position.y = 4 * Math.sin(elapsedTime*((key+1)/10 + 0.2));
            }
			// 循环将与射线相交的物体设置为不同的颜色
            const itobjects = raycaster.intersectObjects(torusObjects);
            for(const itobject of itobjects){
                itobject.object.material.color.set(0xcc33ff);
            }
            
            // 更新控制器。如果没在动画里加上,那必须在摄像机的变换发生任何手动改变后调用
            control.update();
            renderer.render(scene, camera);
        };

可以知道我们往x正方向投射了光线,与之交互就会变颜色。

3.2 效果

请添加图片描述


四、完整代码

最后给出完整代码,如下:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        html,
        body {
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100%;
        }
    </style>
</head>

<body>
    <script type="module">
        // 倒入轨道控制器
        import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
        import * as THREE from "three";
        // 创建场景
        const scene = new THREE.Scene();

        // 创建相机
        const camera = new THREE.PerspectiveCamera( // 透视相机
            45, // 视角 角度数
            window.innerWidth / window.innerHeight, // 宽高比 占据屏幕
            0.1, // 近平面(相机最近能看到物体)
            1000, // 远平面(相机最远能看到物体)
        );
        camera.position.set(0, 2, 20);
        // camera.lookAt(0, 0, 0);

        // 创建渲染器
        const renderer = new THREE.WebGLRenderer({
            antialias: true, // 抗锯齿
        });
        // 设置渲染器宽高
        renderer.setSize(window.innerWidth, window.innerHeight)
        // renderer(渲染器)的dom元素添加到我们的HTML文档中
        document.body.appendChild(renderer.domElement)

        // 开启坐标轴辅助器
        const axesHelper = new THREE.AxesHelper(5);
        scene.add(axesHelper);

        const geometry = new THREE.TorusGeometry( 1, 0.5, 20, 25 );
        const geometry1 = new THREE.TorusGeometry( 1, 0.5, 20, 25 );
        const geometry2 = new THREE.TorusGeometry( 1, 0.5, 20, 25 );

		const material = new THREE.MeshBasicMaterial({color: 0xff0000});
		const material1 = new THREE.MeshBasicMaterial({color: 0xff0000});
		const material2 = new THREE.MeshBasicMaterial({color: 0xff0000});

		const torus = new THREE.Mesh( geometry, material );
		const torus1 = new THREE.Mesh( geometry1, material1 );
		const torus2 = new THREE.Mesh( geometry2, material2 );
        torus1.position.x = 3;
        torus2.position.x = -3;

        torus.rotation.y = Math.PI / 2;
        torus1.rotation.y = Math.PI / 2;
        torus2.rotation.y = Math.PI / 2;

		scene.add(torus, torus1, torus2);

        // 添加光线投射
        const raycaster = new THREE.Raycaster();
        const rcOrigin = new THREE.Vector3(-5, 0, 0);
        const rcDirection = new THREE.Vector3(1, 0, 0);
        rcDirection.normalize(); // 标准化

        // 第一种构造方法设置
        // const raycaster = new THREE.Raycaster(rcOrigin, rcDirection);
        
        // 第二种方法设置
        raycaster.set(rcOrigin, rcDirection);

        let torusObjects = [torus, torus1, torus2];


        // 控制器
        const control = new OrbitControls(camera, renderer.domElement)
        // 开启阻尼惯性,默认值为0.05
        control.enableDamping = true

        // 跟踪时间对象
        const clock = new THREE.Clock();
       
        // 渲染循环动画
        function animate() {
            // 获取自时钟启动后的秒数
            const elapsedTime = clock.getElapsedTime();
            // 在这里我们创建了一个使渲染器能够在每次屏幕刷新时对场景进行绘制的循环(在大多数屏幕上,刷新率一般是60次/秒)
            requestAnimationFrame(animate);
            // 一开始先将物体遍历设置颜色,如果不设置的话,下面判断相交的射线一开始会判定为相交
            for(const key in torusObjects){
                torusObjects[key].material.color.set(0xff0000);
                torusObjects[key].position.y = 4 * Math.sin(elapsedTime*((key+1)/10 + 0.2));
            }
			// 循环将与射线相交的物体设置为不同的颜色
            const itobjects = raycaster.intersectObjects(torusObjects);
            for(const itobject of itobjects){
                itobject.object.material.color.set(0xcc33ff);
            }
            
            // 更新控制器。如果没在动画里加上,那必须在摄像机的变换发生任何手动改变后调用
            control.update();
            renderer.render(scene, camera);
        };

        // 执行动画
        animate();
    </script>
</body>
</html>

在学习的路上,如果你觉得本文对你有所帮助的话,那就请关注点赞评论三连吧,谢谢,你的肯定是我写博的另一个支持。

标签:Raycaster,Threejs,const,THREE,camera,renderer,投射,new
From: https://blog.csdn.net/weixin_44103733/article/details/142134403

相关文章

  • Threejs之光线投射Raycaster交互
    这里写目录标题前言一、前置准备1.1代码1.2效果二、添加交互事件2.1代码2.2效果三、完整代码前言基于上篇文章Threejs之光线投射Raycaster我们知道了光线投射的基础用法,在本届我们将使用光线投射进行鼠标交互事件一、前置准备1.1代码<!DOCTYPEhtml><ht......
  • 用Threejs搭建一个Web3D汽车展厅!
    在网页里360度展示它家新款汽车的3d模型,还要可以让用户DIY汽车部件的颜色。先看最终效果3D引擎的基本知识本文的目标是让大家看完之后可以立刻上手用起来,既然要用3d引擎,那我们理解了一些3d的基本知识后,再看threejs的API文档效率就会很高。无论什么3d引擎,都不外乎由以下几种......
  • ThreeJS 综合教程100+【目录】
    ThreeJS综合教程100+旨在为开发者提供两大方面的知识信息:(1)提供详细的每个api知识点的详解(2)提供实战的示例,提供源代码。在这量大系统性的知识下,给用户提供清晰的思路和示例参考,更好的服务于自己的threeJS开发项目。文章正在建设中,下面的是cesium的示例教程(暂时撑门面),随......
  • vue+ThreeJS:从0 到1 搭建开发环境
    文章目录一、下载安装(懒人版)二、顺序安装1,下载安装nodejs2,安装vue-cli3,创建vue-three项目。4,安装threeJS5,安装elementUI(选装)最终package.json文件如下:本系列教程是在vue2.X的基础上加载threeJS程序,来开发各种示例程序。一、下载安装(懒人版)下载vue-three系统包,n......
  • WebGL_0020:threejs 加载glb模型,加载图片贴图,加载canvas贴图,创建精灵模型并贴图
    1,import*asTHREEfrom'three';importtype{MapViewer}from'@/utils/map3d/mapViewer';import{STATIC_URL}from'@/config';import{GLTFLoader}from'three/examples/jsm/loaders/GLTFLoader';constgetSpri......
  • ThreeJs基础
    基本结构场景相机渲染场景用来放入各种网格模型。每个网格模型为独立个体,又几何体和材质组成。投影相机如同人眼,用来观察网格模型。最终利用渲染对象对相机和场景进行渲染,将3D模型渲染在页面上。 创建几何体THREE.BoxGeometry创建立方体constgeometry=newTHREE.......
  • threejs中OrbitControls的用法
    OrbitControls是Three.js库中一个非常流行的相机控制组件,它允许用户通过鼠标(或触控设备)来旋转、缩放和平移场景中的相机,从而从不同的角度和距离观察场景。下面是如何在Three.js中使用OrbitControls的方法:1.引入OrbitControls首先需要从Three.js的CDN或本地路径中引入O......
  • Threejs路径规划案例V1
       最近在做一个路径规划的例子,大概场景是在一个xy坐标系中,有几个障碍物,一个车要绕过这些障碍物到达目的地,本来用java来实现,但是java调试太不直观了,我就想起用threejs把场景简单搭建出来,规划好的路线也直接展示出来,就可以实时查看路径规划的怎么样了。先来一张效果图:首先是添加t......
  • threeJs 修改TransformControls的显示位置
    有的时候模型的原点不是自身中心而是在场景的[0,0,0]位置这个时候想要让TransformControls的位置显示在模型的中心目前找的的处理方式是修改源码找到updateMatrixWorld方法updateMatrixWorld(){...for(leti=0;i<handles.length;i++){ ... if(this......
  • 06--kubernetes.pod管理与投射数据卷
    前言:上一章记录了部署k8s常用的两个方式,这一章就简单一些,整理一下k8s资源对象的配置和管理命令。1、集群状态检查前天搭建的环境,然后关机了两天今天开启后第一时间需要检查集群环境是否正常[root@k8s-master1~]#kubectlgetnodeNAMESTATUSROLESAGE......