Похоже, я не совсем понимаю как делать правильное выравнивание при передаче uniform-буферов в шейдер.
Насколько я понял, если для передачи данных в шейдеры использовать не обычные unform-переменные, а uniform-буферы, то данные, которые записываются в эти буферы, должны быть выровнены. Один из форматов, по которому это выравнивание может быть осуществлено - 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 байт. Но об этом позже.
Далее я объявляю uniform-блок, где используются эти структуры:
// UBO-блок с параметрами маппинга текстур
layout(std140) uniform textureMapping
{
TextureMapping diffuseTexMapping;
TextureMapping specularTexMapping;
TextureMapping bumpTexMapping;
};
Затем, уже в С++ коде, я создаю аналог этой структуры, для того чтобы передать данные в шейдер. Все это выглядит как-то так:
Сама структура
struct TextureBasicMapping
{
glm::vec2 offset; // Сдвиг текстуры
glm::vec2 origin; // Центральная точка
glm::vec2 scale; // Масштабирование
glm::mat4 rotation; // Поворот (используется только часть 2*2)
};
А затем, я создаю сам uniform-буфер, учитывая что в нем 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-байтовй padding добавить. Так вот, я не совсем понимаю где именно.
В результате многочисленных проб оказалось, что этот самый 8-байтовый padding, для корректной передачи данных, необходимо добавить перед полем glm::mat4 rotation
. В итоге структура стала выглядеть так:
struct TextureBasicMapping
{
glm::vec2 offset; // Сдвиг текстуры
glm::vec2 origin; // Центральная точка
glm::vec4 scale; // Масштабирование (vec2 + 8 байт выравнивания)
glm::mat4 rotation; // Поворот (используется только часть 2*2)
};
Но почему именно там? Почему не в конце? Почему не в начале? Как это вообще работает? Буду рад подробному пояснению.
Дело в том, что вычислительный конвейер подразумевается заточенным под операции с векторными блоками из 2 или 4 машинных единиц (то бишь vec2 из 8 байт vec4 из 16 байт). Для эффективной организации операции блоками они должны быть выравнены по границам таких базовых векторов:
Заметьте, что размер нигде прямо не задается, просто к блоку может быть добавлено неиспользуемое место, чтобы выравнивание следующего за ним блока было соблюдено:
struct s1
{
vec2 offset; // 0 +2
vec2 origin; // 2 +2
}; // 4
struct s2
{
vec3 offset; // 0 +3
float dd; // 3 +1
vec4 origin; // 4 +4
}; // 8
struct s3
{
vec3 offset; // 0 +3
// 3 +1 иначе следующий блок будет не выровнен
vec2 origin; // 4 +2
// 6 +2 иначе следующая структура будет не выровнена
}; // 8
struct s4
{
float offset; // 0 +1
// 1 +3 иначе следующая структура будет не выровнена
}; // 4
struct s5
{
float offset; // 0 +1
// 1 +1 иначе следующий блок будет не выровнен
vec2 origin; // 2 +2
}; // 4
struct s6
{
float offset; // 0 +1
// 1 +3 иначе следующий блок будет не выровнен
vec4 origin; // 4 +4
}; // 8
struct TextureBasicMapping
{
glm::vec2 offset; // 0 +2
glm::vec2 origin; // 2 +2
glm::vec2 scale; // 4 +2
// 6 +2 иначе следующий блок будет не выровнен
glm::mat4 rotation; // 8 +16
}; // 24
Оборудование для ресторана: новинки профессиональной кухонной техники
Частный дом престарелых в Киеве: комфорт, забота и профессиональный уход
Всем доброго времени суток! Хотел бы попросить вас о помощиНе могу понять, как сделать следующее задание
Можно ли оставлять выход за границы массива в программах? Чем это грозит? Что происходит при выходе за его границы?
Пришлось полностью восстанавливать пример, у вас не хватаетgetNodeValue()