Запекание Освещения в Вершинные Цвета с Wonderland Engine

Для своей игры в мини-гольф “Above Paradowski”, Колин Фриман, Аюшман Джохри и Джеймс Кейн использовали отличную технику для запекания освещения в своей сцене. Они избавились от обращений к текстурам lightmap в фрагментном шейдере, но при этом добились высокополированного вида своей работы.

В этой статье мы объясним почему эта техника умная и как вы можете использовать её в Wonderland Engine.

Запекание Освещения в Вершинные Цвета с Wonderland Engine
Запекание Освещения в Вершинные Цвета с Wonderland Engine

Скриншот парящего острова в Blender: равномерное освещение (слева), запечённые вершины (справа).

Мотивация 

Расчёт освещения занимает долгое время. Для реалистичного результата необходимо проследить пути света и отражения, каждое из которых приводит к большему количеству путей света и отражений для расчёта. Объём работы стремительно увеличивается!

Так рендерятся анимационные фильмы, но в реальном времени для VR у нас вместо минут на кадр есть около 11 миллисекунд для двух кадров (левый и правый глаз) при 90 Гц для автономных VR-устройств. Вместо фермы рендера на GPU у нас есть мобильный GPU.

Так как поддержание 60-90 Гц важно для комфорта и погружения в VR, мы должны подойти к проблеме по-другому. Wonderland Engine уже реализует многие отличные методы и оптимизации для быстрого рендеринга, даже с реальным временем тенями, но для чрезвычайно больших сцен мы должны использовать каждую возможность повышения производительности.

Запекание Освещения 

Вместо расчёта освещения в реальном времени, мы можем сделать это заранее и сохранить результат в нашем ассете, например, рисуя или рассчитывая тени на наших текстурах. Этот процесс называется “запеканием”.

Мы даже можем использовать те же методы, что и в 3D-анимации, и тем самым получать очень реалистичные результаты.

Текстуры работают хорошо, так как они позволяют сохранить большое количество деталей с тонкими тенями и эффектами освещения. Особенно с потоковой передачей текстур в Wonderland Engine, вы можете использовать текстуры очень высокого разрешения и получать потрясающий вид сцен.

Тем не менее, текстуры требуют много данных для хранения, даже когда они хорошо сжаты. Вместо этого, мы можем обменять немного деталей на размер загрузки и сохранить дополнительный атрибут цвета в вашей сетке на вершину.

Lightmap Текстуры vs Вершинные Цвета 

Когда освещение запекается в текстуры, наш расчёт освещения на GPU в основном сводится к чтению текстуры: для каждого пикселя, который мы рендерим на экран, мы находим соответствующий пиксель в lightmap. Каждый рендеренный пиксель может получать различный цвет из lightmap, что позволяет иметь высокочастотные детали.

Вершинные цвета, с другой стороны, являются входными данными для вершинного шейдера и интерполируются между вершинами. Частота деталей будет зависеть от разрешения вашей сетки и, как правило, будет очень низкой. Это ещё больше сокращает вычисления цвета пикселя до простого переноса интерполированного цвета из вершинного шейдера в выходной буфер кадра.

Производительность 

Что более производительно? Ответ на любой вопрос о производительности всегда такой: это зависит. Особенно от ваших узких мест.

Многие приложения WebXR сегодня ограничены вызовами отрисовки: CPU не может делать больше работы, так что оптимизация рабочей нагрузки на GPU не даёт эффекта. Возможно, это влияет на срок службы батареи, но не на вашу частоту кадров.

Wonderland Engine решает это полностью с помощью своих оптимизаций, рендеря десятки тысяч динамических объектов меньше чем за десять вызовов отрисовки почти в каждом случае. Те некоторые другие приложения, ограниченные вершинным шейдингом из-за скелетной анимации многих персонажей, решены с помощью высокопроизводительного метода скиннинга, оптимизированного для VR, который эффективно обрабатывает сотни различных скинованных сеток.

Но даже приложения Wonderland Engine могут быть ограничены фрагментным шейдингом. Больше инструкций и более дорогих операций в вашем фрагментном шейдере требуют больше вычислительной мощности от GPU на пиксель экрана. Наш “Физический” (PBR) шейдер имеет больше инструкций, чем “Фонг”, который, в свою очередь, имеет больше, чем “Плоский”.

Хотя современные GPU очень быстры при чтении текстур, простое чтение цветов из данных сетки во время выборки вершин будет более кэш-эффективным и трудно переплюнуть, особенно если это также означает, что вы можете полностью исключить нормали и текстурные координаты из вашей сетки. Для этой техники мы можем использовать нетекстурированный плоский шейдер, который требует только позиции и цвета.

Это оставляет меньший объём памяти для чтения на вершину и практически не требует работы на фрагмент. Это оставило бы нас ограниченными только вершинным шейдингом или выборкой вершин, но только при очень впечатляющем количестве вершин в нашей сцене, как показано в Резюме.

Учебник 

Мы начнем с запекания освещения в вершины в Blender, а затем импортируем модель в Wonderland Engine.

Запекание в Вершинные Цвета в Blender 

Выберите сцену и настройте источники света. Blender уже полностью поддерживает запекание в вершины, так что никаких плагинов не нужно, настройка проста:

  1. Откройте окно сценариев в Blender и используйте следующий скрипт на Python, чтобы добавить слой вершинных цветов ко всем выделенным объектам, запустив этот скрипт:
1import bpy
2
3for o in bpy.context.selected_objects:
4    if o.type != 'MESH':
5        continue
6    if len(o.data.vertex_colors) != 0:
7        continue
8
9    o.data.vertex_colors.new()
  1. В Свойствах Рендера, переключите движок рендера на Cycles
  2. Найдите секцию Bake ниже и переключите Output > Target на Vertex Colors
  3. Установите Bake Type на Diffuse
  4. Нажмите кнопку Bake в верхней части этой секции

Чтобы увидеть результат, вы можете установить настройки вида вьюпорта для визуализации результата:

  1. В 3D Вьюпорте найдите стрелку рядом с типами рендера (обычно самая правая кнопка в верхнем меню)
  2. Для Lighting выберите Flat
  3. Для Color выберите Vertex
Запекание Освещения в Вершинные Цвета с Wonderland Engine

Наконец, экспортируйте модель как GLB, выбрав File > Export > glTF 2.0 (.glb/.gltf).

Импорт в Wonderland Engine 

Создайте следующий VertexColor.frag в подпапке shaders в вашем проекте:

 1#include "lib/Compatibility.frag"
 2
 3#define USE_COLOR
 4
 5#define USE_MATERIAL_ID
 6#include "lib/Inputs.frag"
 7
 8void main() {
 9    outColor = fragColor;
10}

Далее мы импортируем модель в Wonderland Engine и используем этот шейдер для её рендеринга:

  1. Перетащите .glb файл в Обозреватель Активов
  2. Оттуда перетащите его в окно сцены
  3. Перейдите в Виды > Ресурсы > Пайплайны и выберите Phong Opaque или Phong Opaque Textured, в зависимости от того, использовали ли ваши объекты текстуры изначально.
  4. Измените шейдер на новый VertexColor.

Изменяя существующий Phong пайплайн, мы можем автоматически изменить все материалы. Более чистой настройкой будет назначение автоматически созданного пайплайна “VertexColor” и назначение его всем материалам, которые мы хотим изменить.

Теперь вы должны увидеть вершиничные цвета, правильно примененные к вашей сцене.

Запекание Освещения в Вершинные Цвета с Wonderland Engine

Резюме 

Запекание освещения в вершины - это очень эффективный способ достижения красивого внешнего вида. Следующее видео демонстрирует 3,6 миллиона вершин, рендеренных с использованием этого метода на 60-72 кадра в секунду на Meta Quest 2 в браузере Meta Quest.

YouTube Video

Демо использует оптимизации Wonderland Engine из коробки, фиксированная фовеация (на 1.0) и метод, описанный в этом блоге. Сцена рендерится в 2 вызова отрисовки (на момент версии 0.9.4, предстоящая поддержка мультиэкранного рендеринга сократит это на 50%). Каждый объект можно всё ещё перемещать независимо с помощью скриптов или анимации без негативного влияния на производительность.

Last Update: December 2, 2022

Будьте в курсе.