Работаю над новым постэффектом расфокусированности с поддержкой боке.
(далее…)Кубические карты из DDS
В следующей версии Dagon появится поддержка кубических карт в формате DDS. Чаще всего для кубических карт этот формат используется, если необходимо хранить предрассчитанные зеркальные лепестки (specular lobes) для разных уровней шероховатости – DDS позволяет хранить эти данные в mip-уровнях текстуры и быстро загружать их без промежуточного декодирования.
До этого единственным доступным вариантом была генерация mip-уровней в самом движке, но это делалось блочным фильтром, без учета BRDF. Теперь свертку карты окружения можно осуществлять при помощи внешних инструментов – я рекомендую, например, IBLBaker.
glTF в Dagon
В Dagon 0.12 появится начальная поддержка glTF 2.0, популярного формата 3D-моделей от Khronos. На сегодняшний день готова загрузка мешей, текстур и, частично, материалов, на очереди – сцены и узлы, а в перспективе не исключена и поддержка анимации. Ниже – скриншоты дворца Спонца, загруженного из glTF.
Первое знакомство с WGSL
У тех, кто работает с низкоуровневой графикой, сегодня на слуху WebGPU – новый кроссплатформенный API для доступа к возможностям современных видеокарт. WebGPU призван объединить Vulkan, Metal и D3D12 под унифицированным набором функций и станет не просто веб-стандартом, но и, в перспективе, неплохой заменой OpenGL: реализации этого API уже существуют в виде рабочих прототипов wgpu-native от Mozilla и Dawn от Google – любой может использовать их в своих собственных приложениях.
WebGPU имеет сравнительно простую архитектуру, доступную для понимания “простыми смертными” практически с первого прочтения заголовочного файла. Единственной проблемой до недавнего времени было отсутствие консенсуса по шейдерному языку – существующие реализации WebGPU использовали двоичное промежуточное представление SPIR-V от Khronos, а Apple настаивала на текстовом языке на основе WSL. Компромиссом стал WGSL (WebGPU Shading Language), высокоуровневый язык со строго определенной семантикой и буквальной трансляцией в/из SPIR-V. Многие разработчики оказались недовольны, так как SPIR-V уже успел стать привычным решением и оброс инструментами – сегодня можно компилировать в SPIR-V код на всех языках предыдущих поколений. Однако я вижу больше преимуществ, чем недостатков – перечислю некоторые из них.
- Использование SPIR-V усложняет жизнь при создании игрового движка, требует внедрения дополнительной стадии компиляции шейдеров на стороне разработчика. Референсным компилятором шейдеров считатеся GLSLang от Khronos, но его довольно трудно встроить в приложение как библиотеку, особенно если вы не пишете на C++ – приходится использовать GLSLang как приложение, и это усложняет тулчейн разработки, если нужна кроссплатформенность. Встроенный в API высокоуровневый язык решает эту проблему.
- WGSL разрабатывается как текстовый аналог SPIR-V – они имеют общий набор возможностей. Это значит, что не будет повторения ситуации с GLSL, когда язык по-разному обрабатывается в компиляторах от различных поставщиков. Сохраняется главное преимущество SPIR-V при высоком удобстве использования.
- Vulkan-диалект GLSL 4.60, являющийся де-факто стандартным языком под SPIR-V, имеет множество костылей и архаизмов – у WGSL более продуманный синтаксис, лишенный неявности и многозначности.
Синтаксис WGSL имеет много общего с Rust, особенно заголовки функций:
fn someFunc(x: i32) -> i32 {
//...
}
Типы объявляются через двоеточие после идентификатора, переменные – при помощи ключевого слова let
, константность подразумевается по умолчанию. Для изменяемых переменных есть ключевое слово var
. Система типов также пришла из вселенной Rust. Векторные типы имеют форму vec4<f32>
(вместо простого vec4
), что позволяет явным образом указать битовость используемых чисел. При этом можно объявить type vec4f = vec4<f32>;
и писать коротко, если вам так привычнее.
Кстати, очень порадовало, что есть вывод типов – можно не указывать тип переменной, если она тут же инициализируется:
let a = vec4<f32>(0.0, 0.0, 0.0, 1.0);
Вместо ключевого слова layout
– нотация с использованием двойных квадратных скобок, внутри которых записываются атрибуты location
и др.:
[[location(0)]] position: vec4<f32>;
Встроенные переменные конвейера обозначаются атрибутом builtin
, что весьма удобно при объявлении структур для хранения промежуточных результатов:
struct VertexOutput
{
[[builtin(position)]] position: vec4<f32>;
[[location(0)]] color: vec4<f32>;
};
Сравните это с GLSL, где для встроенных переменных используется зарезервированный префикс gl_
.
Структуры, являющиеся uniform-блоками, помечаются атрибутом block
:
[[block]] struct Uniforms {
//...
};
Прямым аналогом вулкановских set
и binding
являются атрибуты group
и binding
.
Vulkan/GLSL:
layout(set=0, binding=0) uniform Uniforms uniforms;
WGSL:
[[group(0), binding(0)]] var uniforms: Uniforms;
Программы на WGSL можно не разделять на два текста – вершинный и фрагментный шейдеры можно хранить в одном файле и, таким образом, использовать общие объявления. Для этого используется атрибут stage
. Названия самих входных точек могут быть произвольными, но чаще всего в примерах используют vs_main
и fs_main
.
[[stage(vertex)]]
fn vs_main() -> VertexOutput
{
//...
}
[[stage(fragment)]]
fn fs_main(input: FragmentInput) -> [[location(0)]] vec4<f32>
{
//...
}
Очень непривычно в WGSL записываются циклы:
var i = i32(0);
loop {
break if (i == 5);
//...
continuing {
i = i + 1;
}
}
Впрочем, на момент написания статьи обсуждается возможность поддержки классического for
.
Подведу итог: с первого взгляда WGSL кажется хорошим решением давней проблемы с языками шейдеров. Высокоуровневое представление SPIR-V – это отличная идея. Непривычный синтаксис и конструкции со спорным юзабилити могут усложнить портирование на WGSL готовых шейдеров, но в целом впечатление от языка весьма позитивное.
Новые статьи на Medium
Написал две новые статьи на английском:
- dlib: Past, Present and Future – экскурс в историю dlib, о текущем статусе проекта и планах на будущее;
- GitHub Actions and D – о том, как настроить тестирование на GitHub Actions для проектов на D.