问题
Can anybody tell me how exactly do we use GL_INT_2_10_10_10_REV as type parameter in glVertexAttribPointer() ? I am trying to pass color values using this type. Also what is the significance of "REV" suffix in this type ? Does it require any special treatment in the shaders ?
My code is as follows :
GLuint red=1023,green=1023,blue=1023,alpha=3;
GLuint val = 0;
val = val | (alpha << 30);
val = val | (blue << 20);
val = val | (green << 10);
val = val | (red << 0);
GLuint test_data[]={val,val,val,val};
loadshaders();
glBindAttribLocation(ps,0,"tk_position");
glBindAttribLocation(ps,1,"color");
LinkShader();
glUseProgram(ps);
glEnableVertexAttribArray (0);
glVertexAttribPointer(0, 4, GL_FLOAT, 0, 0, vertices);
glEnableVertexAttribArray (1);
glVertexAttribPointer(1,GL_BGRA,GL_UNSIGNED_INT_2_10_10_10_REV,GL_TRUE,0,test_data);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
The shaders are : Vertex Shader -
#version 150
in vec4 tk_position;
in vec4 color;
out vec4 v_color;
void main()
{
v_color = color;
gl_Position = tk_position;
}
Fragment shader -
#version 150
in vec4 v_color;
out vec4 fragColor;
void main()
{
fragColor = v_color;
}
The program object is validated as well. No issues there. This code works fine on AMD card,but fails on NVidia. Failing means I get NULL Pointer access at glDrawArrays() call.
Access violation
Exception Flag: 0x00000000
Exception Addr: 0x055f32ce
回答1:
If you are passing colors, then more likely than not you want UNSIGNED_INT_2_10_10_10_REV. So I'll pretend that's what you asked for.
The entire field is packed into a single unsigned integer. OpenGL defines an unsigned integer to be exactly 32-bits in size, so you should use the GLuint
typedef that OpenGL provides to get one.
However, this format is packed, so you can't just shove an array into it. It's a form of compression, so it's generally going to be used when you're serious about making your vertex attribute data small.
First, the only reason to use 10/10/10/2 for colors is if your original source colors have higher color-depth colors than, for example, the regular 8-bit-per-channel colors. After all, the RGB components will each have 10 bits; if your source colors only had 8 bits, you haven't actually gained any new information.
So let's say you have some floating-point color values, with floating-point precision. You have to normalize each component down to the [0, 1] range. Then you multiply each value by 210 - 1, thus expanding to the [0, 1023] range. Then you convert each component into integers.
The problem comes with packing it into the actual field. The "REV
" in the name means that the order of components is revered. Normally in OpenGL, if you see a format like GL_UNSIGNED_SHORT_5_6_5
, then this means that each unsigned short is broken down into a pattern of 5 bits, followed by 6 bits, followed by 5 more. The left-most 5-bit field is the Red, the 6-bit field is Green, and the right-most 5-bit field is Blue.
The "REV
" means to reverse this. So 2_10_10_10_REV
means that the two most significant bits go to the alpha. The next 10 bits go to Blue. Then Green. Then Red.
So you have to bundle your integers on the [0, 1023] range, and then shove them into the right place in the GLuint value. And you do that for every such component in the array.
GLuint val = 0;
val = val | (alpha << 30);
val = val | (blue << 20);
val = val | (green << 10);
val = val | (red << 0);
This code assumes that alpha
only has 2 non-zero bits, and blue
, green
, and red
each have only 10 non-zero bits.
回答2:
So let's break this down into understandable parts:
INT
means that the format will be read as an integer.
2_10_10_10
means that the division of bits between is 2 bits for the first int and 10 bits for the next 3. Notice that these values add up to 32, the number of bits in a 4-byte integer.
REV
means that the order of the components are reversed.
IIRC this format is most commonly used for packing vertex normals, in order to reduce the size of vertex data. Haven't really seen it used for anything else.
EDIT
Also, I found this cool page with tables that visualize exactly which bits represent which values. The site is mostly in Japanese, but the tables are in English.
EDIT 2
Link to the above page is dead, here is another page with a table of how the values are laid out.
来源:https://stackoverflow.com/questions/14036892/using-gl-int-2-10-10-10-rev-in-glvertexattribpointer