本文摘自PHP中文网,作者angryTom,侵删。

光线投射法
使用three.js自带的光线投射器(Raycaster)选取物体非常简单,代码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
function onMouseMove(event) {
mouse.x = event.clientX / window.innerWidth * 2 - 1;
mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
}
function pick() {
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObjects(scene.children);
}
|
【相关课程推荐:JavaScript视频教程】
它是采用包围盒过滤,计算投射光线与每个三角面元是否相交实现的。
但是,当模型非常大,比如说有40万个面,通过遍历的方法选取物体和计算碰撞点位置将非常慢,用户体验不好。
但是使用gpu选取物体不存在这个问题。无论场景和模型有多大,都可以在一帧内获取到鼠标所在点的物体和交点的位置。
使用GPU选取物体
实现方法很简单:
1. 创建选取材质,将场景中的每个模型的材质替换成不同的颜色。
2. 读取鼠标位置像素颜色,根据颜色判断鼠标位置的物体。
具体实现代码:
1. 创建选取材质,遍历场景,将场景中每个模型替换为不同的颜色。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | let maxHexColor = 1;
scene.traverseVisible(n => {
if (!(n instanceof THREE.Mesh)) {
return ;
}
n.oldMaterial = n.material;
if (n.pickMaterial) {
n.material = n.pickMaterial;
return ;
}
let material = new THREE.ShaderMaterial({
vertexShader: PickVertexShader,
fragmentShader: PickFragmentShader,
uniforms: {
pickColor: {
value: new THREE.Color(maxHexColor)
}
}
});
n.pickColor = maxHexColor;
maxHexColor++;
n.material = n.pickMaterial = material;
});
PickVertexShader:
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
PickFragmentShader:
uniform vec3 pickColor;void main() {
gl_FragColor = vec4(pickColor, 1.0);
}
|
2. 将场景绘制在WebGLRenderTarget上,读取鼠标所在位置的颜色,判断选取的物体。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | let renderTarget = new THREE.WebGLRenderTarget(width, height);
let pixel = new Uint8Array(4);
renderer.setRenderTarget(renderTarget);
renderer.clear();
renderer.render(scene, camera);
renderer.readRenderTargetPixels(renderTarget, offsetX, height - offsetY, 1, 1, pixel);
const currentColor = pixel[0] * 0xffff + pixel[1] * 0xff + pixel[2];
let selected = null ;
scene.traverseVisible(n => {
if (!(n instanceof THREE.Mesh)) {
return ;
}
if (n.pickMaterial && n.pickColor === currentColor) {
selected = n;
}
if (n.oldMaterial) {
n.material = n.oldMaterial; delete n.oldMaterial;
}
});
|
说明:offsetX和offsetY是鼠标位置,height是画布高度。readRenderTargetPixels一行的含义是选取鼠标所在位置(offsetX, height - offsetY),宽度为1,高度为1的像素的颜色。
pixel是Uint8Array(4),分别保存rgba颜色的四个通道,每个通道取值范围是0~255。
完整实现代码:https://gitee.com/tengge1/ShadowEditor/blob/master/ShadowEditor.Web/src/event/GPUPickEvent.js
阅读剩余部分
相关阅读 >>
js (javascript)加密算法库 crypto-js 简介
js怎么清除定时器
js中substring、slice与substr的区别有哪些?
js如何实现滑动门效果
分享几个实用的单行 js 代码
如何利用js实现音乐导航效果
jquery 过时了吗?
js中闭包是什么
css和js后加问号和数字有什么用
如何实现ajax请求?
更多相关阅读请进入《three.js》频道 >>
人民邮电出版社
本书对 Vue.js 3 技术细节的分析非常可靠,对于需要深入理解 Vue.js 3 的用户会有很大的帮助。——尤雨溪,Vue.js作者
转载请注明出处:木庄网络博客 » three.js使用gpu选取物体并计算交点位置