根据我的理解,OpenGL中的索引或IBO
主要用于减少为给定几何绘制所需的顶点数。据我所知,使用索引缓冲区,OpenGL只绘制具有给定索引的顶点并跳过任何其他顶点。但是没有消除使用纹理的可能性吗?据我所知,如果你跳过带索引缓冲区的顶点,它还会跳过它们的顶点属性?如果我的顶点属性设置如下:
attribute vec4 v_Position;
attribute vec2 v_TexCoord;
然后使用索引缓冲区和glDrawElements(...)
,不会消除纹理的使用,或v_Position
得到"重复使用"?如果他们不这样做,我在使用索引缓冲区时如何纹理?
答案 0 :(得分: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,2,3,4,5,3。
请注意,在此示例中,"亮度"也许代表你的UV(W)坐标。它将被类似地插值,就像矢量一样。正如我之前所说,顶点属性的含义是任意的。
现在,既然您要求跳过顶点,那么如果我将索引更改为1,2,4,那么输出就是这样:
这将是1,2,3:
在这里查看模式? OpenGL关注构成它生成的面的顶点,没有别的。索引只是改变这些面的组合方式(并且可以使它跳过完全计算的不需要的顶点)。它们对使用的顶点的含义没有影响,并且会进入面。如果跳过黑色顶点#3,它对任何面部都没有贡献,因为它不是任何面部的部分。
另外,该标准允许实现在单个绘制调用中重用顶点着色器输出。因此,您应该期望重复使用相同的索引可能不会导致其他顶点着色器调用。我说"可能不是"因为你的司机实际上做的事情总是伏都好。
请注意,在此我故意忽略了tesselation和几何着色器。这些是超出此问题范围的主题,但可以对顶点属性的处理方式产生一些有趣的影响。我也忽略了这样一个事实,即顶点的排序可以在着色器中被访问一定程度,因此可能会影响输出。
答案 1 :(得分:2)
索引缓冲区用于速度。
使用索引缓冲区,顶点缓存用于存储最近转换的顶点。在变换期间,如果索引指向的顶点已经变换并且在顶点缓存中可用,则会重新使用它,否则会转换顶点。如果没有索引缓冲区,则无法使用顶点缓存,因此顶点总是会被转换。这就是为什么命令索引最大化顶点缓存命中很重要。
索引缓冲区还用于减少内存占用。
单顶点数据通常非常大。例如:存储位置数据(x,y,z)的单精度浮点需要12个字节(假设每个浮点数需要4个字节)。如果包含顶点颜色,纹理坐标或顶点法线,则此内存要求会变大。
如果你有一个由两个三角形组成的四边形,每个顶点只包含位置数据(x,y,z)。如果没有索引缓冲区,则需要6个顶点(72个字节)来存储四元组。使用16位索引缓冲区,您只需要4个顶点(48个字节)+ 6个索引(6 * 2个字节= 12个字节)= 60个字节来存储四元组。使用索引缓冲区,如果您有许多共享顶点,则此内存要求会变小。