我成功地根据TheJim01的答案,为WebGL1创建了一个可工作的版本!
首先创建第二个更简单的场景用于计算:
pickingScene = new THREE.Scene();
pickingTextureOcclusion = new THREE.WebGLRenderTarget(window.innerWidth / 2, window.innerHeight / 2);
pickingMaterial = new THREE.MeshBasicMaterial({ vertexColors: THREE.VertexColors });
pickingScene.add(new THREE.Mesh(BufferGeometryUtils.mergeBufferGeometries([
createBuffer(geometry, mesh),
createBuffer(geometry2, mesh2)
]), pickingMaterial));
重新创建您的对象为缓冲几何体(性能更快):
function createBuffer(geometry, mesh) {
var buffer = new THREE.SphereBufferGeometry(geometry.parameters.radius, geometry.parameters.widthSegments, geometry.parameters.heightSegments);
quaternion.setFromEuler(mesh.rotation);
matrix.compose(mesh.position, quaternion, mesh.scale);
buffer.applyMatrix4(matrix);
applyVertexColors(buffer, color.setHex(mesh.name));
return buffer;
}
根据mesh.name添加颜色,例如id 1、2、3等
function applyVertexColors(geometry, color) {
var position = geometry.attributes.position;
var colors = [];
for (var i = 0; i < position.count; i ++) {
colors.push(color.r, color.g, color.b);
}
geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
}
然后在渲染循环期间,检查第二个场景中的纹理,并将像素数据与网格名称匹配:
function isOccludedBuffer(object) {
renderer.setRenderTarget(pickingTextureOcclusion);
renderer.render(pickingScene, camera);
var pixelBuffer = new Uint8Array(window.innerWidth * window.innerHeight);
renderer.readRenderTargetPixels(pickingTextureOcclusion, 0, 0, window.innerWidth / 2, window.innerHeight / 2, pixelBuffer);
renderer.setRenderTarget(null);
return !pixelBuffer.includes(object.name);
}
您可以在此处查看WebGL1的演示:
https://jsfiddle.net/kmturley/nb9f5gho/62/
需要注意的一点是,使用这种方法时,
您的拾取场景需要与主场景中的更改保持同步。因此,如果您的对象移动位置/旋转等,则它们也需要在拾取场景中进行更新。在我的示例中,相机在移动,而不是对象,因此不需要更新。
对于WebGL2,我们将有一个更好的解决方案:
https://tsherif.github.io/webgl2examples/occlusion.html
但并非所有浏览器都支持此功能:
https://www.caniuse.com/#search=webgl