看起来我不太明白在将统一缓冲区传递给着色器时如何正确对齐。
据我了解,如果使用统一缓冲区而不是常规 unform 变量将数据传输到着色器,那么写入这些缓冲区的数据必须对齐。可以进行这种对齐的格式之一是 std140。
std140 标记规则是这样的:
标量值(int、float、bool - 占用 4 个字节)。向量要么是 8 字节(vec1,vec2)要么是 16 字节(vec3,vec4)。矩阵就像多个向量(取决于维度)。结构的大小等于其所有成员的大小(考虑到上述规则),如有必要,填充到 16 的重数。
在着色器中,我声明了以下结构:
// Структура описывающая параметры мапинга текстуры
struct TextureMapping
{
vec2 offset;
vec2 origin;
vec2 scale;
mat4 rotation;
};
原来结构本身应该占用 8 + 8 + 8 + 64 字节(88 字节)最多为 16 的倍数(最接近的值是 16 的倍数是 96),少了 8 个字节。但稍后会详细介绍。
接下来,我声明一个使用这些结构的统一块:
// UBO-блок с параметрами маппинга текстур
layout(std140) uniform textureMapping
{
TextureMapping diffuseTexMapping;
TextureMapping specularTexMapping;
TextureMapping bumpTexMapping;
};
然后,已经在 C++ 代码中,我创建了这个结构的类似物,以便将数据传递给着色器。这一切看起来像这样:
结构本身
struct TextureBasicMapping
{
glm::vec2 offset; // Сдвиг текстуры
glm::vec2 origin; // Центральная точка
glm::vec2 scale; // Масштабирование
glm::mat4 rotation; // Поворот (используется только часть 2*2)
};
然后,我自己创建统一缓冲区,因为它有 3 个这样的结构:
// Создать UBO-буфер для параметров маппинга текстуры и выделить память
glGenBuffers(1, &uboTextureMapping_);
glBindBuffer(GL_UNIFORM_BUFFER, uboTextureMapping_);
glBufferData(GL_UNIFORM_BUFFER, 3 * sizeof(TextureBasicMapping), nullptr, GL_STATIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
但不要忘记,最多 16 个重数,该结构TextureBasicMapping缺少 8 个字节。事实证明,为了正确地将数据传输到着色器,您需要在结构本身的某处添加这个 8 字节填充。所以,我不太明白在哪里。
经过无数次测试,结果证明,为了正确传输数据,这个非常 8 字节的填充必须在glm::mat4 rotation. 结果,结构开始看起来像这样:
struct TextureBasicMapping
{
glm::vec2 offset; // Сдвиг текстуры
glm::vec2 origin; // Центральная точка
glm::vec4 scale; // Масштабирование (vec2 + 8 байт выравнивания)
glm::mat4 rotation; // Поворот (используется только часть 2*2)
};
但为什么会在那里?为什么不是最后?为什么不是一开始?它是如何工作的?我将不胜感激详细的解释。
事实是,计算管道旨在针对具有 2 个或 4 个机器单元的向量块(即 8 个字节的 vec2 和 16 个字节的 vec4)的操作进行锐化。为了有效地按块组织操作,它们必须沿着以下基向量的边界对齐:
请注意,大小不是在任何地方直接指定的,只是可以将未使用的空间添加到块中,以便遵循块的对齐方式: