为什么存在 glVertexAttribPointer 的不同变体?

Why do different variations of glVertexAttribPointer exist?

glVertexAttribPointer()
glVertexAttribIPointer()
glVertexAttribLPointer()

据我所知,glVertexAttribPointer可以代替其他两个

如果是,为什么存在 IL 变体?

我在 OpenGL Insights 中看到了这个

使用 glVertexAttribPointer() 时,所有内容都会转换为浮点数。虽然 glVertexAttribIPointer() 只能公开存储整数的顶点数组,而 glVertexAttribLPointer() 仅适用于双精度数。

正如对此 OpenGL.org page 的引述所证实:

For glVertexAttribPointer, if normalized​ is set to GL_TRUE​, it indicates that values stored in an integer format are to be mapped to the range [-1,1] (for signed values) or [0,1] (for unsigned values) when they are accessed and converted to floating point. Otherwise, values will be converted to floats directly without normalization.

For glVertexAttribIPointer, only the integer types GL_BYTE​, GL_UNSIGNED_BYTE​, GL_SHORT​, GL_UNSIGNED_SHORT​, GL_INT​, GL_UNSIGNED_INT​ are accepted. Values are always left as integer values.

glVertexAttribLPointer specifies state for a generic vertex attribute array associated with a shader attribute variable declared with 64-bit double precision components. type​ must be GL_DOUBLE​. index​, size​, and stride​ behave as described for glVertexAttribPointer and glVertexAttribIPointer.

不可以,它们不能相互代替使用。

传统上,GL的所有顶点属性都是浮点数。您可以输入整数数据这一事实并没有改变这一点——数据会即时转换为浮点数。 normalized 参数控制转换的完成方式,如果启用,输入类型的范围将映射到规范化的 [0,1](对于无符号类型,也称为 GL 的 UNORM)或 [- 1,1](对于有符号类型,也称为SNORM),如果禁用,则将值直接转换为输入整数最接近的浮点值。

由于这是原始的 API,因此在引入不同的属性数据类型(整数和双精度)时必须对其进行扩展。另请注意,属性指针独立于着色器,因此目标值不能由当前绑定的着色器(如果有)确定,因为稍后可能会与不同的着色器一起使用。因此,L 变体 ID 用于 double/dvec 属性,而 I 变体用于 int/uint/ivec/uvec 属性。

测试一下,你就会明白其中的区别。

假设您正在使用以下顶点着色器进行变换反馈:

#version 450 core
layout(location = 0) in int input;
layout(xfb_offset = 0) out float output;

void main()
{
    output = sqrt(input);
}

这是你的 "vertex data":

GLint data[] = { 1, 2, 3, 4, 5 };

那么如果你像这样设置顶点属性:

glVertexAttribPointer(0, 1, GL_INT, GL_FALSE, 0, nullptr);

你会得到错误和奇怪的结果。


如果在顶点着色器中更改此行

output = sqrt(input);

output = sqrt(intBitsToFloat(input));

在 C++ 代码中更改此行:

glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
                            ^^^^^^^^
                            does not match the real input type
                            but stops glVertexAttribPointer() converting them

它会起作用的。但这不是自然的方式。


现在glVertexAttribIPointer()来帮忙:

--- glVertexAttribPointer(0, 1, GL_INT, GL_FALSE, 0, nullptr);
+++ glVertexAttribIPointer(0, 1, GL_INT, 0, nullptr);

那么你会得到正确的结果。

(为此折腾了一下午,才找到glVertexAttribIPointer()。)