我试图检测Three.js中的一个对象何时被另一对象部分或完全遮挡(隐藏)。
我当前的简单解决方案将一条光线投射到对象的中心:
function getScreenPos(object) {
var pos = object.position.clone();
camera.updateMatrixWorld();
pos.project(camera);
return new THREE.Vector2(pos.x, pos.y);
}
function isOccluded(object) {
raycaster.setFromCamera(getScreenPos(object), camera);
var intersects = raycaster.intersectObjects(scene.children);
if (intersects[0] && intersects[0].object === object) {
return false;
} else {
return true;
}
}
但是它不能说明对象的尺寸(宽度,高度,深度)。
查看工作演示:
https://jsfiddle.net/kmturley/nb9f5gho/57/
当前认为我可以计算对象框的大小,并为框的每个角投射光线。但这可能仍然太简单了:
var box = new THREE.Box3().setFromObject(object);
var size = box.getSize();
我想找到一种更健壮的方法,该方法可以提供partially occluded
和fully occluded
布尔值,甚至可以是percentage occluded
?
答案 0 :(得分:2)
我根据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;
}
根据网格名称添加颜色。 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
但是尚不支持所有浏览器:
答案 1 :(得分:1)
搜索堆栈溢出和“ GPU选择”的Three.js示例。这个概念可以分为三个基本步骤:
MeshBasicMaterial
)颜色。您的情况允许您进行一些警告。
现在有了像素数据,您可以确定以下内容:
第二个项目符号说形状是“至少部分”可见的。这是因为您无法使用当前的信息测试完全可见性。
I 会做的事情(还有其他人可能会有更好的解决方案)是第二次渲染相同的视口,但是只能看到测试形状,这是等同于完全可见的部分。掌握了这些信息之后,将像素与第一个渲染进行比较。如果两者的唯一颜色像素数相同(可能在公差范围内),则可以说该零件是完全可见的/未被遮挡的。