【问题标题】:OpenGL and GLSL memory alignment for uniforms and varyings统一和变量的 OpenGL 和 GLSL 内存对齐
【发布时间】:2018-05-16 21:28:04
【问题描述】:

我遇到了令我困惑的事情,但我找不到答案。当我这样写着色器时:

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

我知道 vec3 不像许多 vec4 那样是 16 字节对齐的,也不是 SIMD 兼容的数据类型。我知道这一点(我认为),因为我的 C++ 代码中的数据是:

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

每个向量彼此紧贴,没有填充,大小为 8 * sizeof(float),32 字节。我将它传递给制服,着色器读取它很好,所以我知道它们都是对齐的。

但是当涉及到 GLSL 中的统一块时,例如在 std140 标准中,vec3 必须在添加另一个 vec3 或 vec4 之前额外填充四个字节:

  1. 如果成员是一个三分量向量,其分量消耗 N 个基本机器单元,则基本对齐为 4N

但是,您也可以在 vec3 和下一个 vec3 之间存储一个四字节 int 或四字节 bool 以压缩大小。那么这是否意味着顶点布局的属性指针值不遵循 std140 布局?此外,如果我在 C++ 代码中使用 SIMD 16 字节对齐向量,这是否意味着我将不再能够将属性指针值设置为 vec3、vec3、vec2,而是拥有所有 vec4?

我还在文档中看到以下警告:

警告:实现有时会导致 std140 布局错误 vec3 组件。建议您手动填充 结构/数组,完全避免使用 vec3。

这里是说完全避免使用 vec3,但我认为在 vec3 之后打包一个四字节 int 或 bool 是一种节省空间的聪明技术。

【问题讨论】:

    标签: c++ opengl alignment glsl shader


    【解决方案1】:

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

    关于警告:是的,使用 vec3 之后的空间来存储和 int/float/bool 是一种聪明的技术。但正如警告所述,驱动程序实现有时会出错。因此,如果您想确保您的代码在任何地方都能可靠运行,您要么必须进行大量测试,要么根本不使用 vec3。再次注意,这仅在接口块的情况下相关。普通的 vec3 制服不会被这个触及。

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

    【讨论】:

    • 这很有帮助。那个 floatBitsToInt 完全让我大吃一惊,起初我试图找到一个 u8vec4 来存储 0 - 255 RGBA,然后发现 glsl 根本不处理单字节数据类型,所以我的下一个想法是发送一个 int 并使用位运算符以获得正确的颜色通道。
    • 等一下,有点摆弄我仍然需要处理我刚刚意识到的 floatBitsToInt。如果我的 0 - 255 颜色是我的 vec4.w,我仍然需要移动并提取正确的字节。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-24
    • 2010-10-27
    • 1970-01-01
    • 2010-11-07
    • 2021-12-29
    • 1970-01-01
    相关资源
    最近更新 更多