如何在 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个值。
我想节省内存,因为输入数据在 [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个值。