对象选择 GPU
根据你的设置(例如,如果你没有像设置这样的八叉树)和场景中的对象数量,使用 Raycasting 进行对象拾取对你的 CPU 来说可能是一项繁重的任务。
如果你不需要鼠标光标下的世界坐标,但仅用于识别其下的对象,则可以使用 GPU 拾取。
简短的解释,GPU 可以是一个强大的计算工具,但你需要知道如何获得结果。我们的想法是,如果使用表示其 id 的颜色渲染对象,则可以读取光标下像素的颜色并找出所拾取对象的 id。记住 RGB 只是十六进制值,因此 id(整数)和颜色(hex)之间存在转换。
- 为对象创建新场景和新渲染目标
var pickingScene = new THREE.Scene();
var pickingTexture = new THREE.WebGLRenderTarget(renderer.domElement.clientWidth, renderer.domElement.clientHeight);
pickingTexture.texture.minFilter = THREE.LinearFilter;
- 为对象拾取创建新的着色器材质;
var vs3D = `
attribute vec3 idcolor;
varying vec3 vidcolor;
void main(){
vidcolor = idcolor;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0);
}`;
var fs3D = `
varying vec3 vidcolor;
void main(void) {
gl_FragColor = vec4(vidcolor,1.0);
}`;
var pickingMaterial = new THREE.ShaderMaterial(
{
vertexShader: vs3D,
fragmentShader: fs3D,
transparent: false,
side: THREE.DoubleSide
});
- 添加网格/线几何图形,在 RGB 中表示其 id 的新属性,使用相同的几何图形创建 pickingObject 并将其添加到拾取场景,并将实际网格添加到 id-> object 字典
var selectionObjects = [];
for(var i=0; i<myMeshes.length; i++){
var mesh = myMeshes[i];
var positions = mesh.geometry.attributes["position"].array;
var idColor = new Float32Array(positions.length);
var color = new THREE.Color();
color.setHex(mesh.id);
for (var j=0; j< positions.length; j+=3){
idColor[j] = color.r;
idColor[j+1] = color.g;
idColor[j+2] = color.b;
}
mesh.geometry.addAttribute('idcolor', new THREE.BufferAttribute(idColor, 3));
var pickingObject = new THREE.Mesh(mesh.geometry, pickingMaterial);
pickingScene.add(pickingObject);
selectionObjects[mesh.id] = mesh;
}
- 最后,在鼠标单击处理程序上
renderer.render(pickingScene, camera, pickingTexture);
var pixelBuffer = new Uint8Array(4);
renderer.readRenderTargetPixels(pickingTexture, event.pageX, pickingTexture.height - event.pageY, 1, 1, pixelBuffer);
var id = (pixelBuffer[0] << 16) | (pixelBuffer[1] << 8) | (pixelBuffer[2]);
if (id>0){
//this is the id of the picked object
}else{
//it's 0. clicked on an empty space
}