Threejs_10 光线投射技术完成画布三维事件交互

你完成了一个threejs的模型之后,里面有很多东西,你咋知道你点击的是哪个呢??如何触发你点击的事件呢?再canvas画布中可不能和html事件一样直接使用e.target来完成了哦。如何做到呢?

光线投射实现三维定位

方法思想

方法就是从点击的地方创造一条虚拟的从相机射入的射线,来计算这条射线是否穿过了什么几何体,穿过了几个,然后通过方法获取到穿过物体的属性。

1.创建三个小球,将其放入场景中

// 创建三个球
const sphere1 = new THREE.Mesh(new THREE.SphereGeometry(1, 32, 32),new THREE.MeshBasicMaterial({color: 0x00ff00,})
);
sphere1.position.x = -4;
scene.add(sphere1);
const sphere2 = new THREE.Mesh(new THREE.SphereGeometry(1, 32, 32),new THREE.MeshBasicMaterial({color: 0x0000ff,})
);
scene.add(sphere2);
const sphere3 = new THREE.Mesh(new THREE.SphereGeometry(1, 32, 32),new THREE.MeshBasicMaterial({color: 0xff00ff,})
);
sphere3.position.x = 4;
scene.add(sphere3);

 如果觉得三个球离得太近 可以把相机的z轴位置调高一点  也就是我们的眼睛靠后一点

camera.position.z = 15;
// 为了看到z轴
camera.position.y = 2;
// 设置x轴
camera.position.x = 2;
//设置相机的焦点 (相机看向哪个点)
camera.lookAt(0, 0, 0);

2.新建射线,新建鼠标向量

// 创建射线
const raycaster = new THREE.Raycaster();//创建鼠标向量
const mouse = new THREE.Vector2();

使用THREE.Raycaster 方法创建一个射线,鼠标向量用来存储后面得到的坐标值

3. window事件 获取点击到的地方

window.addEventListener("click", (e) => {console.log(e.clientX, e.clientY);//设置鼠标向量的xy值
});

4.公式计算出对应的坐标值 传入鼠标向量中

//给window侦听点击事件 获取点击到的地方
window.addEventListener("click", (e) => {console.log(e.clientX, e.clientY);//设置鼠标向量的xy值//设置鼠标向量的xy值//公式 可以用边框四个点做测试 或者暂时先记住mouse.x = (e.clientX / window.innerWidth) * 2 - 1;mouse.y = -((e.clientY / window.innerHeight) * 2 - 1);
});

 公式是为什么可以用四个点测试一下,然后自己思考一下。或者直接套用。得到的x,y的值就是平面像素转换为三维坐标的x,y值。

5.通过鼠标向量更新射线坐标

window.addEventListener("click", (e) => {console.log(e.clientX, e.clientY);//设置鼠标向量的xy值//设置鼠标向量的xy值//公式 可以用边框四个点做测试 或者暂时先记住mouse.x = (e.clientX / window.innerWidth) * 2 - 1;mouse.y = -((e.clientY / window.innerHeight) * 2 - 1);//通过摄像机和鼠标位置更新射线raycaster.setFromCamera(mouse, camera);
});

6. 使用raycaster.intersectObjects方法计算物体和射线的焦点

window.addEventListener("click", (e) => {console.log(e.clientX, e.clientY);//设置鼠标向量的xy值//设置鼠标向量的xy值//公式 可以用边框四个点做测试 或者暂时先记住mouse.x = (e.clientX / window.innerWidth) * 2 - 1;mouse.y = -((e.clientY / window.innerHeight) * 2 - 1);//通过摄像机和鼠标位置更新射线raycaster.setFromCamera(mouse, camera);//计算物体和射线的焦点const intersects = raycaster.intersectObjects([sphere1, sphere2, sphere3]);console.log(intersects);
});

点击空的地方得到的就是一个空数组,点击有球的地方,得到的就是一个数组,数组值中有object属性,代表的就是这个小球的内容,可以通过object属性来设置小球的参数。

7.交互Demo实现

当然 也有可能出现两个的情况,所以说我们这时候只用取数组第一个值,用它来设置就好了。我们现在用他来做一个点击就变成红色的交互效果,要求是第二次点击的时候 要变回原有的颜色。

我们的思路就是需要再点击的时候判断他是否已经变过色了,如果没有变过色,就让他变色,并且将现在的颜色存起来。如果变过色,就让他的颜色变回来。

//给window侦听点击事件 获取点击到的地方
window.addEventListener("click", (e) => {console.log(e.clientX, e.clientY);//设置鼠标向量的xy值//设置鼠标向量的xy值//公式 可以用边框四个点做测试 或者暂时先记住mouse.x = (e.clientX / window.innerWidth) * 2 - 1;mouse.y = -((e.clientY / window.innerHeight) * 2 - 1);//通过摄像机和鼠标位置更新射线raycaster.setFromCamera(mouse, camera);//计算物体和射线的焦点const intersects = raycaster.intersectObjects([sphere1, sphere2, sphere3]);// console.log(intersects);if (intersects[0].object._isSelect) {//设定旧的颜色intersects[0].object.material.color.set(intersects[0].object._originColor);intersects[0].object._isSelect = false;return;}//添加一个属性 选中状态intersects[0].object._isSelect = true;//将之前的颜色记录下来intersects[0].object._originColor =intersects[0].object.material.color.getHex();//设定新的颜色intersects[0].object.material.color.set(0xff0000);
});

 全部代码

//导入 threejs
import * as THREE from "three";
//导入轨道控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
// 创建场景
const scene = new THREE.Scene();
// 创建相机
const camera = new THREE.PerspectiveCamera(45, // 视角window.innerWidth / window.innerHeight, // 宽高比 窗口的宽高进行设置的0.1, // 近平面   相机最近最近能看到的物体1000 // 远平面   相机最远能看到的物体
);
// 创建渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染器的大小  (窗口大小)
renderer.setSize(window.innerWidth, window.innerHeight);
// 将渲染器的dom元素添加到body中
document.body.appendChild(renderer.domElement);
camera.position.z = 15;
// 为了看到z轴
camera.position.y = 2;
// 设置x轴
camera.position.x = 2;
//设置相机的焦点 (相机看向哪个点)
camera.lookAt(0, 0, 0);//添加世界坐标辅助器  (红色x轴,绿色y轴,蓝色z轴)一个线段 参数为 线段长度
const axesHelper = new THREE.AxesHelper(5);
//添加到场景之中
scene.add(axesHelper);// 添加轨道控制器 (修改侦听位置)  一般监听画布的事件  不监听document.body
const controls = new OrbitControls(camera, renderer.domElement);//渲染函数
function animate() {controls.update();//请求动画帧requestAnimationFrame(animate);//渲染renderer.render(scene, camera);
}
animate();
//渲染// 监听窗口的变化 重新设置渲染器的大小 画布自适应窗口
window.addEventListener("resize", () => {// 重新设置渲染器的大小renderer.setSize(window.innerWidth, window.innerHeight);// 重新设置相机的宽高比camera.aspect = window.innerWidth / window.innerHeight;// 重新计算相机的投影矩阵camera.updateProjectionMatrix();
});// 创建三个球
const sphere1 = new THREE.Mesh(new THREE.SphereGeometry(1, 32, 32),new THREE.MeshBasicMaterial({color: 0x00ff00,})
);
sphere1.position.x = -4;
scene.add(sphere1);
const sphere2 = new THREE.Mesh(new THREE.SphereGeometry(1, 32, 32),new THREE.MeshBasicMaterial({color: 0x0000ff,})
);
scene.add(sphere2);
const sphere3 = new THREE.Mesh(new THREE.SphereGeometry(1, 32, 32),new THREE.MeshBasicMaterial({color: 0xff00ff,})
);
sphere3.position.x = 4;
scene.add(sphere3);// 创建射线
const raycaster = new THREE.Raycaster();//创建鼠标向量
const mouse = new THREE.Vector2();//给window侦听点击事件 获取点击到的地方
window.addEventListener("click", (e) => {console.log(e.clientX, e.clientY);//设置鼠标向量的xy值//设置鼠标向量的xy值//公式 可以用边框四个点做测试 或者暂时先记住mouse.x = (e.clientX / window.innerWidth) * 2 - 1;mouse.y = -((e.clientY / window.innerHeight) * 2 - 1);//通过摄像机和鼠标位置更新射线raycaster.setFromCamera(mouse, camera);//计算物体和射线的焦点const intersects = raycaster.intersectObjects([sphere1, sphere2, sphere3]);// console.log(intersects);if (intersects[0].object._isSelect) {//设定旧的颜色intersects[0].object.material.color.set(intersects[0].object._originColor);intersects[0].object._isSelect = false;return;}//添加一个属性 选中状态intersects[0].object._isSelect = true;//将之前的颜色记录下来intersects[0].object._originColor =intersects[0].object.material.color.getHex();//设定新的颜色intersects[0].object.material.color.set(0xff0000);
});// //给window侦听点击事件 获取点击到的地方
// window.addEventListener("click", (e) => {
//   // console.log(e.clientX, e.clientY);
//   //设置鼠标向量的xy值
//   //公式 可以用边框四个点做测试 或者暂时先记住
//   mouse.x = (e.clientX / window.innerWidth) * 2 - 1;
//   mouse.y = -((e.clientY / window.innerHeight) * 2 - 1);//   //测试向量坐标是否正确
//   // console.log(mouse.x, mouse.y);//   //通过摄像机和鼠标位置更新射线
//   raycaster.setFromCamera(mouse, camera);//   //计算物体和射线的焦点
//   const intersects = raycaster.intersectObjects([sphere1, sphere2, sphere3]);//   if (intersects[0].object._isSelect) {
//     //设定旧的颜色
//     intersects[0].object.material.color.set(intersects[0].object._originColor);
//     intersects[0].object._isSelect = false;
//     return;
//   }
//   //添加一个属性 选中状态
//   intersects[0].object._isSelect = true;
//   //将之前的颜色记录下来
//   intersects[0].object._originColor =
//     intersects[0].object.material.color.getHex();
//   //设定新的颜色
//   intersects[0].object.material.color.set(0xff0000);
//   // console.log(intersects);
// });
//3D 光线投射技术 完成3D三维场景中事件交互

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/154996.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

自动化物流运输设备模组要选择哪种类型?

在自动化物流运输设备中,选择合适的模组类型取决于具体的运输需求和应用场景。 1、同步带模组:同步带模组是一种低噪音、低成本的物流运输设备,适用于中短距离、轻型货物的运输。它采用同步带传动的方式,具有传动准确、运行稳定、…

12 分布式锁加入看门狗

1、看门狗的流程图 2、看门狗的代码实现 /****类说明:Redis的key-value结构*/ public class LockItem {private final String key;private final String value;public LockItem(String key, String value) {this.key key;this.value value;}public String getKey…

消消乐游戏开发,消除类游戏

消除游戏是一类简单而又充满乐趣的休闲游戏,通过匹配相同的元素来完成任务,其简单直观的玩法吸引了大量玩家。本文将为你介绍设计和开发一款成功的消除游戏的关键步骤。 1. 确定核心玩法机制 消除游戏的核心在于匹配相同的元素。首先,明确定…

MyBatis Generator 插件 详解自动生成代码

MyBatis Generator(MBG)是MyBatis和iBATIS的代码生成器。可以生成简单CRUD操作的XML配置文件、Mapper文件(DAO接口)、实体类。实际开发中能够有效减少程序员的工作量,甚至不用程序员手动写sql。 它将为所有版本的MyBatis以及版本2.2.0之后的i…

YOLOV5 C++部署的人员检测项目【学习笔记(十一)】

本文为修改后的转载,没有转载链接,所以文章类型暂为原创 文章目录 一、安装Pytorch 及 YOLO v51.1 安装GPU版 pytorch1.2 安装YOLO v5所需依赖 二、YOLO v5训练自定义数据2.1 标注数据2.1.1 安装labelImg2.1.2 标注 2.2 准备数据集2.2.1 组织目录结构2.…

深度学习之三(卷积神经网络--Convolutional Neural Networks,CNNs)

概念 卷积神经网络(Convolutional Neural Networks,CNNs)是一种特殊的神经网络结构,专门用于处理具有网格状结构(如图像、音频)的数据。CNN 在计算机视觉领域取得了巨大成功,广泛应用于图像识别、物体检测、图像生成等任务。以下是 CNN 的主要理论概念: 在数学中,卷…

TeXLive 2023安装教程

TeXLive 2023安装教程 本文介绍最新TeX发行版——TeXLive 2023的安装步骤。如果你想用LaTeX进行写作,那么需要搭建LaTeX环境:可以选择下面两种方案之一进行安装:(1)TeXLive 2023TeXStudio或者(2)TeXLive 2023WinEdt 11。其中TeXLive 2023是由…

[Mac软件]Downie 4.6.34视频下载工具

以下是关于Downie软件的介绍: Downie是一款非常实用的视频下载软件,专门为Mac用户设计。这款软件的使用方法非常简单,只需要将想要下载的视频链接复制到Downie的界面,它就能够自动下载。 Downie最大的特点就是支持的网站非常多&a…

五大匹配算法

五大匹配算法 五大匹配算法 BF 匹配、RK 匹配、KMP 匹配、BM 匹配、Sunday 匹配。 1、BF 匹配 // BF 匹配(暴力匹配) public static int bfMatch(String text, String pattern) {char[] t text.toCharArray();char[] p pattern.toCharArray();int i …

vs code git问题:文件明明已加入忽略文件中,还是出现

vs code git问题:文件明明已加入忽略文件中,还是出现 原因: 因为之前这些文件都已经提交过,线上GIT已经存在,已存在就不能忽略, 解决办法: 先要删除这些文件提交上去,然后把这些文…

使用USB转JTAG芯片CH347在Vivado下调试

简介 高速USB转接芯片CH347是一款集成480Mbps高速USB接口、JTAG接口、SPI接口、I2C接口、异步UART串口、GPIO接口等多种硬件接口的转换芯片。 通过XVC协议,将CH347应用于Vivado下,简单尝试可以成功,源码如下,希望可以一起共建&a…

软件系统运维方案

1.项目情况 2.服务简述 2.1服务内容 2.2服务方式 2.3服务要求 2.4服务流程 2.5工作流程 2.6业务关系 2.7培训 3.资源提供 3.1项目组成员 3.2服务保障 点击获取所有软件开发资料:点我获取

一文了解Spring依赖注入时循环依赖问题

目录 什么是循环依赖 凡是Java的循环依赖都会有问题? 为什么Spring循环依赖会有问题? Spring解决循环依赖问题的思路? 设置二级缓存对象池 方案一直接将实例化对象放入早期对象池 方案一缺点 方案二-将实例化对象处理AOP后放入早期对象…

入行IC | 从小白助理级,到总监专家级,到底要经历怎样的成长阶段呢?

《中国集成电路产业人才发展报告》是业内和IC设计、IC人才都息息相关的一份报告。 (文末可领全部报告资料) * 从报告数据来看,无论在半导体产业的哪个环节,个人发展路径和年薪待遇都是逐级攀升的趋势。 那么从小白助理级&a…

口袋参谋:找关键词的三种方法!

​如何找热搜关键词?99%的商家都不知道。那么今天可以根据我说的三种方法去做。 第一种方法:利用竞争对手 通过分析竞争对手,正在使用和采取何种优化方法,来帮助你理解市场上正在流行什么样的关键字,这些热词可以直接从…

Java自动化驱动浏览器搜索稻香

下载最新的Chrome浏览器 查看chrome版本,在浏览器地址栏输入:chrome://version/ 下载对应的浏览器驱动,将其放到一个目录中,我放到了D:/chromedriver-win64 导入对应的依赖【注意:不要导入最新的版本,最…

数字化转型导师坚鹏:数字化时代银行网点厅堂营销5大重点分析

数字化时代银行网点厅堂营销存在以下5大重点: 1、厅堂宣传。应以主推产品作为厅堂宣传的宣传重点,结合视频宣传、平面物料、互动机具、陈列物料等多维度,开展有序重复展示,进而加大吸引客户关注度。 2、产品推荐。在识别出中高端…

纽扣电池/含纽扣电池产品上架亚马逊各国法规标准要求16 CFR 第 1700.15/20 ANSI C18.3M(瑞西法案认证)

亚马逊纽扣电池认证标准有哪些? 一、美国站(亚马逊纽扣电池/含纽扣电池商品)安全测试标准要求: 16 CFR 第 1700.15 、16 CFR 第 1700.20 ANSI C18.3M、警示标签声明要求(第 117-171 号公众法) 二、澳大…

Linux应用开发基础知识——网络通信编程(九)

前言: 通过学习为后续Linux网络编程奠定基础。首先介绍网络编程的概念,即网络协议分层,旨在帮助读者对网络建立初步的、全面立体的认识,其次介绍包括协议、端口、地址等;最后介绍应用非常广泛的传输控制协议&#xff0…

CentOS8部署Skywalking(非容器方式)

一、官网下载安装包 二、安装 #tar -zxf apache-skywalking-apm-9.6.0.tar.gz #mv apache-skywalking-apm-9.6.0 skywalking #cd /opt/skywalking 修改配置文件 #vi /opt/skywalking/config/application.yml #vi vi /opt/skywalking/webapp/application.yml 三、运行 ./bin…