OpenGL和GLSL中Uniforms和Varyings的内存对齐

6

我希望你能帮我翻译一下涉及IT技术的内容。以下是需要翻译的内容:

我遇到了一个令我困惑的问题,而且找不到答案。当我编写这样的shader时:

layout (location = 0) in vec3 inPosition;
layout (location = 1) in vec3 inNormal;
layout (location = 2) in vec2 inTexCoords;

我知道vec3与许多vec4或SIMD兼容数据类型不同,它们没有16字节对齐。我知道这一点(我认为),因为在我的C++代码中,我的数据是:

struct Vertex
{
    vec3 position;
    vec3 normal;
    vec2 texCoords;
};

每个向量都与其他向量紧密相邻,没有填充,大小为8 * sizeof(float),32字节。我将其传递给uniform变量,着色器可以正确读取它,因此我知道它们都是对齐的。
但是,当涉及到GLSL中的uniform块时,例如使用std140标准,一个vec3在添加另一个vec3或vec4之前必须填充额外的四个字节:
如果成员是由占用N个基本机器单元的三个组件组成的矢量,则基本对齐方式为4N
然而,你也可以在vec3和下一个vec3之间存储四个字节的int或bool变量以压缩大小。这是否意味着顶点布局的属性指针值不遵循std140布局?另外,例如,如果我在C++代码中使用SIMD 16字节对齐的向量,这是否意味着我将不能再将属性指针值设置为vec3、vec3、vec2,而必须全都使用vec4?
此外,我在文档中看到了以下警告:
警告:实现有时会在vec3组件上出错std140布局。建议您手动填充结构/数组并避免完全使用vec3。
这里建议不要使用vec3,但我认为将一个四字节的int或bool变量放在vec3之后是一种聪明的节省空间的技巧。
1个回答

6

std140布局仅适用于接口块,而不适用于缓冲区内容或接口块之外的属性。由于接口块不能用作顶点着色器的输入或片段着色器的输出,因此std140不会影响glVertexAttribPointer的设置方式或顶点数据的存储方式。

关于警告:是的,将vec3后面的空间用于存储int/float/bool是一种聪明的技巧。但正如警告所述,驱动程序实现有时会出错。因此,如果您想确保您的代码在任何地方都能可靠运行,您要么必须进行大量测试,要么根本不使用vec3。再次注意,这只适用于接口块的情况。普通的vec3统一变量不会受到影响。

您可以在C++端打包存储3个浮点数和一个整数,但通过接口块访问时使用vec4。然后,您可以通过使用floatBitsToInt(myBlock.myVec4.w)来检索整数。


那很有帮助。floatBitsToInt 完全让我大开眼界,因为一开始我试图找到一个 u8vec4 来存储 0-255 的 RGBA,然后发现 glsl 根本不处理单字节数据类型,所以我的下一个想法是发送一个 int 并使用位运算符来获取正确的颜色通道。 - Zebrafish
等一下,我意识到即使使用floatBitsToInt,我仍然需要进行位操作。如果我的0-255颜色是我的vec4.w,我仍然需要进行移位和提取正确的字节。 - Zebrafish

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接