如何在 C++ 和 GLSL 之间打包(4 字节)和解包(vec4)

How to pack(4bytes) and unpack(vec4) between c++ and GLSL

我想节省内存,因为输入数据在 [0,..,255] 范围内,所以我不需要 4xFloat,但 4xByte 就足够了。 GLSL 和 gpu 不喜欢字节,所以需要打包和解包。也不应该发生精度损失。

C++ 和打包代码:

最快和最简单的解决方案应该是使用 uint 进行传输。 GLM 已经准备好矢量,所以将 glm::u8vec4(1, 1, 1, 1) 放入顶点数组应该没问题。我用 gDEBugger 检查了顶点数组,所以我确信它们包含正确的数据。 VAP 看起来像这样:

glVertexAttribPointer(
    0,
    1, // one element
    GL_UNSIGNED_INT, //transfer data type
    GL_FALSE, //dont normalize
    1 * sizeof(GLuint), // size of one element
    (void*)0 // offset
    );

GLSL 和解包:

layout(location = 0) in uint data;
vec4 unpack;
unpack.x = float((data & uint(0xff000000)) >> 24);
unpack.y = float((data & uint(0x00ff0000)) >> 16);
unpack.z = float((data & uint(0x0000ff00)) >> 8);
unpack.w = float((data & uint(0x000000ff)) >> 0);

结果应该会提供提示,但太乱了。

编辑:

即使我的解决方案毫无意义,也有两个错误。首先如下所述,我必须使用 glVertexAttribIPointer。其次,在我的例子中,移位是镜像的(X 应该移动 0,Y 移动 8,..)。

正确的解决方案如下所示:

glVertexAttribPointer(
    0,
    4,
    GL_UNSIGNED_BYTE,
    GL_FALSE,
    4 * sizeof(GLubyte),
    (void*)0
);
shader:
layout(location = 0) in vec4 data;

GLSL and gpu don't like bytes so pack and unpack is required. Also no precision loss should occur.

为什么这么说?使用 GL_UNSIGNED_BYTE 属性数据得到了很好的支持并且非常普遍(例如颜色)。这没有性能问题(只要遵守基本对齐规则)。

GL会自动将整数属性数据转换为浮点数。 normalized 参数定义数据是否应规范化为 [0,1](或有符号整数类型的 [-1,1])范围,或者是否应直接转换为浮点数,以便(GLubyte )255 将在着色器中显示为 255.0f。

您的代码失败,因为您需要使用 glVertexAttribIPointer()(请注意那里的 I)来设置整数属性。但在你的情况下,这确实是一个毫无意义的练习。

您的 C++ 代码是正确的,但您也可以使用 glVertexAttribIPointer(我代表整数?)。最后两个值可以是 zero/nullptr,因为缓冲区中只有一个值。所有参数都适用于当前绑定的缓冲区,除了第一个适用于当前绑定的 VAO。

glVertexAttribIPointer(0, 1, GL_UNSIGNED_INT, 0, nullptr);

OpenGL 着色器代码应如下所示:

layout(location = 0) in uint data;
out vec4 color                     // I assume you want this to go 'out'?
void main()
{
    color = vec4(
        data & uint(0xFF000000),
        data & uint(0x00FF0000),
        data & uint(0x0000FF00),
        data & uint(0x000000FF));
}

现在您可以在 uint 中存储 rgba 值。如:0xRRGGBBAA,为您提供每部分256个值。