1

据我了解,OpenGL 中的 indexing 或IBOs 主要用于减少为给定几何图形绘制所需的顶​​点数。我知道使用索引缓冲区,OpenGL 只绘制具有给定索引的顶点并跳过任何其他顶点。但这不是消除了使用纹理的可能性吗?据我所知,如果您跳过带有索引缓冲区的顶点,它也会跳过它们的顶点属性吗?如果我的顶点属性设置如下:

attribute vec4 v_Position;
attribute vec2 v_TexCoord;

然后使用索引缓冲区glDrawElements(...),这不会消除纹理的使用,还是v_Position会“重用”?如果他们不这样做,我如何在使用索引缓冲区时纹理?

4

2 回答 2

4

我认为您误解了几个关键术语。

“顶点属性”是定义每个单独顶点的数据。虽然这些包括纹理坐标,但它们也包括位置。事实上,至少如果你不使用固定函数,顶点属性的含义是完全任意的;它们的含义由顶点着色器如何使用和/或将它们转发到后续着色器阶段来定义。

因此,位置、纹理坐标和任何其他顶点属性如何转发到顶点着色器之间没有区别。无论如何使用(或不使用)索引,它们都被完全相同地解析。

一个示例顶点着色器:

layout(location = 0) in vec4 position;
layout(location = 1) in vec2 uvAttr;

out vec2 uv;

void main( )
{
    uv = uvAttr;
    gl_Position = position;
}

以及与上述配对的片段着色器的开头:

in vec2 uv;

如您所见,顶点着色器的输出基于顶点属性。然后在将其发送到片段着色器之前,将该输出插值到由图元组装生成的面上。原始装配是索引发挥作用的主要场所:索引确定如何使用顶点着色器输出来创建实际几何体。然后将该几何体分解为片段,这些片段实际上会影响渲染输出。顶点着色器的输出成为片段着色器的输入。

在顶点着色器之后,顶点属性不再被定义。只有如上所述转发它们,才能访问它们以用于纹理等用途。因此,您甚至没有首先将顶点属性本身用作纹理坐标:您使用的是顶点着色器输出的变量并在原始组装/光栅化中进行插值。

“如果你跳过带有索引缓冲区的顶点,它也会跳过它们的顶点属性”

是的 - 它完全忽略了顶点:纹理坐标、位置以及您为该顶点定义的任何其他内容。但只有跳过的顶点。其余的继续正常处理,就好像跳过的顶点不存在一样。

例如。让我们说为了论证我有 5 个顶点。我将这些订购成蝴蝶结形状,如下所示。每个顶点都有位置(只有 x 和 y 的 2 个分量向量)和一个用作颜色的单个分量“亮度”。领结的中心顶点仅定义一次,但通过索引引用两次。

示例 1

顶点属性为:

  1. [(1, 1), 0.5], 又名 [(x, y), 亮度]
  2. [(1, 5), 0.5]
  3. [(3, 3), 0.0]
  4. [(5, 5), 0.5]
  5. [(5, 1), 0.5]

索引为:1、2、3、4、5、3。

请注意,在此示例中,“亮度”也可以代表您的 UV(W) 坐标。它将被类似地插值,就像一个向量。正如我之前所说,顶点属性的含义是任意的。

现在,由于您要询问是否跳过顶点,因此如果我将索引更改为 1、2、4,则输出如下:

示例 2

这将是 1、2、3:

示例 3

看到这里的模式了吗?OpenGL 只关心构成它生成的面的顶点,仅此而已。索引仅仅改变了这些面的组合方式(并且可以使它跳过完全计算的不需要的顶点)。它们对所使用的顶点的含义没有影响,并且确实进入了面。如果黑色顶点#3 被跳过,它不会对任何面产生影响,因为它不是任何面的一部分

顺便说一句,该标准允许实现在单个绘制调用中重用顶点着色器输出。因此,您应该期望重复使用相同的索引可能不会导致额外的顶点着色器调用。我说“可能不是”,因为你的司机实际上做的总是巫毒。

请注意,在此我有意忽略了曲面细分和几何着色器。这些是超出此问题范围的主题,但可能对如何处理顶点属性有一些有趣的影响。我还忽略了这样一个事实,即顶点的顺序可以在一定程度上在着色器中访问,因此可能会影响输出。

于 2016-03-15T07:14:35.120 回答
2

索引缓冲区用于速度。

使用索引缓冲区,顶点缓存用于存储最近转换的顶点。在转换过程中,如果索引指向的顶点已经转换并且在顶点缓存中可用,则重新使用它,否则,顶点被转换。如果没有索引缓冲区,就无法使用顶点缓存,因此顶点总是会被转换。这就是为什么对索引进行排序以最大化顶点缓存命中很重要的原因。

索引缓冲区也用于减少内存占用。

单个顶点数据通常非常大。例如:存储单精度浮点位置数据(x,y,z)需要12个字节(假设每个浮点数需要4个字节)。如果包含顶点颜色、纹理坐标或顶点法线,则此内存需求会变得更大。

如果您有一个由两个三角形组成的四边形,每个顶点仅包含位置数据(x,y,z)。如果没有索引缓冲区,则需要 6 个顶点(72 个字节)来存储一个四边形。使用 16 位索引缓冲区,您只需要 4 个顶点(48 字节)+ 6 个索引(6*2 字节 = 12 字节)= 60 字节来存储一个四边形。使用索引缓冲区,如果您有许多共享顶点,则此内存需求会变小。

于 2016-03-15T06:49:55.380 回答