Three.js索引BufferGeometry与InstancedBufferGeometry(Three.js indexed BufferGeometry vs. InstancedBuffer

编程入门 行业动态 更新时间:2024-10-28 05:28:06
Three.js索引BufferGeometry与InstancedBufferGeometry(Three.js indexed BufferGeometry vs. InstancedBufferGeometry)

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

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

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

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

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

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

I'm trying to learn more about performant geometries in THREE.js, and have come to understand that an indexed BufferGeometry and InstancedBufferGeometry are the two most performant geometry types.

My understanding so far is that in an indexed BufferGeometry, vertices that are re-used in a geometry are only added to the geometry once, and each instance of a given re-used vertex are referenced by their index position in the vertex array.

My understanding of the InstancedBufferGeometry is that this geometry allows one to create a "blueprint" of an object, send one copy of that object's vertices to a shader, then use custom attributes to modify each copy of the blueprint's position, rotation, scale, etc. [source]

I'd like to better understand: are there cases in which an indexed BufferGeometry will be more performant than the InstancedBufferGeometry.

Also, in the InstancedBufferGeometry, are there WebGL maximum parameters (such as maximum vertices per mesh) that one must consider so as to avoid making a mesh too large? How are the vertices in an InstancedBufferGeometry counted?

If anyone could help clarify the situations in which indexed BufferGeometry and InstancedBufferGeometry should be used, and the performance ceilings of InstancedBufferGeometry, I'd be very grateful.

最满意答案

[...] 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的性能上限,我将非常感激。

您可以(也可能应该)将索引几何用于几乎任何类型的几何体。 但它们并非没有缺点:

当使用索引时,所有属性都将得到相同的处理。 因此,例如,您不能在索引几何中使用每面颜色(请参阅在BufferGeometry中访问面 ) 对于具有很少重复顶点的点云或几何,它们将弊大于利(由于索引需要额外的内存/带宽)

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

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

例如几何形状

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

缺点:

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

[...] IndexedBufferGeometry and InstancedBufferGeometry are the two most performant geometry types.

Yes, BufferGeometries in general are the most performant way to deal with geometry-data as they store data in exactly the format that is used in the communication with the GPU via WebGL. Any plain Geometry is internally converted to a BufferGeometry before rendering.

You are also correct in your descriptions of the indexed and instanced geometries, but I'd like to note one more detail: In an indexed geometry, the instructions for the GPU how to assemble the triangles are separated from the vertex-data and presented to the GPU in a special index-attribute (as opposed to being an implied part of the vertices for non-indexed arrays).

I'd like to better understand: are there cases in which an IndexedBufferGeometry will be more performant than the InstancedBufferGeometry.

They do different things at different levels, so I don't think there are many use-cases where a choice between them makes much sense. In fact, you can even create an instanced geometry based on a "blueprint"-geometry that has is an indexed BufferGeometry.

Let's dive a bit into the details to explain. An instanced geometry allows you to render multiple "clones" of the same "blueprint"-geometry in a single draw-call. The first part of this, the creation of the blueprint, is identical to rendering a single geometry. For this, the attributes (positions, normals, uv-coordinates and possibly the index for an indexed geometry) need to be transferred to the GPU.

The special thing for instanced geometries are some extra attributes (in three.js InstancedBufferAttribute). These control how many times the geometry will be rendered and provide some instance-specific values. A typical use-case would be to have an additional vec3-attribute for the instance-position and a vec4-attribute for the quaternion per instance. But it really could be anything else as well.

In the vertex-shader, these special attributes look just like any other attribute and you need to manually apply the instance-specific updates per vertex. So instead of this:

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

You would have something like this:

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

What you don't see here is that the vertex-shader in the instanced version will not only be called once per vertex of your geometry (as it is the case for regular rendering) but once per vertex and instance.

So there isn't actually any magic going on, instanced geometries are in fact nothing but a very efficient way to express duplication of entire geometries.

Also, in the InstancedBufferGeometry, are there WebGL maximum parameters (such as maximum vertices per mesh) that one must consider so as to avoid making a mesh too large?

I am not sure about that, but I didn't encounter any so far. If you are aware that rendering 1000 instances of an object with 1000 vertices will invoke the vertex-shader a million times that should help your judgement of performance implications.

If anyone could help clarify the situations in which IndexedBufferGeometry and InstancedBufferGeometry should be used, and the performance ceilings of InstancedBufferGeometry, I'd be very grateful.

You can (and maybe should) use indexed geometries for almost any kind of geometry. But they are not free of drawbacks:

when using indices, all attributes will get the same treatment. So for instance, you can't use per-face colors in indexed geometries (see Access to faces in BufferGeometry) for point-clouds or geometries with little repeated vertices, they will do more harm than good (due to the extra amount of memory/bandwidth needed for the index)

most of the time though they will get a performance-benefit:

less memory/bandwidth required for vertex-data GPUs can cache results of vertex-shaders and re-use them for repeated vertices (so, in an optimal case you'd end up with one VS-invocation per stored vertex, not per index)

For instanced geometries

if you have a larger number of somewhat similar objects where the differences can be expressed in just a few numbers, go for instanced geometries (simple case: render copies of the same object at different locations, complex case: render a forest by changing the tree's geometry based on some instance-attribute or render a crowd of people by changing the individual persons pose with an instance-attribute) another thing I found quite inspiring: rendering of fat lines using instancing: use instancing to render a bunch of line-segments where each line-segment consists of 6 triangles (see https://github.com/mrdoob/three.js/blob/dev/examples/js/lines/LineSegmentsGeometry.js by @WestLangley)

Drawbacks:

as it is right now, there is no builtin-support for using regular materials together with instanced geometries. You have to write your shaders yourself. (to be precise: there is a way to do it, but it requires some intimate knowledge of how the three.js shaders work).

更多推荐

本文发布于:2023-08-02 22:51:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1381552.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:索引   js   BufferGeometry   indexed   InstancedBufferGeometry

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!