Three.js索引BufferGeometry与InstancedBufferGeometry

时间:2018-04-28 14:18:23

标签: three.js

我试图在THREE.js中了解有关高性能几何的更多信息,并且已经了解索引的BufferGeometry和InstancedBufferGeometry是两种性能最高的几何类型。

到目前为止,我的理解是在索引的BufferGeometry中,在几何中重复使用的顶点只被添加到几何体中一次,并且给定重用顶点的每个实例都由它们在顶点中的索引位置引用阵列。

我对InstancedBufferGeometry的理解是,这种几何形状允许人们创建一个&#34;蓝图&#34;对象的一个​​副本,将该对象的顶点的一个副本发送到着色器,然后使用自定义属性修改蓝图的位置,旋转,比例等的每个副本。[source] < / p>

我想更好地理解:是否存在索引的BufferGeometry比InstancedBufferGeometry更高效的情况。

另外,在InstancedBufferGeometry中,是否有必须考虑的WebGL最大参数(例如每个网格的最大顶点)以避免网格过大?如何计算InstancedBufferGeometry中的顶点?

如果有人可以帮助澄清应该使用索引的BufferGeometry和InstancedBufferGeometry的情况,以及InstancedBufferGeometry的性能上限,我将非常感激。

1 个答案:

答案 0 :(得分:9)

  

[...] IndexedBufferGeometry和InstancedBufferGeometry是两种性能最佳的几何类型。

是的,BufferGeometries通常是处理几何数据的最高性能方式,因为它们以与通过WebGL与GPU通信中使用的格式精确地存储数据。在渲染之前,任何普通的几何体都会在内部转换为BufferGeometry。

您对索引和实例化几何的描述也是正确的,但是我想再详细说明一下:在索引几何中,GPU如何组装三角形的指令与顶点分开-data并以特殊的索引属性呈现给GPU(而不是非索引数组的顶点的隐含部分)。

  

我想更好地理解:是否存在IndexedBufferGeometry比InstancedBufferGeometry更高效的情况。

他们在不同的层面做不同的事情,所以我不认为有很多用例,他们之间的选择很有意义。 实际上,您甚至可以基于具有索引的BufferGeometry的&#34; blueprint&#34; -geometry来创建实例化几何体。

让我们深入了解细节进行解释。实例化几何体允许您渲染多个&#34;克隆&#34;在单次绘制调用中使用相同的&#34; blueprint&#34; -geometry。 第一部分,即蓝图的创建,与渲染单个几何体相同。为此,需要将属性(位置,法线,uv坐标以及索引几何的索引)传输到GPU。

instanced几何的特殊之处是一些额外的属性(在three.js InstancedBufferAttribute中)。它们控制几何体的渲染次数,并提供一些特定于实例的值。一个典型的用例是为实例位置增加一个vec3属性,为每个实例添加一个vec4属性。但它确实可能是其他任何东西。

在顶点着色器中,这些特殊属性看起来就像任何其他属性一样,您需要为每个顶点手动应用特定于实例的更新。所以不要这样:

attribute vec3 position;
void main() {
  gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}

你会有这样的事情:

attribute vec3 position;
attribute vec3 instanceOffset; // this is the InstancedBufferAttribute
void main() {
  gl_Position = 
    projectionMatrix 
    * modelViewMatrix 
    * vec4(position + instanceOffset, 1.0);
}

你在这里看到的是,实例化版本中的顶点着色器不仅会在几何体的每个顶点被调用一次(正如常规渲染的情况),而是每个顶点和实例一次。

所以实际上并没有任何魔法,实例几何实际上只是表达整个几何重复的一种非常有效的方式。

  

另外,在InstancedBufferGeometry中,是否有必须考虑的WebGL最大参数(例如每个网格的最大顶点)以避免网格过大?

我不确定,但到目前为止我还没有遇到任何问题。如果您知道渲染1000个具有1000个顶点的对象的实例将调用顶点着色器一百万次,这将有助于您判断性能影响。

  

如果有人可以帮助澄清应该使用IndexedBufferGeometry和InstancedBufferGeometry的情况,以及InstancedBufferGeometry的性能上限,我将非常感激。

您可以(也许应该)使用索引几何图形来处理几乎任何类型的几何图形。但它们并非没有缺点:

  • 使用索引时,所有属性都将获得相同的处理。例如,您不能在索引几何中使用每面颜色(请参阅Access to faces in BufferGeometry
  • 对于点云或具有少量重复顶点的几何图形,它们弊大于利(由于索引需要额外的内存/带宽)

大部分时间虽然他们会获得性能优势:

  • 顶点数据所需的内存/带宽更少
  • GPU可以缓存顶点着色器的结果,并将它们重复用于重复的顶点(因此,在最佳情况下,您最终会为每个存储的顶点调用一次VS调用,而不是每个索引)

例如几何

  • 如果你有更多的有些相似的对象,其差异只能用几个数字表示,那就去实例几何(简单的情况:在不同的位置渲染同一个对象的副本,复杂的情况:渲染一个森林基于某个实例属性更改树的几何体,或通过使用实例属性更改个人姿势来渲染一群人)
  • 我发现另一件令人鼓舞的事情:使用实例渲染胖线:使用实例渲染一堆线段,其中每个线段由6个三角形组成(参见https://github.com/mrdoob/three.js/blob/dev/examples/js/lines/LineSegmentsGeometry.js @WestLangley)

缺点:

  • 就像现在一样,没有内置支持将常规材料与实例几何一起使用。你必须自己编写着色器。 (确切地说:有一种方法可以做到这一点,但它需要对three.js着色器的工作方式有一些了解。)