в целом, Nanite из Unreal Engine является мутацией подхода c Visibility Buffer, но он не очень эффективен.
Потому что при использовании visibility buffer нам вообще не нужен g-буфер, мы можем напрямую работать с идентификаторами в компьютах и очень сильно всё ускорить.
А Nanite использует буфер видимости исключительно чтобы ускорить заполнение g-буфера, который потом используется уже у них в обычном деферред пайплайне.
В общем, они сделали более простую реализацию, которая лучше интегрируется в существующий код движка, но далеко не самая оптимальная при этом
Потому что при использовании visibility buffer нам вообще не нужен g-буфер, мы можем напрямую работать с идентификаторами в компьютах и очень сильно всё ускорить.
А Nanite использует буфер видимости исключительно чтобы ускорить заполнение g-буфера, который потом используется уже у них в обычном деферред пайплайне.
В общем, они сделали более простую реализацию, которая лучше интегрируется в существующий код движка, но далеко не самая оптимальная при этом
👍3
собственно, почти все продвинутые варианты этих подходов довольно заморочные, но или дают хороший буст производительности, или решают какие-то проблемы
и почти все эти продвинутые варианты требуют компьют шейдеров, то есть кроссплатформерный опенгл в пролете
и почти все эти продвинутые варианты требуют компьют шейдеров, то есть кроссплатформерный опенгл в пролете
👍2
если подытожить, то есть простая памятка
если у тебя больше стилизованные или низкодетализированные сцены, с малым количеством источников света
то лучше брать форвард рендер, желательно его более современные вариации
это выйдет даже выгоднее по видеопамяти относительно деферреда
если тебе важнее более реалистичная графика, с PBR, кучей эффектов постобработки и тд
или очень много источников света
то лучше брать деферред рендер, потому что тут мы уже значительно выиграем на нагрузке видеокарты относительно форварда
буфер видимости потенциально лучше, но очень заморочный и по нему меньше информации, поэтому для инди вряд ли стоит того
если у тебя больше стилизованные или низкодетализированные сцены, с малым количеством источников света
то лучше брать форвард рендер, желательно его более современные вариации
это выйдет даже выгоднее по видеопамяти относительно деферреда
если тебе важнее более реалистичная графика, с PBR, кучей эффектов постобработки и тд
или очень много источников света
то лучше брать деферред рендер, потому что тут мы уже значительно выиграем на нагрузке видеокарты относительно форварда
буфер видимости потенциально лучше, но очень заморочный и по нему меньше информации, поэтому для инди вряд ли стоит того
👍7
и еще небольшой нюанс - на мобильных устройствах и маках (где по сути та же мобильная архитектура у чипов) само железо больше заточено на деферред рендеринг
следовательно, там он показывает даже лучшие результаты, чем на обычных пк
также, люди, пробовавшие разные подходы, пишут, что в среднем деферред оказывается быстрее даже форвард+, если нужен хоть какой-то постпроцессинг вроде SSAO
https://www.reddit.com/r/GraphicsProgramming/comments/1kmrura/deferred_rendering_vs_forward_rendering_in_aaa/
следовательно, там он показывает даже лучшие результаты, чем на обычных пк
также, люди, пробовавшие разные подходы, пишут, что в среднем деферред оказывается быстрее даже форвард+, если нужен хоть какой-то постпроцессинг вроде SSAO
https://www.reddit.com/r/GraphicsProgramming/comments/1kmrura/deferred_rendering_vs_forward_rendering_in_aaa/
👍2
Немного подробнее про деферред рендер, так как считаю его сейчас оптимальным выбором для инди
В наивном варианте он сводится к рендеру в 2 прохода:
1. Через MRT (Multiple Render Targets) делаем обычную отрисовку наших мешей, но вместо вывода на экран пишем их параметры в отдельные текстуры. Обычный набор - позиции, нормали, альбедо (цвет) и спекулар (отражаемость). Потом можно расширять под PBR другими текстурами по необходимости
полученные текстуры называются G Buffer, и уже содержат только итоговые фрагменты, которые попадут на экран. Они уже прошли тест глубины и прочее, выдав нам итоговые пиксели, просто в нужном формате
а далее просто делается второй прогон, полностью отвязанный от геометрии исходной сцены. Рисуем полноэкранный квад, вертекс шейдер примитивен. А во фрагментном уже считаем свет на базе текстур из G Buffer так же, как считали бы в форварде
Если в наивном форвард рендере нам надо считать свет для каждого фрагмента объекта, даже если он в итоге не будет освещен, и делать это для каждого источника света
То в деферреде на итоговом прогоне освещения мы идем чисто по пикселям экрана и семплим текстуры G Buffer для расчета света.
Отсюда независимость сложности расчета света в деферреде от сложности сцены - сама сцена посчитана на построении G Buffer, для света мы работаем только с итоговыми пикселями
Но тут и минусы - видеопамять и пропускная способность видеокарты тратятся на хранение G Buffer и взаимодействие с ним. А также полупрозрачность требует отдельного форвард прогона. И не работает MSAA, приходится реализовывать более сложные способы сглаживания
но, по сути, почти любой постпроцессинг потом использует те же самые данные из G Buffer, и в конечном счете получается очень выгодно
В наивном варианте он сводится к рендеру в 2 прохода:
1. Через MRT (Multiple Render Targets) делаем обычную отрисовку наших мешей, но вместо вывода на экран пишем их параметры в отдельные текстуры. Обычный набор - позиции, нормали, альбедо (цвет) и спекулар (отражаемость). Потом можно расширять под PBR другими текстурами по необходимости
полученные текстуры называются G Buffer, и уже содержат только итоговые фрагменты, которые попадут на экран. Они уже прошли тест глубины и прочее, выдав нам итоговые пиксели, просто в нужном формате
а далее просто делается второй прогон, полностью отвязанный от геометрии исходной сцены. Рисуем полноэкранный квад, вертекс шейдер примитивен. А во фрагментном уже считаем свет на базе текстур из G Buffer так же, как считали бы в форварде
Если в наивном форвард рендере нам надо считать свет для каждого фрагмента объекта, даже если он в итоге не будет освещен, и делать это для каждого источника света
То в деферреде на итоговом прогоне освещения мы идем чисто по пикселям экрана и семплим текстуры G Buffer для расчета света.
Отсюда независимость сложности расчета света в деферреде от сложности сцены - сама сцена посчитана на построении G Buffer, для света мы работаем только с итоговыми пикселями
Но тут и минусы - видеопамять и пропускная способность видеокарты тратятся на хранение G Buffer и взаимодействие с ним. А также полупрозрачность требует отдельного форвард прогона. И не работает MSAA, приходится реализовывать более сложные способы сглаживания
но, по сути, почти любой постпроцессинг потом использует те же самые данные из G Buffer, и в конечном счете получается очень выгодно
🔥4
Однако, указанная выше реализация все еще очень неоптимальна, потому что даже в ней, мы вынуждены во фрагментном шейдере прохода освещения рассчитывать свет для pixels * number of lights, то есть каждый источник света участвует в расчетах каждого пикселя, даже если физически в сцене объект на нем слишком далеко и не может быть засвечен. Что все равно дорого, пусть и гораздо лучше обычного форварда
есть несколько дальнейших оптимизаций
1. Light volumes. Старый прием, хорош отсутствием необходимости использовать компьют шейдеры, и на этом все
Сводится к тому, что мы заранее для каждого источника света рассчитываем освещаемое им пространство (тот самый "объем"). Например, сферу
И далее, когда у нас идет проход расчета освещения, мы вместо полноэкранного квада просто рисуем эти объемы (сферы, конусы и тд). И считаем свет только в их пределах, Таким образом, мы отсекаем из расчетов источники света, которые находятся слишком далеко
У данного подхода есть ряд минусов:
- нужно рендерить по объекту на источник света, то есть большой overdraw и плохо масштабируется на большое количество источников
- сложности с глубиной, камерой внутри освещенных объемов и т.д.
2. Deferred Lighting (оно же Light Pre-Pass). Тоже старая техника
Делаем три прохода вместо двух - в первый проход (геометрии) заполняем всё, кроме альбедо. Второй считает освещение без знания альбедо и складывает в отдельный буфер. И третий, итоговый, снова рендерит геометрию, читает альбедо и умножает на посчитанный до этого свет
Можно совмещать с light volumes
Суть в том, что такие манипуляции позволяют уменьшить G Buffer, а значит сэкономить видеопамять и пропускную способность видеокарты. Но, при этом, мы вынуждены делать больше проходов, сложнее считать тени, и без полноценных данных в G Buffer сложнее сделать PBR и постпроцессинг
На данный момент встречается редко
3. Tiled Deferred Shading. Более современное решение, требует компьют шейдеров
Идея в следующем: в компьют шейдере делим экран на тайлы (обычно 8х8 или 16х16). Для каждого тайла строим список источников света, пересекающих его область видимости (tile frustum). Это может быть просто список индексов из глобального массива источников света
Далее считаем свет по пикселям тайла, учитывая только его источники освещения. Ну и пишем результат в буфер освещения
Это уже довольно оптимизированный вариант, способный рендерить около тысячи источников света за менее чем миллисекунду
Прикреплю ниже презентацию этого подхода с бенчмарками с SIGGRAPH 2010
Из минусов же:
- большое использование видеопамяти на все эти буферы индексов тайлов, причем оно зависит и от разрешения.
- 2д тайлы не знают глубины. При большом динамическом диапазоне по Z в одном тайле может оказаться много источников света
4. Clustered Deferred Shading. Современный, очень оптимизированный, но довольно сложный в реализации вариант
Это развитие идеи Tiled Deferred Shading.
Вместо 2д тайлов мы разбиваем в 3д - каждый frustum еще нарезается логарифмически по Z, таким образом получаем кластеры.
Аналогично, строим список источников света, но уже для каждого кластера отдельно. Соответственно, при расчете освещения, каждый кластер учитывает только свои источники света, что решает вопрос глубины
Тут довольно много оптимизаций, например можно делать куллинг кластеров по октодереву
Также эти списки источников света для кластеров можно потом переиспользовать, например в отдельном прогоне для прозрачности
Реализация довольно трудоемка, однако выдает очень внушительные результаты - в изначальном докладе их реализация куллила 1048576 случайно распределенных источников света за 6 миллисекунд, в то время как Tiled Deferred Shading справился с той же задачей за 342 миллисекунды
Однако стоит заметить, что в том же докладе Clustered вариант показал себя незначительно хуже Tiled при малом количестве источников освещения (тысяча и меньше), потому что накладные расходы на алгоритм Clustered при таких масштабах проигрывают грубому перебору Tiled
Сам доклад тоже скину
есть несколько дальнейших оптимизаций
1. Light volumes. Старый прием, хорош отсутствием необходимости использовать компьют шейдеры, и на этом все
Сводится к тому, что мы заранее для каждого источника света рассчитываем освещаемое им пространство (тот самый "объем"). Например, сферу
И далее, когда у нас идет проход расчета освещения, мы вместо полноэкранного квада просто рисуем эти объемы (сферы, конусы и тд). И считаем свет только в их пределах, Таким образом, мы отсекаем из расчетов источники света, которые находятся слишком далеко
У данного подхода есть ряд минусов:
- нужно рендерить по объекту на источник света, то есть большой overdraw и плохо масштабируется на большое количество источников
- сложности с глубиной, камерой внутри освещенных объемов и т.д.
2. Deferred Lighting (оно же Light Pre-Pass). Тоже старая техника
Делаем три прохода вместо двух - в первый проход (геометрии) заполняем всё, кроме альбедо. Второй считает освещение без знания альбедо и складывает в отдельный буфер. И третий, итоговый, снова рендерит геометрию, читает альбедо и умножает на посчитанный до этого свет
Можно совмещать с light volumes
Суть в том, что такие манипуляции позволяют уменьшить G Buffer, а значит сэкономить видеопамять и пропускную способность видеокарты. Но, при этом, мы вынуждены делать больше проходов, сложнее считать тени, и без полноценных данных в G Buffer сложнее сделать PBR и постпроцессинг
На данный момент встречается редко
3. Tiled Deferred Shading. Более современное решение, требует компьют шейдеров
Идея в следующем: в компьют шейдере делим экран на тайлы (обычно 8х8 или 16х16). Для каждого тайла строим список источников света, пересекающих его область видимости (tile frustum). Это может быть просто список индексов из глобального массива источников света
Далее считаем свет по пикселям тайла, учитывая только его источники освещения. Ну и пишем результат в буфер освещения
Это уже довольно оптимизированный вариант, способный рендерить около тысячи источников света за менее чем миллисекунду
Прикреплю ниже презентацию этого подхода с бенчмарками с SIGGRAPH 2010
Из минусов же:
- большое использование видеопамяти на все эти буферы индексов тайлов, причем оно зависит и от разрешения.
- 2д тайлы не знают глубины. При большом динамическом диапазоне по Z в одном тайле может оказаться много источников света
4. Clustered Deferred Shading. Современный, очень оптимизированный, но довольно сложный в реализации вариант
Это развитие идеи Tiled Deferred Shading.
Вместо 2д тайлов мы разбиваем в 3д - каждый frustum еще нарезается логарифмически по Z, таким образом получаем кластеры.
Аналогично, строим список источников света, но уже для каждого кластера отдельно. Соответственно, при расчете освещения, каждый кластер учитывает только свои источники света, что решает вопрос глубины
Тут довольно много оптимизаций, например можно делать куллинг кластеров по октодереву
Также эти списки источников света для кластеров можно потом переиспользовать, например в отдельном прогоне для прозрачности
Реализация довольно трудоемка, однако выдает очень внушительные результаты - в изначальном докладе их реализация куллила 1048576 случайно распределенных источников света за 6 миллисекунд, в то время как Tiled Deferred Shading справился с той же задачей за 342 миллисекунды
Однако стоит заметить, что в том же докладе Clustered вариант показал себя незначительно хуже Tiled при малом количестве источников освещения (тысяча и меньше), потому что накладные расходы на алгоритм Clustered при таких масштабах проигрывают грубому перебору Tiled
Сам доклад тоже скину
🔥4
EVE Online всегда занимала у меня особое место в сердце
Не зря наиграл в нее больше 10к часов в стиме, и еще немало вне стима. И пусть сейчас играть уже некогда, и зачастую интереснее писать код в свободное время, многие аспекты игры до сих пор восхищают. Например, реализация сервер меша на питон бекенде в 2003 году, с которой до сих пор, более 20 лет спустя, смогла сравниться лишь пара игр
Другой из этих аспектов - как разработчики год за годом обновляли графику игры, при этом сохраняя отличную оптимизацию и очень низкие системные требования. Игра регулярно выглядела лучше и лучше, при этом все еще оставаясь играбельной даже на встроенной видеокарте бюджетного ноутбука
Сейчас, к сожалению, авторы игры уже не очень охотно делятся техническими подробностями ее работы. Но так было не всегда, и можно найти старые подробные описания, как все было устроено под капотом
Вот один из примеров
https://www.eveonline.com/news/view/the-many-additions-of-v5plusplus
Статья от 2015 года, где рассказывают про новые оптимизации их доработанного PBR. Тут и увеличение допустимого количества материалов на одну модель, и новые способы упаковки текстур, и смена расчета модели отражений
Редизайны сайта не пощадили статью, и некоторые ссылки в ней теперь отображаются как обычный текст. Но при ручном открытии они все еще работают, и можно наглядно посмотреть, о чем же шла речь
В целом, я считаю, что у этих ребят можно многому научиться в техническом плане. Особенно в разрезе доработки визуала при сохранении отличной оптимизации
В конце концов, они смогли перейти от ужасно устаревшей графики к современной, не растеряв поддержки бюджетных устройств)
Не зря наиграл в нее больше 10к часов в стиме, и еще немало вне стима. И пусть сейчас играть уже некогда, и зачастую интереснее писать код в свободное время, многие аспекты игры до сих пор восхищают. Например, реализация сервер меша на питон бекенде в 2003 году, с которой до сих пор, более 20 лет спустя, смогла сравниться лишь пара игр
Другой из этих аспектов - как разработчики год за годом обновляли графику игры, при этом сохраняя отличную оптимизацию и очень низкие системные требования. Игра регулярно выглядела лучше и лучше, при этом все еще оставаясь играбельной даже на встроенной видеокарте бюджетного ноутбука
Сейчас, к сожалению, авторы игры уже не очень охотно делятся техническими подробностями ее работы. Но так было не всегда, и можно найти старые подробные описания, как все было устроено под капотом
Вот один из примеров
https://www.eveonline.com/news/view/the-many-additions-of-v5plusplus
Статья от 2015 года, где рассказывают про новые оптимизации их доработанного PBR. Тут и увеличение допустимого количества материалов на одну модель, и новые способы упаковки текстур, и смена расчета модели отражений
Редизайны сайта не пощадили статью, и некоторые ссылки в ней теперь отображаются как обычный текст. Но при ручном открытии они все еще работают, и можно наглядно посмотреть, о чем же шла речь
В целом, я считаю, что у этих ребят можно многому научиться в техническом плане. Особенно в разрезе доработки визуала при сохранении отличной оптимизации
В конце концов, они смогли перейти от ужасно устаревшей графики к современной, не растеряв поддержки бюджетных устройств)
EVE Online
Textures, Shaders, and Dirt, Oh My! (The Many Additions of V5++) | EVE Online
.twentytwenty-container { width: 550px; min-height: 309px !important; margin-bottom: 2em; } Revamping every* ship in EVE is an intense process, leveraging the entirety of our art team from concept artists to tech artists and programmers to QA. It takes extreme…
👍3❤1
Только что понял, что еще не писал тут про WASM
Исправляюсь, так как штука очень полезная и в веб-разработке, и на десктопе, и в геймдеве
Есть такой забавный стандарт, WebAssembly
Изначально он задумывался исключительно как некий бинарный придаток к JavaScript, чтобы выносить в него дорогие вычисления на веб-страницах, и таким образом их ускорять
С тех пор много воды утекло - WASM сначала стал полноценный межбраузерным байткодом, потом получил доступ ко внешним API в рамках стандарта WASI, а затем стал использоваться для построения целых веб-приложений с околонулевым участием JavaScript
И потом мы прибыли к той же ключевой точке, которой когда-то достиг сам JS - мы вытащили WASM за пределы браузера и научились запускать его где угодно, вообще без единой строчки на JS и без его движка
WebAssembly на нативных платформах сохранил свои основные качества - переносимость, компактность, неплохая оптимизация, бинарный формат байткода, расширяемость, и, что главное, встроенная песочница для исполняемого кода
Стали появляться нативные WASM рантаймы, способные запускать его в довольно оптимизированном и легковесном виде хоть напрямую на нативных платформах, хоть встраиваясь в другие приложения в качестве библиотек
WASM стали развивать уже с учетом нативного исполнения, и с каждым годом добавлять все больше полезных фич, оптимизаций и возможностей. Как в сам язык, так и в WASI - многопоточность, поддержку сборщиков мусора, компонентную модель, и так далее
Сейчас он превратился в универсальный межъязыковой байткод, полностью портативный между разными платформами. То, чем не смогли стать ни байткод JVM, ни CLR у .NET. Почти любой существующий язык поддерживает сборку в WASM, делая его идеальным кандидатом для интероперабельности
Cloudflare пишут свои Workers на Rust, но не запускают его напрямую. Вместо этого, они собирают Rust код в WASM и запускают на серверах в WASM рантайме, чтобы обеспечить и динамическую загрузку кода, и поддержку многих других языков, кроме Rust - рантайму все равно, из какого языка был собран WASM байткод.
У нас на работе ситуация схожая - внутренний аналог AWS Lambda, бессерверных функций, реализован на WASM. Мы пишем код на Go (как на основном языке в компании), потом собираем его в байткод и запускаем на сервере, чтобы обеспечить динамическую подгрузку, обновление, и лимиты по потреблению ресурсов для этих функций
Zed, стремительно набирающий популярность редактор для разработки, реализовал свою систему плагинов на WASM - они предоставляют контракт API в специальном формате WIT, используемым компонентной моделью WASM. А дальше можно для любого языка сгенерировать из него привязки и реализовать плагин, который будет динамически загружен и исполнен в рантайме, встроенном в сам редактор
В отличие от динамических библиотек, нет никакой привязки к платформе, ABI компилятора и прочему. И есть встроенная песочница для исполняемого кода. Пользователь рантайма определяет, как ограничить ресурсы при запуске, и к каким API давать доступ, причем для каждого запускаемого WASM модуля отдельно
В отличие от скриптовых языков, это оптимизированный бинарный байткод, доступный для всех распространенных языков программирования
Исправляюсь, так как штука очень полезная и в веб-разработке, и на десктопе, и в геймдеве
Есть такой забавный стандарт, WebAssembly
Изначально он задумывался исключительно как некий бинарный придаток к JavaScript, чтобы выносить в него дорогие вычисления на веб-страницах, и таким образом их ускорять
С тех пор много воды утекло - WASM сначала стал полноценный межбраузерным байткодом, потом получил доступ ко внешним API в рамках стандарта WASI, а затем стал использоваться для построения целых веб-приложений с околонулевым участием JavaScript
И потом мы прибыли к той же ключевой точке, которой когда-то достиг сам JS - мы вытащили WASM за пределы браузера и научились запускать его где угодно, вообще без единой строчки на JS и без его движка
WebAssembly на нативных платформах сохранил свои основные качества - переносимость, компактность, неплохая оптимизация, бинарный формат байткода, расширяемость, и, что главное, встроенная песочница для исполняемого кода
Стали появляться нативные WASM рантаймы, способные запускать его в довольно оптимизированном и легковесном виде хоть напрямую на нативных платформах, хоть встраиваясь в другие приложения в качестве библиотек
WASM стали развивать уже с учетом нативного исполнения, и с каждым годом добавлять все больше полезных фич, оптимизаций и возможностей. Как в сам язык, так и в WASI - многопоточность, поддержку сборщиков мусора, компонентную модель, и так далее
Сейчас он превратился в универсальный межъязыковой байткод, полностью портативный между разными платформами. То, чем не смогли стать ни байткод JVM, ни CLR у .NET. Почти любой существующий язык поддерживает сборку в WASM, делая его идеальным кандидатом для интероперабельности
Cloudflare пишут свои Workers на Rust, но не запускают его напрямую. Вместо этого, они собирают Rust код в WASM и запускают на серверах в WASM рантайме, чтобы обеспечить и динамическую загрузку кода, и поддержку многих других языков, кроме Rust - рантайму все равно, из какого языка был собран WASM байткод.
У нас на работе ситуация схожая - внутренний аналог AWS Lambda, бессерверных функций, реализован на WASM. Мы пишем код на Go (как на основном языке в компании), потом собираем его в байткод и запускаем на сервере, чтобы обеспечить динамическую подгрузку, обновление, и лимиты по потреблению ресурсов для этих функций
Zed, стремительно набирающий популярность редактор для разработки, реализовал свою систему плагинов на WASM - они предоставляют контракт API в специальном формате WIT, используемым компонентной моделью WASM. А дальше можно для любого языка сгенерировать из него привязки и реализовать плагин, который будет динамически загружен и исполнен в рантайме, встроенном в сам редактор
В отличие от динамических библиотек, нет никакой привязки к платформе, ABI компилятора и прочему. И есть встроенная песочница для исполняемого кода. Пользователь рантайма определяет, как ограничить ресурсы при запуске, и к каким API давать доступ, причем для каждого запускаемого WASM модуля отдельно
В отличие от скриптовых языков, это оптимизированный бинарный байткод, доступный для всех распространенных языков программирования
1👍5❤1
Итак, как же всем этим счастьем воспользоваться?
Тут все сводится к выбору подходящего рантайма. Их довольно много, от интерпретатора wasm3 до написанного на Go Wazero. И каждый из них показывает разные результаты по поддержке стандарта, по производительности, и прочим параметрам
Но есть один рантайм, который рекомендуется самими авторами стандартов WASM и WASI, а также первым развивает и внедряет новые фичи (например, WasmGc, поддержку сборщиков мусора, они внедрили за год до появления в стандарте. И реализацию нового стандарта WASI Preview 2 обкатывают именно на нем)
Называется он Wasmtime, и именно его используем и мы на работе, и Zed для своих плагинов, и Cloudflare (но у последних он параллельно с V8)
Разработчикам на Rust тут повезло, потому что Wasmtime написан именно на этом языке, сверху донизу, и отлично интегрируется в проекты на нем. Однако он также имеет C и C++ API, что позволяет встроить его в код на других языках
Поскольку у нас на работе подавляющая часть кода на Go, мы изначально рассматривали Wazero, так как его элементарно интегрировать благодаря тому же языку. Однако Wasmtime оказался в 9.8 раз быстрее в исполнении байткода, поэтому решили, что такая разница в производительности стоит страданий с CGO и привязками
Wasmtime не только отличен сам по себе, он также основан на Cranelift от тех же разработчиков (ByteCodeAlliance), который оптимизируется под его нужды. А это аналог LLVM, который весит в сотню раз меньше, обрабатывает код в 10 раз быстрее, и генерируемые бинарные файлы, по разным данным, или работают с той же скоростью, или медленнее лишь на 5-10%. Это позволяет Cranelift использоваться и для обычной AOT компиляции, и для JIT в рантайме, включая WASM внутри Wasmtime
Cranelift, кроме упомянутого выше применения, также используется для экспериментального бекенда компилятора языка Rust, тогда как бекендом по-умолчанию является LLVM. На реальном проекте переход на Cranelift сократил время компиляции Rust кода на 59%
В общем, на данный момент WASM является отличным способом запуска кода, написанного на Rust, JS, TS, Python, Go, Zig, C, C++, Kotlin, C#, Java, PHP, Ruby, Swift, R, Objective-C, Dart, Odin, и многих других языках, на любой платформе и в контролируемом окружении. С возможностью как ограничить доступные ресурсы и API, так и предоставить собственные. И с динамическим запуском и выгрузкой, без критичных потерь производительности относительно натива благодаря JIT
При этом, в отличие от многих больших рантаймов языков вроде V8, упомянутый Wasmtime весит всего 10-15мб в виде библиотеки, в зависимости от платформы. А сборка с LTO способна еще больше сократить этот размер, исключив неиспользуемые участки кода
Тут все сводится к выбору подходящего рантайма. Их довольно много, от интерпретатора wasm3 до написанного на Go Wazero. И каждый из них показывает разные результаты по поддержке стандарта, по производительности, и прочим параметрам
Но есть один рантайм, который рекомендуется самими авторами стандартов WASM и WASI, а также первым развивает и внедряет новые фичи (например, WasmGc, поддержку сборщиков мусора, они внедрили за год до появления в стандарте. И реализацию нового стандарта WASI Preview 2 обкатывают именно на нем)
Называется он Wasmtime, и именно его используем и мы на работе, и Zed для своих плагинов, и Cloudflare (но у последних он параллельно с V8)
Разработчикам на Rust тут повезло, потому что Wasmtime написан именно на этом языке, сверху донизу, и отлично интегрируется в проекты на нем. Однако он также имеет C и C++ API, что позволяет встроить его в код на других языках
Поскольку у нас на работе подавляющая часть кода на Go, мы изначально рассматривали Wazero, так как его элементарно интегрировать благодаря тому же языку. Однако Wasmtime оказался в 9.8 раз быстрее в исполнении байткода, поэтому решили, что такая разница в производительности стоит страданий с CGO и привязками
Wasmtime не только отличен сам по себе, он также основан на Cranelift от тех же разработчиков (ByteCodeAlliance), который оптимизируется под его нужды. А это аналог LLVM, который весит в сотню раз меньше, обрабатывает код в 10 раз быстрее, и генерируемые бинарные файлы, по разным данным, или работают с той же скоростью, или медленнее лишь на 5-10%. Это позволяет Cranelift использоваться и для обычной AOT компиляции, и для JIT в рантайме, включая WASM внутри Wasmtime
Cranelift, кроме упомянутого выше применения, также используется для экспериментального бекенда компилятора языка Rust, тогда как бекендом по-умолчанию является LLVM. На реальном проекте переход на Cranelift сократил время компиляции Rust кода на 59%
В общем, на данный момент WASM является отличным способом запуска кода, написанного на Rust, JS, TS, Python, Go, Zig, C, C++, Kotlin, C#, Java, PHP, Ruby, Swift, R, Objective-C, Dart, Odin, и многих других языках, на любой платформе и в контролируемом окружении. С возможностью как ограничить доступные ресурсы и API, так и предоставить собственные. И с динамическим запуском и выгрузкой, без критичных потерь производительности относительно натива благодаря JIT
При этом, в отличие от многих больших рантаймов языков вроде V8, упомянутый Wasmtime весит всего 10-15мб в виде библиотеки, в зависимости от платформы. А сборка с LTO способна еще больше сократить этот размер, исключив неиспользуемые участки кода
1👍4
И тут мы приходим к вариантам реализации поддержки модов в играх (и плагинов в приложениях, поскольку подход по сути тот же)
1. Подгрузка динамических библиотек
Старый, проверенный способ. Самый гибкий, поскольку позволяет таким образом подменять ключевые части игры, такие как рендер движок, если код изначально был разработан с учетом такой возможности
Из минусов же - зависит и от операционной системы, и от используемого компилятора, и от архитектуры процессора, и от прочих факторов. В общем, портативность околонулевая
И поддерживается по-настоящему лишь парой языков, а конкретно C, C++, Rust, Odin и Zig. Очевидно, что в геймдеве гораздо более распространены первые два, что еще больше сужает выбор
Кроме того, у автора приложения, загружающего подобную чужую библиотеку, нет почти никакого контроля над ее поведением, что плохо отражается на безопасности
2. Интеграция поддержки скриптовых языков прямо в игру.
Это довольно популярный способ - Dual Universe, Starbase, аддоны WoW и другие, например, предпочитают использовать Lua или подобные ему языки.
Данный подход гораздо проще для начинающих мододелов, но требует встраивать рантайм языка в движок игры и предоставлять API для модов. А также загоняет в рамки одного, избранного разработчиками скриптового языка, нередко не слишком производительного благодаря своей текстовой форме (отсюда те же ограничения на размер кода скрипта в Starbase, например)
Однако полностью пропадают проблемы портативности и кроссплатформерности - написанный в таком формате мод будет работать где угодно
Ну и, в отличие от подгрузки динамических библиотек, здесь уже есть только возможность вызывать предоставленные движком игры API, а не заменять его части на собственные реализации
3. Подход с WASM, описанный в прошлых сообщениях.
По сути, является развитием идеи со встраиванием скриптовых языков - мы так же встраиваем рантайм, так же делаем для него свое API, но теперь в качестве "поддерживаемого языка" у нас универсальный байткод в виде WASM, а не конкретный скриптовый язык.
Это имеет те же самые минусы, что и изначальный подход со скриптами, но зато добавляются новые плюсы - повышенная производительность и поддержка любых языков. Можно даже миксовать языки - например, из одного мода, изначально написанного на Python, вызывать другой, написанный на Zig. Это подобно тому, как разные языки на базе байткода JVM могут вызывать библиотеки друг друга
Ну и, разумеется, тут пользователь рантайма уже полностью контролирует и потребление ресурсов, и доступ к разным API загружаемого кода
Стоит заметить. что перечисленные выше подходы актуальны лишь для игр, написанных на компилируемых нативных языках, вроде упомянутых в первом пункте. Поскольку динамические языки вроде JS или Python и так способны подгружать и исполнять код во время работы, полностью решая проблему расширяемости
1. Подгрузка динамических библиотек
Старый, проверенный способ. Самый гибкий, поскольку позволяет таким образом подменять ключевые части игры, такие как рендер движок, если код изначально был разработан с учетом такой возможности
Из минусов же - зависит и от операционной системы, и от используемого компилятора, и от архитектуры процессора, и от прочих факторов. В общем, портативность околонулевая
И поддерживается по-настоящему лишь парой языков, а конкретно C, C++, Rust, Odin и Zig. Очевидно, что в геймдеве гораздо более распространены первые два, что еще больше сужает выбор
Кроме того, у автора приложения, загружающего подобную чужую библиотеку, нет почти никакого контроля над ее поведением, что плохо отражается на безопасности
2. Интеграция поддержки скриптовых языков прямо в игру.
Это довольно популярный способ - Dual Universe, Starbase, аддоны WoW и другие, например, предпочитают использовать Lua или подобные ему языки.
Данный подход гораздо проще для начинающих мододелов, но требует встраивать рантайм языка в движок игры и предоставлять API для модов. А также загоняет в рамки одного, избранного разработчиками скриптового языка, нередко не слишком производительного благодаря своей текстовой форме (отсюда те же ограничения на размер кода скрипта в Starbase, например)
Однако полностью пропадают проблемы портативности и кроссплатформерности - написанный в таком формате мод будет работать где угодно
Ну и, в отличие от подгрузки динамических библиотек, здесь уже есть только возможность вызывать предоставленные движком игры API, а не заменять его части на собственные реализации
3. Подход с WASM, описанный в прошлых сообщениях.
По сути, является развитием идеи со встраиванием скриптовых языков - мы так же встраиваем рантайм, так же делаем для него свое API, но теперь в качестве "поддерживаемого языка" у нас универсальный байткод в виде WASM, а не конкретный скриптовый язык.
Это имеет те же самые минусы, что и изначальный подход со скриптами, но зато добавляются новые плюсы - повышенная производительность и поддержка любых языков. Можно даже миксовать языки - например, из одного мода, изначально написанного на Python, вызывать другой, написанный на Zig. Это подобно тому, как разные языки на базе байткода JVM могут вызывать библиотеки друг друга
Ну и, разумеется, тут пользователь рантайма уже полностью контролирует и потребление ресурсов, и доступ к разным API загружаемого кода
Стоит заметить. что перечисленные выше подходы актуальны лишь для игр, написанных на компилируемых нативных языках, вроде упомянутых в первом пункте. Поскольку динамические языки вроде JS или Python и так способны подгружать и исполнять код во время работы, полностью решая проблему расширяемости
👍4
По поводу ограничения ресурсов при запуске WASM, рантаймы придумали довольно занятные схемы, выходящие за пределы простых лимитов CPU и памяти
Например, в Wasmtime сделали концепцию топлива. Инструкции в исполняемом WASM потребляют его на свою работу, а пользователь рантайма может задать как изначальное количество топлива для каждого исполняемого модуля, так и периодическое его пополнение
Таким образом, можно не просто помешать динамически загружаемому коду сожрать все ресурсы железа, но и, по сути, троттлить его, периодически выделяя какое-то количества топлива, например раз в секунду
В паре с динамической настройкой доступных API это позволяет очень гибко подстраивать песочницу рантайма под свои нужды, реализуя приоритеты для исполняемых модулей и другие необходимые механизмы
Например, в Wasmtime сделали концепцию топлива. Инструкции в исполняемом WASM потребляют его на свою работу, а пользователь рантайма может задать как изначальное количество топлива для каждого исполняемого модуля, так и периодическое его пополнение
Таким образом, можно не просто помешать динамически загружаемому коду сожрать все ресурсы железа, но и, по сути, троттлить его, периодически выделяя какое-то количества топлива, например раз в секунду
В паре с динамической настройкой доступных API это позволяет очень гибко подстраивать песочницу рантайма под свои нужды, реализуя приоритеты для исполняемых модулей и другие необходимые механизмы
🔥3
Уже второй или третий раз натыкаюсь на высказывание "WebGPU не нужен для натива, когда есть NVRHI"
Так как это уже не впервые, хочется пояснить, почему я считаю это недальновидным
1. NVRHI - библиотека-абстракция от Nvidia. Пока что опенсорсная, но эта корпорация уже прославилась "бумажным" опенсорсом, как с их драйверами. Нет ровно никаких гарантий, что ее не сделают проприетарной. Особенно учитывая, что у них же самих есть и NRI, по сути конкурент NVRHI. То есть, рано или поздно должен остаться кто-то один, просто по законам оптимизации расходов бизнеса
Учитывая, что игры без движка и сами движки, которые и являются основными пользователями подобных библиотек, разрабатываются годами, если не десятилетиями - я бы назвал идею надеяться на многолетнюю доброту Nvidia очень наивной
На контрасте сразу выделяется WebGPU и его реализации, поскольку это стандарт W3C, созданный и развиваемый Mozilla, Google, Apple и Khronos. Тут невозможно закрытие или прекращение развития всего API просто по желанию одной конкретной компании - существуют разные реализации стандарта, которыми управляет рабочая группа
2. Поддержка платформ
NVRHI поддерживает только Windows x64 и Linux x64/arm64. Никакой поддержки мобильных устройств, веба, устройств компании Apple
Более того, оно поддерживает исключительно DirectX 11, DirectX 12 и Vulkan. Резервного варианта с OpenGL нет.
Указание конкретных архитектур намекает, что в исходном коде есть что-то, что привязано к ним, а значит еще и портирование будет значительно затруднено
Реализации WebGPU же поддерживают и все операционные системы, и все графические API как бекенды. И не зависят от используемой архитектуры (по крайней мере wgpu, как реализация, с которой я больше всего знаком)
3. Исходный код и его качество
NVRHI написан на C++, и это значит 2 вещи:
- Очень тяжело привязываться из других языков. Не зря .NET и Odin привязываются именно к растовой wgpu через его C API под названием wgpu-native, вместо написанного на C++ Dawn
- Более низкая надежность кода. Я бы сказал "потенциальная", если бы не было уже фактических подтверждений
Например вот, базовая функция, задуманная как потокобезопасная, внезапно не оказалась таковой, и крашила всю библиотеку
https://github.com/NVIDIA-RTX/NVRHI/issues/32
Это говорит и о зрелости всей библиотеки, и о качестве тестирования (или его отсутствии).
Очень старые и зрелые библиотеки на C++ могут быть более-менее стабильными, просто потому что у них уже было много лет на нахождение всех критичных багов. И даже это не факт - не так давно обнаружилось, что openssl некорректно работал с glibc в многопотоке, вызывая порчу памяти и краш на arm64 архитектуре)
У подобных NVRHI новых решений же даже этих многих лет на стабилизацию не было, что делает их еще более хрупкими и ненадежными. Собственно, в ишью выше они сами же и пишут, что "в многопоточном окружении не тестировали проект")
С другой же стороны, wgpu существует с 2014 года (если учитывать его разработку под старым названием gfx) и уже прошел самую болезненную, незрелую фазу. А также он изначально написан на языке, где львиная часть подобных проблем предотвращается компилятором (например, возможность случайно поделиться ресурсами между потоками без синхронизации, как было тут)
В целом, я бы сказал, что NVRHI является валидным выбором только в очень специфичном случае - если у вас однопоточная игра на C++, рассматривающая как целевые платформы только самые распространенные конфигурации Windows и Linux. И даже так, остаются риск под названием Nvidia и нестабильность библиотеки
Во всех остальных кейсах я бы предпочел WebGPU, а конкретно Dawn/wgpu-native для C++ проектов, и wgpu/wgpu-native для всех остальных языков программирования
Так как это уже не впервые, хочется пояснить, почему я считаю это недальновидным
1. NVRHI - библиотека-абстракция от Nvidia. Пока что опенсорсная, но эта корпорация уже прославилась "бумажным" опенсорсом, как с их драйверами. Нет ровно никаких гарантий, что ее не сделают проприетарной. Особенно учитывая, что у них же самих есть и NRI, по сути конкурент NVRHI. То есть, рано или поздно должен остаться кто-то один, просто по законам оптимизации расходов бизнеса
Учитывая, что игры без движка и сами движки, которые и являются основными пользователями подобных библиотек, разрабатываются годами, если не десятилетиями - я бы назвал идею надеяться на многолетнюю доброту Nvidia очень наивной
На контрасте сразу выделяется WebGPU и его реализации, поскольку это стандарт W3C, созданный и развиваемый Mozilla, Google, Apple и Khronos. Тут невозможно закрытие или прекращение развития всего API просто по желанию одной конкретной компании - существуют разные реализации стандарта, которыми управляет рабочая группа
2. Поддержка платформ
NVRHI поддерживает только Windows x64 и Linux x64/arm64. Никакой поддержки мобильных устройств, веба, устройств компании Apple
Более того, оно поддерживает исключительно DirectX 11, DirectX 12 и Vulkan. Резервного варианта с OpenGL нет.
Указание конкретных архитектур намекает, что в исходном коде есть что-то, что привязано к ним, а значит еще и портирование будет значительно затруднено
Реализации WebGPU же поддерживают и все операционные системы, и все графические API как бекенды. И не зависят от используемой архитектуры (по крайней мере wgpu, как реализация, с которой я больше всего знаком)
3. Исходный код и его качество
NVRHI написан на C++, и это значит 2 вещи:
- Очень тяжело привязываться из других языков. Не зря .NET и Odin привязываются именно к растовой wgpu через его C API под названием wgpu-native, вместо написанного на C++ Dawn
- Более низкая надежность кода. Я бы сказал "потенциальная", если бы не было уже фактических подтверждений
Например вот, базовая функция, задуманная как потокобезопасная, внезапно не оказалась таковой, и крашила всю библиотеку
https://github.com/NVIDIA-RTX/NVRHI/issues/32
Это говорит и о зрелости всей библиотеки, и о качестве тестирования (или его отсутствии).
Очень старые и зрелые библиотеки на C++ могут быть более-менее стабильными, просто потому что у них уже было много лет на нахождение всех критичных багов. И даже это не факт - не так давно обнаружилось, что openssl некорректно работал с glibc в многопотоке, вызывая порчу памяти и краш на arm64 архитектуре)
У подобных NVRHI новых решений же даже этих многих лет на стабилизацию не было, что делает их еще более хрупкими и ненадежными. Собственно, в ишью выше они сами же и пишут, что "в многопоточном окружении не тестировали проект")
С другой же стороны, wgpu существует с 2014 года (если учитывать его разработку под старым названием gfx) и уже прошел самую болезненную, незрелую фазу. А также он изначально написан на языке, где львиная часть подобных проблем предотвращается компилятором (например, возможность случайно поделиться ресурсами между потоками без синхронизации, как было тут)
В целом, я бы сказал, что NVRHI является валидным выбором только в очень специфичном случае - если у вас однопоточная игра на C++, рассматривающая как целевые платформы только самые распространенные конфигурации Windows и Linux. И даже так, остаются риск под названием Nvidia и нестабильность библиотеки
Во всех остальных кейсах я бы предпочел WebGPU, а конкретно Dawn/wgpu-native для C++ проектов, и wgpu/wgpu-native для всех остальных языков программирования
GitHub
Thread safety documentation · Issue #32 · NVIDIA-RTX/NVRHI
I was looking at implementing multi-threading in my engine for uploading textures. I used the CommandList::writeTexture method. Unfortunately this causes a crash, as although it's a member of t...
👍6❤1
Один из адептов NVRHI такую картинку показал
И добавил, что обновлять очень тяжело
Но он использовал Dawn, потому что фанат C++, и не захотел брать wgpu-native, так как оно растовое
Про саму NVRHI я уже только что написал
Но это, на самом деле, дает очень хорошую почву для сравнения Dawn и wgpu как реализаций
Потому что wgpu принимает и другие форматы шейдеров, не только wgsl (можно использовать wgsl, glsl, spir-v и naga ir с валидацией, или любые другие форматы без нее)
И поддерживает трассировку лучей, байндлесс ресурсы, меш шейдеры, и прочее, чего человеку не хватило
И, кроме того, весит в 10 раз меньше Dawn как библиотека
Ну и собирается и обновляется элементарно, благодаря хорошему тулингу Rust и аккуратным изменениям в API
Отсюда видна разница в подходах:
- Dawn просто тупо идет по стандарту WebGPU, сохраняя все проблемы типичной С++ библиотеки, и ничего не дает сверх этого.
- wgpu старается обеспечить удобство и возможности нативных API там, где это возможно, за рамками веб стандарта
И добавил, что обновлять очень тяжело
Но он использовал Dawn, потому что фанат C++, и не захотел брать wgpu-native, так как оно растовое
Про саму NVRHI я уже только что написал
Но это, на самом деле, дает очень хорошую почву для сравнения Dawn и wgpu как реализаций
Потому что wgpu принимает и другие форматы шейдеров, не только wgsl (можно использовать wgsl, glsl, spir-v и naga ir с валидацией, или любые другие форматы без нее)
И поддерживает трассировку лучей, байндлесс ресурсы, меш шейдеры, и прочее, чего человеку не хватило
И, кроме того, весит в 10 раз меньше Dawn как библиотека
Ну и собирается и обновляется элементарно, благодаря хорошему тулингу Rust и аккуратным изменениям в API
Отсюда видна разница в подходах:
- Dawn просто тупо идет по стандарту WebGPU, сохраняя все проблемы типичной С++ библиотеки, и ничего не дает сверх этого.
- wgpu старается обеспечить удобство и возможности нативных API там, где это возможно, за рамками веб стандарта
❤4👌1
К слову, во время создания стандарта WebGPU, изначально хотели в качестве формата шейдеров использовать как раз SPIR-V
Потому что уже существует, используется Vulkan, опенсорсный, и зачем изобретать велосипед
Но в ходе экспериментов было выявлено, что он просто ужасен в качестве промежуточного формата шейдеров
И именно тогда было принято решение сделать WGSL, поскольку SPIR-V себя совсем не оправдал
Про это неплохо, с примерами, написано в блоге Димы Kvark, тогдашнего участника рабочей группы W3C от Mozilla, одного из разработчиков wgpu, и участника нашего геймдев чата
https://kvark.github.io/spirv/2021/05/01/spirv-horrors.html
Потому что уже существует, используется Vulkan, опенсорсный, и зачем изобретать велосипед
Но в ходе экспериментов было выявлено, что он просто ужасен в качестве промежуточного формата шейдеров
И именно тогда было принято решение сделать WGSL, поскольку SPIR-V себя совсем не оправдал
Про это неплохо, с примерами, написано в блоге Димы Kvark, тогдашнего участника рабочей группы W3C от Mozilla, одного из разработчиков wgpu, и участника нашего геймдев чата
https://kvark.github.io/spirv/2021/05/01/spirv-horrors.html
kvark.github.io
Horrors of SPIR-V
Disclaimer: this is a rant about SPIR-V specifically in the context of graphics (not general compute). Some of the weirdness of SPIR-V came around from the n...
❤4
This media is not supported in your browser
VIEW IN TELEGRAM
Наглядный пример, почему баги будут всегда, и наивно думать, что можно протестить все конфигурации
В данном случае люди наткнулись на занятный баг в Godot 4.5
картинка рендерится вверх ногами, но только при двух условиях
- используется Compatibility рендер, то есть на opengl. На Forward+, который на новых графических API, такого нет
- параллельно включен захват экрана в OBS
https://www.reddit.com/r/IndieDev/comments/1oan6n9/lets_just_update_the_engine_quickly_and_send_the/nkah168
некоторые баги требуют совпадения десятков специфических условий для возникновения
Еще один пример - AWS нашли баг, затрагивающий их сервисы S3 и DynamoDB, для возникновения которого требовалось совпадение 35 конкретных условий по нескольким сервисам
https://cacm.acm.org/research/how-amazon-web-services-uses-formal-methods/
В данном случае люди наткнулись на занятный баг в Godot 4.5
картинка рендерится вверх ногами, но только при двух условиях
- используется Compatibility рендер, то есть на opengl. На Forward+, который на новых графических API, такого нет
- параллельно включен захват экрана в OBS
https://www.reddit.com/r/IndieDev/comments/1oan6n9/lets_just_update_the_engine_quickly_and_send_the/nkah168
некоторые баги требуют совпадения десятков специфических условий для возникновения
Еще один пример - AWS нашли баг, затрагивающий их сервисы S3 и DynamoDB, для возникновения которого требовалось совпадение 35 конкретных условий по нескольким сервисам
https://cacm.acm.org/research/how-amazon-web-services-uses-formal-methods/
🔥7❤🔥1👍1
Завел отдельный канал, в который буду скидывать полезные ссылки и файлы по компьютерной графике и геймдеву
Идея сделать его неким списком закладок, чтобы не терять ценные материалы
@rust_gamedev_bookmarks
Идея сделать его неким списком закладок, чтобы не терять ценные материалы
@rust_gamedev_bookmarks
1👍4🤯2❤🔥1
Abyssal Code pinned «Завел отдельный канал, в который буду скидывать полезные ссылки и файлы по компьютерной графике и геймдеву Идея сделать его неким списком закладок, чтобы не терять ценные материалы @rust_gamedev_bookmarks»
Abyssal Code
Однако, указанная выше реализация все еще очень неоптимальна, потому что даже в ней, мы вынуждены во фрагментном шейдере прохода освещения рассчитывать свет для pixels * number of lights, то есть каждый источник света участвует в расчетах каждого пикселя,…
frostbite_unified_volumetrics.pdf
1.6 MB
Не так давно я упоминал Clustered Shading как способ оптимизации для отрисовки множества источников света
Там была идея в разбиении видимой области (frustum) на 3д регионы, желательно логарифмически. И дальнейшем просчете света в рамках этих регионов
Так вот, наткнулся на способ рендера объемных тел (например, облаков или туманностей) через очень похожий способ
Его объясняют в прикрепленной презентации от 2015 года разработчики движка Frostbite
Там идет точно такое же разбиение видимой области сцены на 3д регионы, и этим регионам дается название - froxel, от frustum voxel
Очень занимательный доклад, показывающий выгоду данного подхода относительно старых способов рендера подобных объектов
А сходство подходов с Clustered Shading позволяет использовать один и тот же набор фрокселей и для освещения, и для рендера объемных сущностей, что очень удобно и экономит ресурсы
Там была идея в разбиении видимой области (frustum) на 3д регионы, желательно логарифмически. И дальнейшем просчете света в рамках этих регионов
Так вот, наткнулся на способ рендера объемных тел (например, облаков или туманностей) через очень похожий способ
Его объясняют в прикрепленной презентации от 2015 года разработчики движка Frostbite
Там идет точно такое же разбиение видимой области сцены на 3д регионы, и этим регионам дается название - froxel, от frustum voxel
Очень занимательный доклад, показывающий выгоду данного подхода относительно старых способов рендера подобных объектов
А сходство подходов с Clustered Shading позволяет использовать один и тот же набор фрокселей и для освещения, и для рендера объемных сущностей, что очень удобно и экономит ресурсы
8❤3👍2👌2🔥1