Vulkan API — урок 39. Глобальные переменные

В связи с небольшим изменением в самих уроках, до текстур доберемся через 5 уроков, включая этот.

Из-за особенностей переводимых разными людьми текстов, перед этим был вынужден переводить handle как дескриптор, как общепринятый вариант, что бы не внести больше путаницы в умы читателей, хотя это не совсем корректно (так же как использовать слово «поток» для thread, но все ведь мы привыкли слышать что-то вроде «многопоточные программы», а это в свою очередь путает начинающих программистов, ведь «потоки» так же используются для «streams» (потоки ввода/вывода). А еще графический конвейер на самом деле «graphics pipeline», пусть здесь и не возникает путаницы, пока. Этот список можно продолжать, но суть думаю уловили). И вот теперь, в серии уроков под названием «Uniform buffers» словом «дескриптор» будет обозначаться «descriptor» непосредственно.

Теперь можно передавать произвольные атрибуты в vertex shader для каждой вершины, но что насчет глобальных переменных? Теперь мы переходим к 3D графике, а это потребует матрицы model-view-projection (моделей-отображения-проекции или модельная, видовая и проекционная матрицы)(так же настоятельно рекомендую прочесть вот это, ну и ознакомиться с другими базовыми принципами линейной/векторной алгебры, если не знакомы). Мы бы могли включить её как данные вершины, но это пустая трата памяти и потребовало бы от нас обновлять буфер вершин всяякий раз, когда изменяется преобразование (transformation). Преобразование может легко изменить каждый отдельный кадр.

Правильный путь к решению этого в Vulkan’е – использование дескрипторов ресурсов (resource descriptors). Дескриптор – это возможность шейдеров свободно получить доступ к ресурсам, как то буферы и изображения. Мы собираемся создать буфер, который содержит матрицы преобразования и доступен vertex shader через дескриптор. Для этого понадобится:

  • Указать макет дескриптора (descriptor layout) во время создания конвейера.
  • Выделить набор дескрипторов (descriptor set) из пула дескрипторов.
  • Выполнить привязку набора во время рендеринга.

Макет дескриптор (descriptor layout) определяет типы ресурсов, которые будут доступны конвейеру, так же, как и проход рендера определяет тип вложений, которые будут доступны. Набор дескрипторов определяет актуальный буфер или графические ресурсы, которые будут привязаны к дескрипторам, как видеобуфер определяет image views для вложения render pass. Затем набор связывается с командами рисования, аналогично буферу вершин и фреймбуферу.

Есть много типов дескрипторов, но пока мы будем работать с буфером постоянных объектов (uniform buffer objects, можно так же перевести как буфер глобальных переменных, но это более «художественный» вариант), далее UBO. Другие типы дескрипторов так же будут рассмотрены в дальнейшем, но базовые принципы схожи. Допустим, есть данные, что мы хотим сделать доступными в vertex shader в структуре С, примерно так:

struct UniformBufferObject {
    glm::mat4 model;
    glm::mat4 view;
    glm::mat4 proj;
};

Затем мы можем скопировать данные в VkBuffer и получить доступ к ним через дескриптор UBO из vertex shader:

layout(binding = 0) uniform UniformBufferObject {
    mat4 model;
    mat4 view;
    mat4 proj;
} ubo;

void main() {
    gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 0.0, 1.0);
    fragColor = inColor;
}

Таким образом можно обновить модель, отображение и проекцию матрицы каждого кадра, и «перенести» прямоугольник из предыдущего урока в 3D.

Но перед тем нужно модифицировать vertex shader. Источник, откуда лично я черпаю большую часть информации настоятельно рекомендует ознакомиться с этим. А вот изменения в шейдере:

#version 450
#extension GL_ARB_separate_shader_objects : enable

layout(binding = 0) uniform UniformBufferObject {
    mat4 model;
    mat4 view;
    mat4 proj;
} ubo;

layout(location = 0) in vec2 inPosition;
layout(location = 1) in vec3 inColor;

layout(location = 0) out vec3 fragColor;

out gl_PerVertex {
    vec4 gl_Position;
};

void main() {
    gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 0.0, 1.0);
    fragColor = inColor;
}

Обратите внимание, что порядок uniform, in and out не имеет значения. Директива binding аналогична директиве location для атрибутов. Мы будем ссылаться на этот binding в descriptor layout. Строка gl_Position изменяется с учетом преобразований для расчета конечной позиции в клип координатах.

Main Admin

One Comment

  1. Ошибка в переводе. Правильно будет «Директива binding аналогична директиве location для атрибутов.»

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *