Three.js 选择三维模型对象(射线拾取)

发布于 2021-12-15 20:50:32 字数 3131 浏览 1498 评论 0

在canvas画布上使用鼠标单击选中一个三维模型对象,三维模型然后做出反应,比如弹出一个窗口、颜色发生变化。要实现这一点首先把鼠标单机位置的屏幕坐标转化为标准设备坐标,然后要借助 Vector3 对象的方法 unproject 把标准设备坐标转化为世界坐标。

然后利用鼠标单击位置对应的屏幕坐标转化得到的世界坐标和相机对象的世界坐标两个参数创建一个射线对象 Raycaster

下面的代码完成的作用是当鼠标单击 Canvas 画布的时候,如果选中一个网格模型的时候,该网格模型的材质对象由不透明状态变为半透明状态。

/**
 * 射线拾取函数
 * 选中的网格模型变为半透明效果
 */
function ray() {
  var Sx = event.clientX;//鼠标单击位置横坐标
  var Sy = event.clientY;//鼠标单击位置纵坐标
  //屏幕坐标转标准设备坐标
  var x = ( Sx / window.innerWidth ) * 2 - 1;//标准设备横坐标
  var y = -( Sy / window.innerHeight ) * 2 + 1;//标准设备纵坐标
  var standardVector  = new THREE.Vector3(x, y, 0.5);//标准设备坐标
  //标准设备坐标转世界坐标
  var worldVector = standardVector.unproject(camera);
  //射线投射方向单位向量(worldVector坐标减相机位置坐标)
  var ray = worldVector.sub(camera.position).normalize();
  //创建射线投射器对象
  var raycaster = new THREE.Raycaster(camera.position, ray);
  //返回射线选中的对象
  var intersects = raycaster.intersectObjects([boxMesh,sphereMesh,cylinderMesh]);
  if (intersects.length > 0) {
    intersects[0].object.material.transparent = true;
    intersects[0].object.material.opacity = 0.6;
  }
}
addEventListener('click',ray);// 监听窗口鼠标单击事件

鼠标事件

通过方法 addEventListener 可以实时监控鼠标事件,一旦发生鼠标单击事件就执行函数 ray()。执行 ray 函数,首先通过鼠标事件的返回的事件对象 event 的坐标属性 clientX、clientY 获得鼠标单机位置相对浏览器窗口客户区的坐标(单位:像素)。

标准设备坐标

//屏幕坐标转标准设备坐标
var x = ( Sx / window.innerWidth ) * 2 - 1;//标准设备横坐标
var y = -( Sy / window.innerHeight ) * 2 + 1;//标准设备纵坐标
var standardVector  = new THREE.Vector3(x, y, 0.5);//标准设备坐标

通过返回的坐标值 clientX、clientY 读入坐标变换公式转化为标准设备坐标系下标准设备坐标 x、y,z 可以随意自定义一个值。参考教程世界坐标转化为屏幕坐标

世界坐标

//标准设备坐标转世界坐标
var worldVector = standardVector.unproject(camera);

unproject 是 Vector3 对象的方法,作用是把标准设备坐标转化为世界坐标,方法的参数是相机对象 camera,该方法的使用可以参考 Vector3 对象的 project 方法,这两个方法的作用都是进行坐标变换,只不过方向是反过来的。

射线发射器对象 Raycaster

格式

RaycasterRaycaster( origin, direction, near, far )

origin 表示射线起点位置,direction 表示射线方向,两个参数的数据类型都是 Vector3 对象。

通过构造函数 new THREE.Raycaster(camera.position, ray); 创建一个射线发射器对象,camera.position 是相机的位置,ray 表示射线方向向量,通过语句ray = worldVector.sub(camera.position).normalize(); 创建,sub 是 Vector 对象的一个方法,两个坐标值(向量)进行减法运算,normalize() 方法表示对象向量进行归一化计算,计算相机对象与上面转换得到的世界坐标进行减法运算,然后归一化得到一个单位向量。

通过射线发射器对象的方法intersectObjects可以返回射线旋转的所有对象,该方法的参数是一个 Object3D 对象构成的数组,表示射线对象的选择范围,凡是选中的都会以数组的形式返回,返回的数据结构是 [ { distance, point, face, faceIndex, indices, object },{ distance, point, face, faceIndex, indices, object } ... ],比如案例代码中参数[boxMesh,sphereMesh,cylinderMesh],如果两个网格模型屏幕坐标位置是重合的,那么都会被选中,因此可以通过数组下标的形式访问第几个对象,被选中的网格模型对象以object属性的形式存在,代码intersects[0].object就表示被选中所有的网格模型中的第一个网格模型对象。

通过语句 intersects[0].object.material.opacity = 0.6; 可以更改材质对象的透明度。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

夜无邪

暂无简介

0 文章
0 评论
19448 人气
更多

推荐作者

qq_aHcEbj

文章 0 评论 0

寄与心

文章 0 评论 0

13545243122

文章 0 评论 0

流星番茄

文章 0 评论 0

春庭雪

文章 0 评论 0

潮男不是我

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文