2

谁能告诉我我们究竟如何使用 GL_INT_2_10_10_10_REV 作为 glVertexAttribPointer() 中的类型参数?我正在尝试使用这种类型传递颜色值。还有这种类型的“REV”后缀有什么意义?它是否需要在着色器中进行任何特殊处理?

我的代码如下:

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);

着色器是:顶点着色器 -

#version 150

in vec4 tk_position;
in vec4 color;

out vec4 v_color;

void main()
{
    v_color = color;
    gl_Position = tk_position; 
}

片段着色器 -

#version 150

in vec4 v_color;
out vec4 fragColor;

void main()
{
    fragColor =  v_color;
}

程序对象也被验证。那里没有问题。此代码在 AMD 卡上运行良好,但在 NVidia 上失败。失败意味着我在 glDrawArrays() 调用中获得了 NULL 指针访问权限。

Access violation
    Exception Flag: 0x00000000
    Exception Addr: 0x055f32ce
4

2 回答 2

16

如果您传递颜色,那么您很可能需要UNSIGNED_INT_2_10_10_10_REV。所以我会假装这是你要求的。

整个字段被打包成一个无符号整数。OpenGL 将无符号整数定义为 32 位大小,因此您应该使用GLuintOpenGL 提供的 typedef 来获得一个。

但是,这种格式是打包的,所以你不能只是把一个数组塞进去。它是一种压缩形式,因此当您认真考虑将顶点属性数据缩小时,通常会使用它。

首先,对颜色使用 10/10/10/2 的唯一原因是,如果您的原始源颜色具有比常规 8 位每通道颜色更高的颜色深度颜色。毕竟,RGB 分量各有 10 位;如果您的源颜色只有 8 位,那么您实际上并没有获得任何新信息。

因此,假设您有一些浮点颜色值,具有浮点精度。您必须将每个组件标准化为 [0, 1] 范围。然后将每个值乘以 2 10 - 1,从而扩展到 [0, 1023] 范围。然后将每个组件转换为整数。

问题在于将其打包到实际字段中。名称中的“ REV”表示尊重组件的顺序。通常在 OpenGL 中,如果您看到类似 的格式GL_UNSIGNED_SHORT_5_6_5,则这意味着每个无符号 short 被分解为 5 位的模式,然后是 6 位,再接着是 5 位。最左边的 5 位字段是红色,6 位字段是绿色,最右边的 5 位字段是蓝色。

REV”的意思是颠倒这个。所以2_10_10_10_REV意味着两个最高有效位进入alpha。接下来的 10 位转到蓝色。然后是格林。然后是红色。

因此,您必须将整数捆绑在 [0, 1023] 范围内,然后将它们推到 GLuint 值中的正确位置。你对数组中的每个这样的组件都这样做。

GLuint val = 0;
val = val | (alpha << 30);
val = val | (blue << 20);
val = val | (green << 10);
val = val | (red << 0);

此代码假定alpha只有 2 个非零位,并且blue,greenred每个只有 10 个非零位。

于 2012-12-29T15:01:45.717 回答
4

所以让我们把它分解成可以理解的部分:

INT表示格式将被读取为整数。

2_10_10_10意味着第一个 int 为 2 位,下一个 3 为 10 位。请注意,这些值加起来为 32,即 4 字节整数中的位数。

REV表示组件的顺序颠倒了。

IIRC 这种格式最常用于打包顶点法线,以减少顶点数据的大小。还没有真正看到它用于其他任何事情。

编辑

此外,我还发现了这个很酷的页面,其中包含可以准确显示哪些位代表哪些值的表格。该网站大部分是日文的,但表格是英文的。

编辑 2

指向上述页面的链接已失效,是另一个页面,其中包含如何布置值的表格。

于 2012-12-26T10:46:46.513 回答