【问题标题】:Using GL_INT_2_10_10_10_REV in glVertexAttribPointer()在 glVertexAttribPointer() 中使用 GL_INT_2_10_10_10_REV
【发布时间】:2012-12-26 06:42:21
【问题描述】:

谁能告诉我我们究竟如何在 glVertexAttribPointer() 中使用 GL_INT_2_10_10_10_REV 作为类型参数? 我正在尝试使用这种类型传递颜色值。还有这种类型的“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

【问题讨论】:

    标签: opengl glsl vertex-attributes


    【解决方案1】:

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

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

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

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

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

    问题在于将其打包到实际字段中。名称中的“REV”表示尊重组件的顺序。通常在 OpenGL 中,如果你看到像 GL_UNSIGNED_SHORT_5_6_5 这样的格式,那么这意味着每个无符号短字节被分解为 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 个非零位,bluegreenred 各只有 10 个非零位。

    【讨论】:

    • 它在 AMD 上运行良好,但在 NVidia 上却以某种方式失败。感谢您的回复。
    • 什么“工作正常”?它是如何成功的,又是如何失败的?用“不知何故失败”的代码来扩充你的问题。
    【解决方案2】:

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

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

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

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

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

    编辑

    另外,我发现this cool page 的表格可以准确地显示哪些位代表哪些值。该网站大部分是日文的,但表格是英文的。

    编辑 2

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

    【讨论】:

    • 这很有用,谢谢。第二部分仍然没有答案。如果我使用这种类型来指定颜色值,我该如何编码?以下似乎不起作用: GLint data[]= { 32767,32767,32767,32767 }; glVertexAttribPointer(1,GL_BGRA,GL_INT_2_10_10_10_REV,GL_TRUE,0,data);您还可以详细说明什么是“顶点法线包装”?
    • 我发布的表格显示了哪些位对应于着色器中的哪些值。根据man page for glVertexAttribPointer,您会得到一个GL_INVALID_OPERATION,用于将大小设置为1 而不是4。
    • 而顶点法线打包是指将顶点的法线向量(通常是 3d 向量,或 12 个字节)压缩为单个字节。你会失去一点准确性,但对于法线,这不是一个明显的差异,但它会显着减少每个顶点的大小。
    • 我这里没有将大小设置为 1。 GL_BGRA 是我为“大小”传递的参数。 1 对应于属性的“索引”。
    • @Jessy 找到另一个有类似表的人。
    猜你喜欢
    • 1970-01-01
    • 2021-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多