根据 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));
将您的对象重新创建为 Buffer Geometry(性能更快):
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