Why do different variations of glVertexAttribPointer exist?
Have a test and you will understand the difference.
Suppose you are doing transform feedback with the following vertex shader:
#version 450 core
layout(location = 0) in int input;
layout(xfb_offset = 0) out float output;
void main()
{
output = sqrt(input);
}
And this is your "vertex data":
GLint data[] = { 1, 2, 3, 4, 5 };
Then if you setup vertex attributes like this:
glVertexAttribPointer(0, 1, GL_INT, GL_FALSE, 0, nullptr);
You will get wrong and strange results.
If you change this line in the vertex shader
output = sqrt(input);
to
output = sqrt(intBitsToFloat(input));
OR
change this line in C++ code:
glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
^^^^^^^^
does not match the real input type
but stops glVertexAttribPointer() converting them
It will work. But this is not a natural way.
Now glVertexAttribIPointer()
comes to help:
--- glVertexAttribPointer(0, 1, GL_INT, GL_FALSE, 0, nullptr);
+++ glVertexAttribIPointer(0, 1, GL_INT, 0, nullptr);
Then you will get correct results.
(I struggled for this for a whole afternoon until I found glVertexAttribIPointer()
.)
No, they can't be used instead of each other.
Traditionally, all vertex attributes of the GL are floating-point. The fact that you can input integer data doesn't change that - the data is converted to floating-point on the fly. The normalized
parameter controls how the conversion is done, if it is enabled, the range of the input type is mapped to the normalized [0,1] (for unsigned types, also called UNORM ing the GL) or [-1,1] (for signed types, also called SNORM), if it is disabled, the value is directly converted to the nearest floating-point value of the input integer.
Since this was the original API, it had to be extended when different attribute data types (integers and doubles) were introduced. Also note that the attribute pointers are independent of the shaders, so the target value cannot be determined by the currently bound shader (if any), as this might be used with different shaders later on. So, the L
variants id for double/dvec
attributes, while the I
variant is for int/uint/ivec/uvec
attributes.
I read about this in OpenGL Insights
When using glVertexAttribPointer()
everything gets cast to a float. While glVertexAttribIPointer()
can only expose vertex arrays that store integers and glVertexAttribLPointer()
is only for doubles.
As confirmed by a quote on this 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.