【问题标题】:OpenGL GLSL Send color as integer to shader to be decomposed as vec4 RGBAOpenGL GLSL 将颜色作为整数发送到着色器以分解为 vec4 RGBA
【发布时间】:2018-11-05 22:05:31
【问题描述】:

我可以将颜色作为 4 个浮点数发送到着色器 - 没问题。但是我想将它作为整数(或无符号整数,并不重要,重要的是 32 位)发送并在着色器上的 vec4 中分解。

我使用 OpenTK 作为 OpenGL 的 C# 包装器(尽管它应该只是一个直接包装器)。

让我们考虑一个最简单的着色器,它的顶点包含位置(xyz)和颜色(rgba)。

顶点着色器:

#version 150 core

in vec3 in_position;
in vec4 in_color;
out vec4 pass_color;
uniform mat4 u_WorldViewProj;

void main()
{
    gl_Position = vec4(in_position, 1.0f) * u_WorldViewProj;
    pass_color = in_color;
}

片段着色器:

#version 150 core

in vec4 pass_color;
out vec4 out_color;

void main()
{
    out_color = pass_color;
}

让我们创建顶点缓冲区:

public static int CreateVertexBufferColor(int attributeIndex, int[] rawData)
{
    var bufferIndex = GL.GenBuffer();
    GL.BindBuffer(BufferTarget.ArrayBuffer, bufferIndex);
    GL.BufferData(BufferTarget.ArrayBuffer, sizeof(int) * rawData.Length, rawData, BufferUsageHint.StaticDraw);
    GL.VertexAttribIPointer(attributeIndex, 4, VertexAttribIntegerType.UnsignedByte, 0, rawData);
    GL.EnableVertexAttribArray(attributeIndex);
    GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
    return bufferIndex;
}

我在顶点着色器中得到了 vec4 'in_color' 的全零。不知道怎么回事。

我发现的最接近的东西:https://www.opengl.org/discussion_boards/showthread.php/198690-I-cannot-send-RGBA-color-as-unsigned-int

还在 VertexAttribIPointer 中,我将 0 作为步幅传递,因为我确实有 VertexBufferArray 并保持数据分离。因此,每个顶点的颜色紧密排列为 32 位(每种颜色)。

【问题讨论】:

  • 这是 GLSL 而不是 HLSL。对于整数数据类型,类型必须是 ivec4
  • 我不认为整数属性是你想要的。您只需要 UNORM,因此您将 in vec4glVertexAttribPointer 结合使用。不是glVertexAttribIPointer

标签: opengl glsl vertex-buffer vertex-attributes


【解决方案1】:

当着色器中的输入为浮点数 (vec4) 时,您必须使用 VertexAttribPointer 而不是 VertexAttribIPointer。

将标准化参数设置为 GL_TRUE。

规范说:

glVertexAttribPointer,如果 normalized 设置为 GL_TRUE,则表示以整数格式存储的值将映射到范围 [-1,1](对于有符号值)或 [0,1](对于无符号值)当它们被访问并转换为浮点数时。否则,值将直接转换为浮点数而不进行规范化。

【讨论】:

  • 这样做看起来合乎逻辑,但这不起作用:GL.VertexAttribPointer(attributeIndex, 4, VertexAttribPointerType.UnsignedByte, true, 0, rawData);rawDataint[],其中整数包含 4 通道 RGBA 或 ARGB 或任何一个的所有 32 位)。我仍然在顶点着色器中得到 vec4 (0,0,0,0),有什么想法吗?
  • 如果您尝试将所有 4 个通道打包到一个 int 中,您需要设置 GL.VertexAttribIPointer(attributeIndex, 1, VertexAttribIntegerType.UnsignedByte, 0, rawData); 并且在您的着色器中只接收一个 uint 而不是 vec4。然后你可以用vec4 unpackUnorm4x8(uint p);从uint解压到vec4。还要确保它是 uint 而不是 int。
  • 好吧,所以我的着色器看起来像这样:#version 400 core in vec3 in_position; in uint in_color; out vec4 pass_color; uniform mat4 u_WorldViewProj; void main() { gl_Position = vec4(in_position, 1.0f) * u_WorldViewProj; pass_color = unpackUnorm4x8(in_color); } 和顶点属性:GL.VertexAttribIPointer(attributeIndex, 1, VertexAttribIntegerType.UnsignedInt, 0, rawData); 你提到了“VertexAttribIntegerType.UnsignedByte”,我想它应该是“UnsignedInt”,但是它们都没有工作,我仍然在着色器中得到零。
  • 是的,应该是 UnsignedInt。您是否检查 rawData 是否实际包含任何值?你确定attributeIndex是正确的吗?您可以尝试使用GL.VertexAttribIPointer(1, 1, VertexAttribIntegerType.UnsignedInt, 0, rawData); 和着色器layout(location = 1) in uint in_color; 显式设置它。 rawData 是 int 还是 uint?应该是 uint。
  • 好吧,我还是被卡住了。根本无法让它工作。但是,如果我只构建一个顶点缓冲区,在其中将所有属性按步长排列(而不是为属性构建不同的缓冲区),那效果很好:例如位置为 3 个浮点数,颜色为 int:GL.VertexAttribPointer(Shader.in_position, 3, VertexAttribPointerType.Float, false, vertexSize, IntPtr.Zero); + GL.VertexAttribPointer(Shader.in_color, 4, VertexAttribPointerType.UnsignedByte, true, vertexSize, new IntPtr(12));
【解决方案2】:

好的,所以这对我来说完成了这项工作:

将托管数据作为int[],其中它是紧密包装的数组只有颜色(其中int 格式为:RGBA 表示0xAABBGGRR),然后将顶点属性定义为:@987654325 @ 并在着色器中将其用作:in vec4 in_color;

【讨论】:

    猜你喜欢
    • 2016-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-30
    相关资源
    最近更新 更多