threejs:射线拾取封装
射线拾取封装代码:
import * as THREE from 'three';
// 点击事件
// 1.坐标转化(鼠标单击的屏幕坐标转标准设备坐标)
// 2.射线计算(通过鼠标单击位置+相机参数计算射线值)
// 3.射线交叉计算
// ObjectsArr是用来做射线拾取的对象数组,一个二维数组
export function rayChoose(event,width, height, camera, ObjectsArr) {
// .offsetY、.offsetX以canvas画布左上角为坐标原点,单位px
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;
//创建一个射线投射器`Raycaster`
const raycaster = new THREE.Raycaster();
//.setFromCamera()计算射线投射器`Raycaster`的射线属性.ray
// 形象点说就是在点击位置创建一条射线,射线穿过的模型代表选中
raycaster.setFromCamera(new THREE.Vector2(x, y), camera);
// 未选中对象返回空数组[],选中一个对象,数组1个元素,选中两个对象,数组两个元素
const intersects = raycaster.intersectObjects(ObjectsArr);
// intersects.length大于0说明,说明选中了模型
let choosedObj = null;
if (intersects.length > 0) {
// 选中模型的第一个模型
choosedObj = intersects[0].object;
} else {
choosedObj = null;
}
return choosedObj;
}
首先得获取射线拾取的对象集合,放在二位数组里,不同的模型,获取集合方式不同,具体要结合模型来写代码,提前跟建模师沟通好物体名称。
例如以下方法:
model.js
import * as THREE from 'three';
// 引入gltf模型加载库GLTFLoader.js
import {
GLTFLoader
} from 'three/addons/loaders/GLTFLoader.js';
export const model = new THREE.Group();
const loader = new GLTFLoader();
export const granaryArr = []; //所有粮仓模型对象的集合,export导出用于射线拾取
loader.load("models/粮仓.glb", function(gltf) {
//把gltf.scene中的所有模型添加到model组对象中
model.add(gltf.scene);
// 所有粮仓模型的父对象名称:'粮仓'
const group = gltf.scene.getObjectByName('粮仓');
//console.log('粮仓', group);
group.traverse(function(obj) {
if (obj.type === 'Mesh') {
granaryArr.push(obj);
}
})
});
在vue文件里,rayChoose要放在addEventListener里使用。
index.vue
<template>
<!-- 封装射线拾取案例 -->
</template>
<script setup>
import {
model,granaryArr
} from './model.js'; //模型对象
import {
renderer,scene,camera,width,height
} from './init.js';
import {
rayChoose
} from '../../utils/rayChoose.js';
scene.add(model); //模型对象添加到场景中
renderer.domElement.addEventListener('click', function(event) {
// choosedObj只能放在addEventListener内部使用
const choosedObj = rayChoose(event, width,height,camera,granaryArr);
console.log(choosedObj);
})
</script>
<style>
</style>
获取到choosedObj后,可以对其进一步处理,比如高光描边,弹出一个信息框等等。