Three.js开发必备:射线拾取模型包含拾取gltf模型案例

Three.js开发必备:射线拾取模型

在这里插入图片描述

在这里插入图片描述

射线

射线Ray

类比数学几何提到的射线,三维控件中,一条线把一个点作为起点,沿着某个方向无限延伸。

const ray = new THREE.Ray()

射线起点.origin

射线Ray的起点.origin3D空间中的坐标,可以用一个三维向量Vector3x,y,z分量表示。

ray.origin = new THREE.Vector3(0, 0, 0);

起点.origin属性值是三维向量Vector3,也可以用.set()方法设置。

ray.origin.set(0, 0, 0);

射线方向.direction

射线Ray的方向.direction通用用一个三维向量Vector3表示,向量长度保证为1,也就是单位向量。

// 表示射线沿着X轴的正方向
ray.direction = new THREE.Vector3(1, 0, 0);
// 表示射线沿着X轴的负方向
ray.direction = new THREE.Vector3(-1, 0, 0);

需要注意的是direction的值需要时单位向量,不是的话可执行.normalize()归一化或者说标准化。

ray.direction = new THREE.Vector3(5, 0, 0).normalize();

3D是否交叉.intersectTriangle()方法

射线Ray有很多数学计算方法,.intersectTriangle()就是一个计算一个射线和一个三角形在3D空间中是否交叉。执行.intersectTriangle(),如果有交叉返回交点坐标,如果没有则返回空值null
intersectTriangle()参数4表示是否进行背面剔除,p1,p2,p3可以理解为一个三角形有正反两个面,一面是正面一面是反面,在一面观察p1,p2,p3如果沿着三个点顺序转圈是逆时针方向表示正面,另一面观察p1,p2,p3是顺时针方向表示背面。

import * as THREE from 'three';
const geometry = new THREE.BufferGeometry(); //创建一个几何体对象
//类型数组创建顶点数据
const vertices = new Float32Array([
  100, 25, 0, //顶点1坐标
  100, -25, 25, //顶点2坐标
  100, -25, -25, //顶点3坐标
]);
// 创建属性缓冲区对象
const attribue = new THREE.BufferAttribute(vertices, 3); //3个为一组,表示一个顶点的xyz坐标
// 设置几何体attributes属性的位置属性
geometry.attributes.position = attribue;

const material = new THREE.MeshBasicMaterial({
   
   
  color: 0x00ffff, //材质颜色
  side: THREE.FrontSide, //默认只有正面可见
  // side: THREE.BackSide, //设置只有背面可见
  // side: THREE.DoubleSide, //两面可见
});
// 网格模型本质:一个一个三角形(面)构成
const mesh = new THREE.Mesh(geometry, material);

const ray = new THREE.Ray()
ray.origin.set(0, 0, 0);
ray.direction = new THREE.Vector3(1, 0, 0);

const p1 = new THREE.Vector3(100, 25, 0);
const p2 = new THREE.Vector3(100, -25, 25);
const p3 = new THREE.Vector3(100, -25, -25);

const point = new THREE.Vector3(); // 用来记录射线和三角形的交叉点
const result = ray.intersectTriangle(p1, p2, p3, false, point)

console.log("交叉点坐标", point)
console.log("查看是否相交", result)
export default mesh;

效果图:
在这里插入图片描述
如果将ray.direction = new THREE.Vector3(1, 0, 0);改为

ray.direction = new THREE.Vector3(-1, 0, 0);

如果为负值,则x方向为负的射线没有交叉点,所以为null
在这里插入图片描述
如果从背面剔除,x与剔除背面无交叉,也为null

ray.direction = new THREE.Vector3(1, 0, 0);
const result2 = ray.intersectTriangle(p1, p2, p3, true, point);
console.log('查看是否相交', result2);

在这里插入图片描述

Raycaster(射线拾取模型)

Raycaster是一个和射线相关的射线投射器。

射线投射器Raycaster

射线投射器Raycaster具有一个射线属性.ray,该属性的值就是与Ray相关的.direction.origin

const reycaster = new THREE.Raycaster();
console.log("射线属性", reycaster.ray);

在这里插入图片描述

const reycaster = new THREE.Raycaster();
reycaster.ray.origin.set(-100, 0, 0);
reycaster.ray.direction.set(1, 0, 0);
console.log("射线属性", reycaster.ray);

在这里插入图片描述

射线拾取返回信息.intersectObjects()

射线拾取返回的intersects里面的元素包含多个信息,.intersectObjects().intersectObject()功能相同,只是具体语法不同,.intersectObjects()返回数组元素包含的信息。

const raycaster = new THREE.Raycaster();
raycaster.ray.origin.set(-100, 0, 0);
raycaster.ray.direction = new THREE.Vector3(1, 0, 0);
const result = raycaster.intersectObjects([mesh1, mesh2, mesh3]);
console.log("射线属性", result);

在这里插入图片描述

交叉点坐标

const raycaster = new THREE.Raycaster();
raycaster.ray.origin.set(-100, 0, 0);
raycaster.ray.direction = new THREE.Vector3(1, 0, 0);
const result = raycaster.intersectObjects([mesh1, mesh2, mesh3]);
if (result.length > 0) {
   
   
    console.log("交叉点坐标", result[0].point);
    console.log("射线原点和交叉点距离", result[0].distance);
    console.log("交叉对象", result[0].object);
}

在这里插入图片描述

设置交叉点物体的.material

设置射线拾取物体的属性颜色

result[0].object.material.color.set(0xff0000);
result[1].object.material.color.set(0xff0000);

在这里插入图片描述

Raycaster(鼠标点击选中模型)

开发中射线投射器Raycaster用到的很经常,鼠标点击选中一个模型对象,根据以下步骤进行设置即可。

第一步、坐标转化(屏幕坐标转标准设备桌标)

addEventListener('click', function (event) {
   
   
    const px = event.offsetX;
    const py = event.offsetY;
    //屏幕坐标px、py转WebGL标准设备坐标x、y
    //width、height表示canvas画布宽高度
    const x = (px / width) * 2 - 1;
    const y = -(py / height) * 2 + 1;
    console.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值