Вступление

Система рендеринга Unreal Engine 4 бесконечно настраивается и поддерживает большинство методов рендеринга последнего поколения на нескольких платформах. Написание материалов в Unreal очень доступно благодаря редактору на основе узлов, но люди часто не решаются нырять глубже, чем это, из-за сложности системы рендеринга и отсутствия доступного образовательного контента.

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

Когда я намеревался добавить новую модель затенения в Unreal, я изо всех сил пытался понять, как разные части системы рендеринга работают вместе. Есть несколько существующих руководств о том, как это сделать, но, не объясняя, как системы работают вместе, мне было трудно вносить изменения, кроме простого копирования того, что было сделано в руководстве.

Поэтому цель данной серии статей - помочь обрисовать, как различные части системы рендеринга связаны друг с другом, в отличие от рассмотрения технической реализации любой данной части. В этой серии статей мы сосредоточимся на конвейере отложенного затенения со стороны ЦП и ГП, но не будем слишком подробно рассказывать о системе затенения, полупрозрачных объектах или пост-эффектах. Поскольку мы стараемся не смотреть на конкретные детали реализации, наша цель - дать вам почувствовать, какие классы и функции стоит изучить для дальнейшего самостоятельного изучения.

Посты в этой серии

  1. Введение и настройка - вот этот пост! В этом посте объясняются инструменты и настройки конфигурации, которые облегчат нашу жизнь при разработке.
  2. Шейдеры и вершинные фабрики - в этом посте будет рассказано о том, как Unreal создает экземпляры шейдеров и связывает их с их соответствующим кодом HLSL, а также как Unreal получает данные вершин на GPU.
  3. Политики рисования и фабрики политик рисования - в этом посте рассказывается, как Unreal использует правильные варианты шейдеров для различных техник и как движок знает, в каком порядке рисовать разные проходы.
  4. Архитектура шейдеров - в этом посте рассматривается конвейер отложенного затенения на графическом процессоре и следует порядок того, как конкретный пиксель учитывает освещение и затенение.
  5. Советы по итерации шейдеров - итерация шейдеров может занять довольно много времени из-за компиляции перестановок, поэтому в этой статье будут рассмотрены способы, позволяющие тратить меньше времени на компиляцию шейдеров.
  6. Учебник по добавлению новой модели затенения - в этом посте будет рассказано, как добавить мультяшный материал, который соблюдает свойства PBR. Это основано на более старом сообщении в блоге Феликса Кейт.
  7. (Скоро). Изменение базового прохода с помощью геометрического шейдера. В этом сообщении объясняется, как изменить отложенный базовый проход, чтобы добавить поддержку геометрических шейдеров и создать силуэтный шейдер на основе этих изменений.

Ограничения по статье

Как бы я ни хотел охватить все аспекты возможностей рендеринга Unreal, их просто слишком много. Из-за этого я решил ограничить объяснение наиболее общими областями. В этой серии статей основное внимание будет уделено отложенному затенению конвейеру и не будут учитываться мобильные и кластерные модули прямого рендеринга Unreal. Конвейеры затенения Unreal Mobile и Forward используют другой набор классов (как C ++, так и HLSL), но они должны следовать относительно схожим шаблонам, и они действительно разделяют некоторые функции / структуры данных с основным конвейером отложенного затенения. На стороне шейдера мы будем игнорировать полупрозрачность и экземпляры стерео, поскольку они в основном представляют собой определенные препроцессором вариации существующего кода; Вариации для каждой платформы также будут проигнорированы по той же причине. На стороне C ++ мы в основном игнорируем сторону отбрасывания теней.

Стоит отметить, что различные фрагменты кода могут быть сокращены и упрощены. Большая часть очевидной сложности движка проистекает из различных вариаций, определенных препроцессором, поэтому мы проигнорируем их ради обучения. Это означает, что это серия обзорных сообщений, а не конкретное руководство! При этом в конце этой серии есть два обучающих сообщения (сообщение 6 и сообщение 7), которые даст конкретные примеры изменения конвейера отложенного затенения.

Настройка двигателя

Вы должны собирать движок из исходного кода GitHub. Возможно, вам удастся изменить существующие шейдеры с помощью версии Epic Games Launcher, но для добавления новых моделей затенения и тому подобного потребуется исходный код движка. Если вы планируете часто отлаживать код C ++, вместо Debug Game или Development Editor . Быть комфортным с C ++, HLSL и шаблонами - это плюс, хотя и не требуется, поскольку цель скорее теоретическая, чем техническая.

Ниже приведен список рекомендуемых изменений в настройках и объяснения того, что они делают и почему они могут вам понадобиться.

Инструменты HLSL для Visual Studio

Его можно найти по этому URL-адресу как бесплатное расширение для Visual Studio. Это включает базовую подсветку синтаксиса HLSL и переход к определению для файлов Unreal .usf / .ush. Чтобы он работал с файлами .usf / .ush, вам нужно следовать инструкциям в одном из твитов автора, чтобы добавить их через Tools > Text Editor > File Extensions раздел редактора.

RenderDoc

RenderDoc - отличный инструмент для проверки того, что происходит в графическом процессоре. RenderDoc позволит вам видеть вызовы отрисовки, проверять данные по мере их прохождения через каждый этап на графическом процессоре и (в сочетании с некоторыми флагами ниже) показывать вам исходный код, который Unreal создает и запускает. После загрузки и установки в Unreal предустановлен плагин RenderDoc, который вы можете включить, который добавляет кнопку захвата в главное окно просмотра.

Изменение ConsoleVariables.ini

Этот файл находится в каталоге \Engine\Config\ и позволяет вам указывать значения для переменных, которые должны быть установлены перед запуском движка. Большинство этих переменных уже есть и объяснены.

Установка r.ShaderDevelopmentMode = 1 заставит Unreal запрашивать перекомпиляцию шейдера, если не удается скомпилировать материал по умолчанию. В нормальных условиях Unreal выйдет из строя, если он не сможет скомпилировать материал по умолчанию (для использования в качестве запасного варианта), поэтому это заставляет Unreal запрашивать нас и позволяет нам исправить ошибку компиляции и повторить попытку без перезапуска редактора. Примечание. Если к вам подключен отладчик, Unreal все равно выполнит assert, даже если он включен. Это поведение можно отключить, закомментировав оператор if в ShaderCompiler.cpp около середины FShaderCompilingManager::HandlePotentialRetryOnError, просто найдите FPlatformMisc::DebugBreak().

Установка r.Shaders.Optimize = 0 и r.Shaders.KeepDebugInfo = 1 заставляет Unreal указывать компилятору шейдера использовать более низкие уровни оптимизации и оставить отладочную информацию. Более низкие уровни оптимизации должны сократить время компиляции, а оставление отладочной информации в шейдере позволит улучшить отладку с помощью RenderDoc.

Установка r.DumpShaderDebugInfo = 1 и r.DumpShaderDebugShortNames = 1 может быть полезна в определенных ситуациях. Это записывает сгенерированный HLSL на диск (что составляет около 2 ГБ данных в пустом проекте), но я обнаружил, что использование RenderDoc является более эффективным инструментом отладки. Второй просто сокращает названия различных вещей, чтобы помочь им соответствовать максимальной длине пути ОС.

Изменение BaseEngine.ini

Если вы прокрутите вниз до раздела [DevOptions.Shaders], вы найдете bAllowCompilingThroughWorker = True и bAllowAsynchronousShaderCompiling = True. Сочетание этих двух флагов позволит Unreal выполнять многопоточную компиляцию всех необходимых шейдерных карт. Может быть полезно отключить их, если вы пытаетесь отладить часть конвейера шейдера C ++ (чтобы он работал только с одним шейдером за раз), но это приведет к тому, что компиляция шейдера займет действительно много времени!

Начать пустой проект

Если вообще возможно начать новый проект по разработке шейдеров, сделайте это. Каждый раз, когда вы изменяете файл шейдера, Unreal перекомпилирует все перестановки, использующие этот файл. Это означает, что если вы ковыряетесь в некоторых из базовых шейдеров (как мы будем!), вам придется скомпилировать ~ 125 шейдеров, встроенных в движок, которые генерируют ~ 10 000 пермутаций самостоятельно, уф! Пустой проект предотвратит увеличение этого числа, так как на i7–4770k это может занять около 10 минут.

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

Полезные ссылки

Ниже приведены некоторые ссылки на другую существующую документацию, которая может оказаться полезной для вашего понимания или предоставить альтернативные объяснения концепций, которые могут иметь для вас больше смысла. Ссылки на статьи здесь не имеют определенного порядка.

  • Обзор программирования графики Официальная документация Unreal по высокоуровневому обзору системы рендеринга включает параллели между потоком игры и потоком рендеринга.
  • Потоковый рендеринг охватывает межпотоковое взаимодействие между игрой и рендерингом, а также ограничения и возможные состояния гонки.
  • Разработка шейдеров охватывает высокоуровневый взгляд на фабрики вершин, шейдеры материалов и глобальные шейдеры.
  • Теминология координатного пространства описывает, в чем заключаются ценности различных пространств, и, что более важно, к чему они относятся!
  • Как Unreal Renders a Frame охватывает сторону графического процессора визуализированного кадра, показывая, в каком порядке идут проходы, и примеры того, как выглядит большая часть данных графического процессора.

Терминология

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

RHI

Интерфейс оборудования рендеринга, который представляет собой уровень, абстрагирующий различные графические API-интерфейсы для разных платформ. Все команды рендеринга проходят через слой RHI и переводятся в соответствующий рендерер.

Отложенный рендеринг

Средство визуализации по умолчанию в Unreal Engine 4. Этот документ в основном ограничен этим средством визуализации. Получил свое название от того факта, что он откладывает вычисления освещения / затенения до полноэкранного перехода, а не при отрисовке каждой сетки. Полное объяснение отложенного рендеринга выходит за рамки этого документа, поэтому рекомендуется немного познакомиться, прежде чем погружаться в кодовую базу рендеринга Unreal. Более подробную информацию об отложенном рендеринге можно найти в статье в Википедии, в красивом сравнении / сравнении Forward vs Deferred и Пример Intel Developer Zone на Forward Clustered.

(Кластерный) Прямая визуализация

Реализация прямого рендеринга Unreal для настольных ПК. Эта тема не рассматривается в этом руководстве, но вы встретите множество определений препроцессора, связанных с ней. Это также отличается от мобильного рендерера, который использует более традиционный тайловый отложенный рендерер.

Вид

Единое «окно» в FScene. Может иметь несколько представлений для данного FScene (т. Е. Локальный разделенный экран), но также может иметь несколько FScene в редакторе. Шейдеры используются аналогично, так как они вызывают ResolveView() перед рендерингом, который может быть либо видом игрока, либо конкретным глазом, визуализируемым в VR.

Политика рисования / Фабрика политик рисования

Unreal использует термин «политика рисования» для обозначения класса, который содержит логику для рендеринга определенных мешей с определенными шейдерами. Например, политика рисования только глубины находит правильный вариант шейдера только глубины для данного материала, так что объекты, нарисованные с использованием этой политики, используют оптимизированные шейдеры только глубины. Политики рисования обычно не знают подробностей о шейдерах или сетках, которые они визуализируют. Фабрика политик рисования более специфична для типа и обрабатывает создание политики рисования для каждого объекта, который должен быть отображен, и добавление их в разные списки для последующего использования.

Фабрика вершин

Vertex Factory - это класс, который инкапсулирует источник данных вершин и связан со входом вершинного шейдера. Статические сетки, скелетные сетки и компоненты процедурных сеток используют разные фабрики вершин.

Шейдер

В Unreal шейдер представляет собой комбинацию кода HLSL (в виде файлов .ush / .usf) и содержимого графа материала. При создании материала в Unreal он компилирует несколько вариантов шейдеров на основе настроек (например, режима затенения) и использования.

Следующее сообщение

В следующем посте мы рассмотрим шейдеры и вершинные фабрики более подробно. Мы поговорим о том, как код C ++ привязан к коду HLSL, как код C ++ изменяет переменные в коде HLSL и как вы можете настроить данные, поступающие в вершинный шейдер! Этот пост доступен здесь!

Кредиты

В основном написано Мэттом Хоффманом @lordned и рецензировано следующими людьми: Сай Нараян @ nightmask3, Джереми Абель @jabelsjabels, Стивен Уиттл @mov_eax_rgb, Джо Радак @ Fr0z3nR, Стив Биган, Стив Дэйви @llnesisll и Джавад Кучакзаде @stoopdapoop. Спасибо за просмотр более 40 страниц технической документации!