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

three.js射线拾取点击位置与屏幕坐标映射

three.js小白的学习之路。

在使用three.js搭建可视化场景的时候,不可避免的要添加点击事件,需要用到three.js提供的Raycaster类。

在使用过程中,一般是给WebGLRender的DOM监听click点击事件:

const renderer = new Three.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.domElement.addEventListener("click", (evt) => {// ………………
});

然后在里面声明一个Raycaster,然后经过一个坐标转换,就可以监听到鼠标点击的是哪一个模型了:

renderer.domElement.addEventListener("click", (evt) => {const x = (evt.offsetX / window.innerWidth) * 2 - 1;const y = -(evt.offsetY / window.innerHeight) * 2 + 1;const raycaster = new Three.Raycaster();raycaster.setFromCamera(new Three.Vector2(x, y), camera);const intersects = raycaster.intersectObjects(scene.children);console.log(intersects);intersects.forEach((item) => {item.object.material.color.set(0xffff00);});
});

核心就在下面两行代码上:

 const x = (evt.offsetX / window.innerWidth) * 2 - 1;const y = -(evt.offsetY / window.innerHeight) * 2 + 1;

两行代码其实就是屏幕坐标到二维坐标的一个转换。先看一下setFromCamera函数针对这个变量的解释:

意思是:鼠标的二维坐标,以归一化设备坐标(NDC)表示——X和Y分量应在-1和1之间。

归一化之后的坐标大概就是下面的示意图,X轴正方向向右,左侧是-1,右侧是1;Y轴正方向是向上,上方是1,下方是-1:

而原本的屏幕坐标是下面这样的,X轴正方向向右,Y轴正方向向下:

当我们点击屏幕上的一个点时,可以获取到这个点的坐标,也就是offsetX和offsetY这两个分量:

将上述两个分量从鼠标的二维坐标转换到NDC,我们只需要将其归一化,值变为[0, 1],在乘以2,值变为[0, 2],在减去1,值变为[-1, 1],就能达到我们的目的。由于Y轴两个坐标系的正方向是相反的,所以最后的结果需要取反:

const x = (evt.offsetX / window.innerWidth) * 2 - 1;
const y = -((evt.offsetX / window.innerWidth) * 2 - 1);

也就是:

 const x = (evt.offsetX / window.innerWidth) * 2 - 1;const y = -(evt.offsetY / window.innerHeight) * 2 + 1;

这样就可以正常获取到鼠标点击了。

下面写个小案例,将场景里的方块进行点击变色:

// 生成一些立方体
const generateBox = (color: string, position: Three.Vector3) => {const geo = new Three.BoxGeometry(50, 50, 50);const material = new Three.MeshLambertMaterial({color: new Three.Color(color),});const box = new Three.Mesh(geo, material);box.position.copy(position.clone());return box;
};
const box1 = generateBox("blue", new Three.Vector3(0, 0, 0));
const box2 = generateBox("green", new Three.Vector3(0, 0, 100));
const box3 = generateBox("red", new Three.Vector3(100, 0, 0));
const box4 = generateBox("orange", new Three.Vector3(100, 0, 100));
scene.add(box1, box2, box3, box4);const renderer = new Three.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight); // 占满全屏renderer.domElement.addEventListener("click", (evt) => {const x = (evt.offsetX / window.innerWidth) * 2 - 1;const y = -(evt.offsetY / window.innerHeight) * 2 + 1;const raycaster = new Three.Raycaster();raycaster.setFromCamera(new Three.Vector2(x, y), camera);const intersects = raycaster.intersectObjects(scene.children);console.log(intersects);if (intersects.length > 0) {intersects[0].object.material.color.set(0xffffff);}
});

使用intersectObjects方法计算射线是否与模型相交,该方法返回相交的模型数组。如果数组长度大于0,只取第一个相交的模型让其材质变为白色(第一个相交的是距离屏幕最近的)。

效果如下:

可以看到即使点击过程中有两个模型,我们取得是第一个,所以最先点到的模型材质会发生变化。完美实现。

http://www.dtcms.com/a/403052.html

相关文章:

  • AutoMQ × Ververica:打造云原生实时数据流最佳实践!
  • Laravel5.8 使用 snappyPDF 生成PDF文件
  • 自己做网站的图片手机芒果tv2016旧版
  • L4 vs L7 负载均衡:彻底理解、对比与实战指南
  • wordpress站群软件自己的网站怎么赚钱
  • 零知IDE——基于STM32F407VET6和MCP2515实现CAN通信与数据采集
  • 若依框架-Spring Boot
  • 全新 CloudPilot AI:嵌入 Kubernetes 的 SRE Agent,降本与韧性双提升!
  • 自建网站推广的最新发展wordpress同步到报价号
  • 4、导线、端子及印制电路板元器件的插装、焊接及拆焊
  • 【Java八股文】13-中间件面试篇
  • (四)优雅重构:洞悉“搬移特性”的艺术与实践
  • 网站建设专用图形库商务网站建设方案
  • 快速入门HarmonyOS应用开发(三)
  • Easysearch 国产替代 Elasticsearch:8 大核心问题解读
  • 【机器学习】搭建对抗神经网络模型来实现 MNIST 手写数字生成
  • 做推广的网站那个好中国机房建设公司排名
  • odoo18应用、队列服务器分离(SSHFS)
  • 老年健康管理小工具抖音快手微信小程序看广告流量主开源
  • c#vb.net动态创建二维数组
  • php做网站完整视频动漫制作和动漫设计哪个好
  • 云原生微服务中间件选型
  • Python/JS/Go/Java同步学习(第二十四篇)四语言“元组概念“对照表: 雷影“老板“发飙要求员工下班留校培训风暴(附源码/截图/参数表/避坑指南)
  • vue3在 script 中定义组件
  • 【CSRF】防御
  • vue从template模板到真实渲染在页面上发生了什么
  • 从构建工具到状态管理:React项目全栈技术选型指南
  • 做彩票网站电话多少钱湛江网站网站建设
  • 云手机性能会受到哪些因素的影响?
  • app网站维护网站开发众包平台