物件選擇 GPU

根據你的設定(例如,如果你沒有像設定這樣的八叉樹)和場景中的物件數量,使用 Raycasting 進行物件拾取對你的 CPU 來說可能是一項繁重的任務。

如果你不需要滑鼠游標下的世界座標,但僅用於識別其下的物件,則可以使用 GPU 拾取。

簡短的解釋,GPU 可以是一個強大的計算工具,但你需要知道如何獲得結果。我們的想法是,如果使用表示其 id 的顏色渲染物件,則可以讀取游標下畫素的顏色並找出所拾取物件的 id。記住 RGB 只是十六進位制值,因此 id(整數)和顏色(hex)之間存在轉換。

  1. 為物件建立新場景和新渲染目標
var pickingScene = new THREE.Scene();
var pickingTexture = new THREE.WebGLRenderTarget(renderer.domElement.clientWidth, renderer.domElement.clientHeight);
    pickingTexture.texture.minFilter = THREE.LinearFilter;
  1. 為物件拾取建立新的著色器材質;
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
    });
  1. 新增網格/線幾何圖形,在 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;
}
  1. 最後,在滑鼠單擊處理程式上
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
}