索引到底是如何工作的?

tub*_*erd 1 c c++ opengl indexing index-buffer

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

attribute vec4 v_Position;
attribute vec2 v_TexCoord;
Run Code Online (Sandbox Code Playgroud)

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

小智 5

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

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

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

顶点着色器示例:

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

out vec2 uv;

void main( )
{
    uv = uvAttr;
    gl_Position = position;
}
Run Code Online (Sandbox Code Playgroud)

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

in vec2 uv;
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

例如。为了便于论证,我们假设我有 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 被跳过,它不会对任何面产生影响,因为它不是任何面的一部分。

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

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