Three.js索引BufferGeometry与InstancedBufferGeometry

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Three.js索引BufferGeometry与InstancedBufferGeometry相关的知识,希望对你有一定的参考价值。

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

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

我对InstancedBufferGeometry的理解是,这个几何允许人们创建一个对象的“蓝图”,将该对象的顶点的一个副本发送到着色器,然后使用自定义属性来修改蓝图的位置,旋转,比例等的每个副本。 。[source]

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

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

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

答案

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

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

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

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

他们在不同的层面做不同的事情,所以我认为有很多用例,他们之间的选择很有意义。实际上,您甚至可以基于具有索引BufferGeometry的“blueprint”-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个三角形组成(参见@WestLangley的https://github.com/mrdoob/three.js/blob/dev/examples/js/lines/LineSegmentsGeometry.js

缺点:

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

以上是关于Three.js索引BufferGeometry与InstancedBufferGeometry的主要内容,如果未能解决你的问题,请参考以下文章

Three.js教程:顶点索引复用顶点数据

绘制不断变色的台体,BufferGeometry和ShaderMaterial的黄金组合(three.js实战5)

Three.js 中 BufferGeometry 的渲染顺序

绘制彩色立方体,使用attribute变量向着色器传值,BufferGeometry和ShaderMaterial配合使用(three.js实战6)

三维空间中绘制点线面UV贴图,万能的BufferGeometry(three.js实战4)

使用 bufferGeometry 获取 THREE.js Points 对象中顶点的屏幕坐标