6

OpenGL规范的谎言(或者这是一个错误?)......参考std140的布局,共享统一缓冲区,它指出:

“GLSL 编译器使用表 L-1 中显示的一组规则来布局 std140 限定的统一块中的成员。块中成员的偏移量是根据块中先前成员的大小累积的 (在相关变量之前声明的那些)和起始偏移量。第一个成员的起始偏移量始终为零。

标量变量类型(bool、int、uint、float)-基本机器类型中标量的大小"

( http://www.opengl-redbook.com/appendices/AppL.pdf )

所以,有了这些信息,我在我的着色器中设置了一个统一的块,看起来像这样:

// Spotlight.

layout (std140) uniform Spotlight
{
    float Light_Intensity;
    vec4  Light_Ambient;
    vec3  Light_Position;   
};

...只是发现它不适用于我在 CPU 端设置的后续 std140 布局。也就是说,前 4 个字节是浮点数(GLfloat 的机器标量类型的大小),接下来的 16 个字节是 vec4,接下来的 12 个字节是 vec3(考虑到规则,最后剩下 4 个字节vec3 确实是 vec4)。

当我更改 CPU 端以将浮点数指定为与 vec4 相同的大小(即 16 个字节)并在此假设下进行偏移量和缓冲区大小时,着色器按预期工作。

所以,要么规范是错误的,要么我在这种情况下误解了“标量”的含义,或者 ATI 存在驱动程序错误。谁能解开这个谜团?

4

1 回答 1

13

您链接到的那个 PDF不是OpenGL 规范。我不知道你从哪里得到它,但这肯定不是完整的规则列表。始终检查您的来源;该规范并不像许多人声称的那样难以理解。

是的,基本类型变量的大小与基本机器类型的大小相同(即:4 字节)。但是单独的大小并不能确定变量的位置

每种类型都有一个基本对齐方式,无论该类型在统一块中的哪个位置找到,它的总字节偏移量都必须符合该对齐方式。a 的基本对齐方式vec4是 4 * 其基本类型的对齐方式(即:float)。所以 a 的基本对齐vec4是 16。

因为Light_Intensity在 4 个字节之后结束,所以编译器必须插入 12 个字节的填充,因为Light_Ambient 不能在 4 个字节的边界上。它必须在 16 字节的边界上,因此编译器使用 12 字节的空白空间。

ATI 确实有一些围绕 std140 布局的驱动程序错误,但这不是其中之一。

作为一般规则,我喜欢明确地将填充放入我的结构中,并且我避免vec3(因为它具有 16 字节对齐)。这样做通常会减少编译器错误以及对事情去向和实际占用多少空间的意外误解。

于 2011-09-17T01:34:57.753 回答