【问题标题】:Three.js indexed BufferGeometry vs. InstancedBufferGeometryThree.js 索引 BufferGeometry 与 InstancedBufferGeometry
【发布时间】:2018-10-09 04:34:59
【问题描述】:

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

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

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

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

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

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

【问题讨论】:

  • 我看到你在另一篇文章中提到了IndexedBufferGeometry,但我仍然不知道你在哪里找到它。这是THREE.js 的事情吗?
  • 您可以查询一个值,该值将为您提供索引的大小。它可以是 16 位,这意味着您只能在一次绘制调用中处理 65536 个顶点。但它也可以是 32 位,但这个限制要高得多。
  • 可能会觉得这很有趣:stackoverflow.com/questions/48798175/…
  • 我已经和三个人一起工作了几年,但从未见过那门课。必须是 v92 中的最新添加。为编辑道歉。
  • 好吧,我坚信歧义会伤害软件 :)。这个问题很有价值,我只是认为它需要改进。

标签: three.js


【解决方案1】:

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

是的,一般来说,BufferGeometries 是处理几何数据的最高效方式,因为它们以与通过 WebGL 与 GPU 通信时使用的格式存储数据。任何普通的 Geometry 在渲染之前都会在内部转换为 BufferGeometry。

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

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

他们在不同的层次上做不同的事情,所以我认为在很多用例中选择它们之间没有多大意义。 事实上,您甚至可以基于“蓝图”几何创建实例化几何,该几何具有索引的 BufferGeometry。

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

实例化几何的特殊之处在于一些额外的属性(在 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 着色器的工作原理有深入了解)。

【讨论】:

  • @MartinSchuhfuß 非常感谢这个非常有用的答案。你知道 THREE.js 中的任何索引和实例化几何的例子吗?如果是这样,我很想看到一个!我正在深入研究一个基本上绘制一堆四边形的场景,每个四边形都有一个纹理,所以我想我还不如去一趟。
  • @duhaime 大多数内置几何图形都默认编入索引。一个更简单的:github.com/mrdoob/three.js/blob/dev/src/geometries/…,例如,我建议您参考我前段时间写的一个代码笔,其中有很多解释性 cmets:codepen.io/usefulthink/pen/YNrvpY?editors=0010
  • 不幸的是,您对缺点的看法是正确的。 github.com/pailhead/three-instanced-mesh 这是为了缓解问题而存在的。
猜你喜欢
  • 2017-12-20
  • 1970-01-01
  • 2014-06-29
  • 2015-04-01
  • 2017-06-12
  • 2013-05-23
  • 1970-01-01
  • 1970-01-01
  • 2020-10-15
相关资源
最近更新 更多