首页 > 解决方案 > ThreeJS InstancedBufferGeometry 剔除问题?

问题描述

当我渲染 3000 个模型实例并将它们保留在视图区域中时,我得到 55FPS,但是如果我有 5000 个模型实例但将其中 2000 个实例保留在视图区域之外,我仍然得到 40 FPS。

camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.01, 10000);

它是否有可能正确剔除,但它必须确定它是否被剔除是什么减慢了它的速度?我主要来自https://github.com/mrdoob/three.js/blob/master/examples/webgl_buffergeometry_instancing_dynamic.html

编辑* 我知道我可以使用 geometry.maxInstancedCount = trackCount; 这很有帮助,但它与剔除并不完全相同,因为我的轨道超出了当前视口,它仍然会损害性能

有什么建议么?或想法?

标签: three.js

解决方案


对于实例几何,three.js 不能进行任何截锥体剔除,因为没有关于对象将在哪里结束的信息。这将在顶点着色器中计算,并且three.js 不知道那里发生了什么。

任何剔除发生的最早时间是在为每个实例的每个顶点运行顶点着色器之后。这已经解释了您所看到的帧速率下降。尽管可见相同数量的对象/三角形,但顶点着色器调用的数量高达 166%。

如果您想自己实现剔除,您可以尝试为每一帧重新排列属性缓冲区中的实例(跳过不可见实例)并将最大实例计数调整为可见实例的数量。这可能有点违反直觉,但是在每一帧上重新计算所有实例属性缓冲区实际上可以在这里提供更好的性能。

要进行可见性测试,最简单的方法可能是使用THREE.Frustum()类和frustum.containsPoint(). 看起来像这样

const frustum = new Frustum();
const projScreenMatrix = new Matrix();

// assume instances is an array of objects containing all the 
// relevant information for all instances
const instances = [
  // {position: ...}, {position: ...}, ...
];

// for every frame
projScreenMatrix.multiplyMatrices(
  camera.projectionMatrix, 
  camera.matrixWorldInverse 
);
frustum.setFromMatrix(projScreenMatrix);

let visibleInstanceCount = 0;

for (let i = 0; i < instanceCount; i++) {
  const pos = instances[i].position;

  if (!frustum.containsPoint(pos)) {
    continue;
  }

  // add instance to instance-attribute buffers
  pos.toArray(instancePositionBuffer, visibleInstanceCount * 3);
  visibleInstanceCount++;
}

geometry.maxInstanceCount = visibleInstanceCount;

推荐阅读