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;
}

首先得获取射线拾取的对象集合,放在二位数组里,不同的模型,获取集合方式不同,具体要结合模型来写代码,提前跟建模师沟通好物体名称。

threejs:射线拾取封装_第1张图片

例如以下方法:

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






获取到choosedObj后,可以对其进一步处理,比如高光描边,弹出一个信息框等等。

你可能感兴趣的:(javascript,开发语言,前端)