Universal render pipeline unity что это
Масштабируемая и высокая производительность рендеринга
Universal Render Pipeline от Unity стал мощным решением, сочетающим красоту, скорость и производительность, а также поддержку всех целевых платформ Unity.
Universal Render Pipeline — это:
В Universal Render Pipeline постобработка встроена непосредственно в процесс рендеринга, обеспечивая высокую производительность. Разработчикам доступны такие эффекты, как сглаживание, глубина резкости, размытие в движении, проекция Панини, блеск, искажение линзы, хроматические аберрации, цвето- и тонокоррекция, виньетка, зернистость и 8-битный дизеринг.
Universal Render Pipeline
Упор на производительность
Однопроходный упреждающий рендеринг
Поддержка Shader Graph
Встроенный процесс рендеринга
Универсальность
Поддерживает как упреждающий, так и отложенный рендеринг
От 2D и 3D до AR/VR-проектов: Universal Render Pipeline позволяет не тратить время на доработку проекта для выпуска на новом устройстве.
Возможность конфигурации рендеринга в Unity с помощью скриптов на C# позволяет вам:
Universal Render Pipeline проще, чем встроенный процесс рендеринга, но улучшает качество графики. Перевод проекта со встроенного процесса рендеринга на Universal Render Pipeline должен обеспечивать аналогичную или улучшенную производительность. Прочтите статью в нашем блоге, чтобы узнать о том, как Universal Render Pipeline повышает частоту кадров без снижения качества графики.
Вы можете воспользоваться преимуществами готовых технологий уже сегодня. Обновите проекты с помощью средств перехода или создайте новый проект на основе нашего шаблона Universal через Unity Hub.
Разработка мобильных игр на Unity. URP, 2D Animation и другие новомодные вещи на примере игры
Дисклеймер! Код в этой статье не проходил рефакторинг и носит лишь ознакомительный характер, чтобы поделиться идеями. И вообще, в целом, это smellscode.
Итак, запасаемся кофе, открываем Unity и погнали!
Базовая настройка проекта. URP и все-все-все.
Стоит указать, что ниже пойдет речь о 2D игре. Для 3D игр подходы будут несколько отличаться, как и настройки.
В нашем проекте стоят следующие настройки (для Quality уровней):
Настройки графики для пресета Low в Project Settings:
На что здесь следует обратить внимание:
Теперь перейдем к настройкам самих URP Asset. На что следует обратить внимание:
Adaptive Performance
Отличная штука для автоматической подгонки производительности мобильных игр (в частности для Samsung-устройств):
Другие полезные настройки:
Отключите 3D освещение, лайтмапы, тени и все что с этим связано.
По-возможности подключите multithreaded rendering.
Игровой фреймворк
Едем дальше. URP и другие настройки проекта сделали. Теперь настало время поговорить о нашем ядре проекта. Что оно включает в себя?
Само ядро фреймворка включает в себя:
Игровые менеджеры для управления состояниями игры, аудио, переводов, работы с сетью, аналитикой, рекламными интеграциями и прочим.
Базовые классы для интерфейсов (компоненты, базовые классы View).
Классы для работы с контентом, сетью, шифрованием и др.
Базовые классы для работы с логикой игры.
Базовые классы для персонажей и пр.
Утилитарные классы (Coroutine Provider, Unix Timestamp, Timed Event и пр.)
Зачем нужны менеджеры?
Они нужны нам для того, чтобы из контроллеров управлять состояниями и глобальными функциями (к примеру, аналитикой).
Хотя мы и используем внедрение зависимостей, менеджеры состояний реализованы в качестве синглтонов (атата по рукам, но нам норм) и могут быть (и по их назначению должны быть) инициализированы единожды. А дальше мы просто можем использовать их:
А уже сам менеджер распределяет, в какие системы аналитики, как и зачем мы отправляем эвент.
Базовые классы.
Здесь все просто. Они включают в себя базовую логику для наследования. К примеру, класс BaseView и его интерфейс:
А дальше мы можем использовать его, к примеру таким образом:
Классы для работы с контентом, сетью, шифрованием
Ну здесь все просто и очевидно. Вообще, у нас реализовано несколько классов:
1) Классы шифрования (Base64, MD5, AES и пр.)
3) Network-классы, которые позволяют удобно работать с HTTP-запросами, работать с бандлами / адрессаблс и др.
Классы для шифрования нужны, чтобы работать с сохранениями и передачей данных на сервер в безопасном формате (относительно безопасном, но от школьников уже спасет).
Утилитарные классы
Здесь у нас хранятся полезные штуки, вроде Unix Time конвертера, а также костыли (вроде Coroutine Provider-а).
Unix Time Converter:
Костыль Coroutine-Provider:
Логика сцен
Зачем это сделано?
Мы можем сохранять прогресс внутри сцены, привязываясь к определенному блоку.
Блоки механик удобнее изменять, нежели огромный инсталлер с кучей разных контроллеров.
Работа с контентом
При работе с контентом, мы стараемся делать упор на оптимизацию. В игре содержится много UI, скелетные 2D анимации, липсинк и прочее. Вообще, контента достаточно много, не смотря на простоту игры.
Анимации в игре
Упаковка и сжатие
Локализация
Вся локализация базируется на JSON. Мы планируем отказаться от этого в ближайшее время, но пока что на время Soft-Launch этого хватает:
Работа с UI
При работе с UI мы разбиваем каждый View под отдельный Canvas. 99% всех анимаций работает на проверенном временем DOTween и отлично оптимизирован.
View инициализируются и обновляются по запросу через эвенты, которые внедряются в Level Installer, либо в отдельных блоках логики.
Что мы используем еще?
Итого
Работа с механиками получается достаточно гибкой за счет блоков логики. Мы изначально думали взять связку Zenject + UniRX, но решили отказаться от нагромождения большой системы. Да, мы сделали проще, но нам и не нужно всех возможностей этих огромных библиотек.
Создание Outline эффекта в Unity Universal Render Pipeline
В Universal Render Pipeline, создавая свои RendererFeature, можно легко расширить возможности отрисовки. Добавление новых проходов в конвеер рендеринга позволяет создавать различные эффекты. В этой статье, используя ScriptableRendererFeature и ScriptableRenderPass, создадим эффект обводки объекта (Outline) и рассмотрим некоторые особенности его реализации.
Вступление или пару слов о Render Pipeline
Scriptable Render Pipeline позволяет управлять отрисовкой графики посредством скриптов на C# и контролировать порядок обработки объектов, света, теней и прочего. Universal Render Pipeline — это готовый Scriptable Render Pipeline, разработанный Unity и предназначенный на замену старому встроенному RP.
Возможности Universal RP можно расширить, создавая и добавляя свои проходы отрисовки ( ScriptableRendererFeature и ScriptableRenderPass ). Об этом и будет текущая статья. Она пригодится тем, кто собирается переходить на Universal RP и, возможно, поможет лучше понимать работу имеющихся ScriptableRenderPass’ов в Universal RP.
При написании этой статьи использовалась Unity 2019.3 и Universal RP 7.1.8.
План действий
Мы будем разбираться в работе ScriptableRendererFeature и ScriptableRenderPass на примере создания эффекта обводки непрозрачных объектов.
Для этого создадим ScriptableRendererFeature, выполняющую следующие действия:
И последовательность результатов, которые мы должны достичь:
В ходе работы мы создадим шейдер, в глобальные свойства которого будут сохраняться результаты первого и второго проходов. Последний проход отобразит результат работы самого шейдера на экран.
Это свойства, объявленные в шейдере, но не имеющие определения в блоке Properties. В данном примере нет принципиальной разницы как мы будем задавать текстуры — через глобальные или обычные свойства.
Основная причина использования глобальных свойств — нет необходимости передавать материал каждому проходу. А также отладка становится немного удобнее.
Создаём OutlineFeature
ScriptableRendererFeature используется для добавления своих проходов отрисовки (ScriptableRenderPass) в Universal RP. Создадим класс OutlineFeature, наследуемый от ScriptableRenderFeature и реализуем его методы.
Метод Create() служит для создания и настройки проходов. А метод AddRenderPasses() для внедрения созданных проходов в очередь отрисовки.
ScriptableRenderer — текущая стратегия рендеринга по умолчанию для Universal RP. На данный момент в Universal RP реализована только стратегия Forward Rendering.
RenderingData содержит данные для настройки проходов отрисовки — данные об отбраковке, камерах, освещении и прочем.
Теперь приступим к созданию проходов отрисовки, а к текущему классу будем возвращаться после реализации каждого из них.
Render Objects Pass
Задача этого прохода — отрисовывать объекты из определенного слоя с заменой материала в глобальное свойство-текстуру шейдера. Это будет упрощенная версия имеющегося в Universal RP прохода RenderObjectsPass, с единственным отличием в цели ( RenderTarget ), куда будет производится отрисовка.
Создадим класс MyRenderObjectsPass, наследуемый от ScriptableRenderPass. Реализуем метод Execute(), который будет содержать всю логику работы прохода, а так же переопределим метод Configure().
Метод Configure() используется для указания цели рендеринга и создания временных текстур. По умолчанию целью является цель текущей камеры и после выполнения прохода она вновь будет указана по умолчанию. Вызов этого метода осуществляется перед выполнение основой логики прохода.
Замена цели рендеринга
Объявим RenderTargetHandle для новой цели рендеринга. Используя его, создадим временную текстуру и укажем её как цель. RenderTargetHandle содержит в себе идентификатор используемой временной RenderTexture. А также позволяет получить RenderTargetIdentifier, служащий для идентификации цели рендеринга, которая может быть задана, например как объект RenderTexture, Texture, временная RenderTexture или встроенная (используется камерой при отрисовке кадра).
Объект RenderTargetHandle будет создаваться в OutlineFeature и передаваться нашему проходу при его создании.
Метод GetTemporaryRT() создаёт временную RenderTexture с заданными параметрами и устанавливает её как глобальное свойство шейдера с указанным именем (имя будет задаваться в фиче).
Для создания временной RenderTexture используем дескриптор текущей камеры, содержащий информацию о размере, формате и прочих параметрах цели камеры.
Указание цели и её очистка должны происходить только в Configure() с использованием методов ConfigureTarget() и ClearTarget().
Рендер
Подробно рассматривать отрисовку не будем, т.к. это может увести нас далеко и надолго от основной темы. Для отрисовки воспользуемся методом ScriptableRenderContext.DrawRenderers(). Создадим настройки для отрисовки только непрозрачных объектов только из указанных слоёв. Маску слоя будем передавать в конструктор.
Замена материала
Переопределим используемые материалы при отрисовке, так как нам нужны только контуры объектов.
Шейдер для отрисовки
Создадим в ShaderGraph шейдер материала, который будет использоваться при отрисовке объектов в текущем проходе.
Добавляем проход в OutlineFeature
Вернемся в OutlieFeature. Для начала создадим класс для настроек нашего прохода.
Объявим поля для настроек MyRenderPass и имени глобального свойства-текстуры, используемой в качестве цели рендеринга нашим проходом.
Создадим идентификатор для свойства-текстуры и экземпляр MyRenderPass.
В методе AddRendererPass добавляем наш проход в очередь на исполнение.
Результат прохода для исходной сцены должен получиться следующий:
Blur Pass
Цель этого прохода — размыть изображение, полученное на предыдущем шаге и установить его в глобальное свойство шейдера.
Для этого несколько раз будем копировать исходную текстуру во временные, с применением к ней шейдера размытия. При этом исходное изображение можно уменьшить в размерах (создать уменьшенную копию), что ускорит расчеты и не повлияет на качестве результата.
Создадим класс BlurPass, наследуемый от ScriptableRenderPass.
Заведём переменные под исходную, целевую и временные текстуры (и их ID).
Все ID для RenderTexture задаются через Shader.PropertyID(). Это не означает что где-то обязательно должны существовать такие свойства шейдера.
Добавим поля и под остальные параметры, которые сразу же инициализируем в конструкторе.
_blurMaterial — материал с шейдером размытия.
_downSample — коэффициент для уменьшения размера текстуры
_passesCount — количество проходов размытия, которое будет применено.
Для создания временных текстур создадим дескриптор со всей необходимой информацией о ней — размере, формате и прочем. Высоту и размер будем масштабировать относительно дескриптора камеры.
Также создадим идентификаторы и сами временные RenderTexture.
Мы снова меняем цель рендеринга, поэтому создадим ещё одну временную текстуру и укажем её как цель.
Размытие
Некоторые задачи рендеринга могут быть выполнены с помощью специальных методов ScriptableRenderContext, которые настраивают и добавляют в него команды. Для выполнения других команд потребуется использовать CommandBuffer, который можно получить из пула.
После добавления команд и отправки их на выполнение контексту, буфер нужно будет вернуть обратно в пул.
Конечная реализация метода Execute() будет следующей.
Шейдер
Для размытия создадим простой шейдер, который будет вычислять цвет пикселя с учётом его ближайших соседей ( среднее значение цвета пяти пикселей ).
Shader «Custom/Blur»
<
Properties
<
_MainTex («Texture», 2D) = «white» <>
>
struct Attributes
<
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
>;
struct Varyings
<
float4 positionCS : SV_POSITION;
float2 uv : TEXCOORD0;
>;
TEXTURE2D_X(_MainTex);
SAMPLER(sampler_MainTex);
float4 _MainTex_TexelSize;
Varyings Vert(Attributes input)
<
Varyings output;
output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
output.uv = input.uv;
return output;
>
half4 Frag(Varyings input) : SV_Target
<
float2 offset = _MainTex_TexelSize.xy;
float2 uv = UnityStereoTransformScreenSpaceTex(input.uv);
half4 color = SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, input.uv);
color += SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, input.uv + float2(-1, 1) * offset);
color += SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, input.uv + float2( 1, 1) * offset);
color += SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, input.uv + float2( 1,-1) * offset);
color += SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, input.uv + float2(-1,-1) * offset);
#pragma vertex Vert
#pragma fragment Frag
Добавляем проход в OutlineFeature
Порядок действия будет аналогичен добавлению нашего первого прохода. Сначала создадим настройки.
И добавим в очередь на выполнение.
Outline Pass
Конечное изображение с обводкой объектов будет получено с помощью шейдера. И результат его работы будет отображаться поверх текущего изображения на экране.
Ниже представлен сразу весь код прохода, т.к. вся логика заключена в двух строках.
RenderingUtils.fullscreenMesh возвращает меш размером 1 на 1.
Шейдер
Создадим шейдер для получения контура. Он должен содержать два глобальных свойства-текстуры. _OutlineRenderTexture и _OutlineBluredTexture для изображения указанных объектов и его размытого варианта.
Результат работы шейдера для для двух полученных ранее изображений:
Добавляем проход в OutlineFeature
Все действия аналогичны предыдущим проходам.
RenderPassEvent
Осталось указать когда будут вызываться созданные проходы. Для этого каждому из них нужно указать параметр renderPassEvent.
Создадим соответствующее поле в OutlineFeature.
И укажем его всем созданным проходам.
Настройка
Добавим слой Outline и установим его для объектов, которые хотим обвести.
Создадим и настроим все необходимые ассеты: UniversalRendererPipelineAsset и ForwardRendererData.
Результат
Результат для нашего исходного кадра будет следующим!
Доработка
Сейчас обводка объекта будет видна всегда, даже через другие объекты. Чтобы наш эффект учитывал глубину сцены нужно внести несколько изменений.
RenderObjectsPass
Указывая цель нашего рендера, мы должны также указать текущий буфер глубины. Создадим соответствующее поле и метод.
В методе Configure() укажем глубину в настройке цели рендера.
OutlineFeature
В OutlineFeature передадим MyRenderObjectsPass текущую глубину сцены.
UniversalRenderPipelineAsset
В используемом UniversalRenderPipelineAsset поставим галочку напротив пункта DepthTexture.
Результат
Результат без учета глубины:
Результат с учетом глубины:
ScriptableRendererFeature достаточно удобный инструмент для добавления своих проходов в RP.
В нем можно легко заменять RenderObjectsPass’ы и использовать их в других ScriptableRendererFeature. Не нужно сильно углубляться в реализацию Universal RP и менять его код, чтобы что-то добавить.
Для того чтобы общий алгоритм работы со ScriptableRendererFeature и ScriptableRenderPass был более понятен, и чтобы статья не сильно разрослась, я намеренно старался создавать код проходов простым, пусть даже в ущерб их универсальности и оптимальности.
Ссылки
Исходный код — ссылка на gitlab
Модели и сцена взяты из игры Lander Missions: planet depths
За основу примера была взята следующая реализация обводки — ссылка на youtube
Примеры реализации собственных RenderFeature от Unity — ссылка на github.
Серия уроков по созданию собственного ScriptableRenderPipeline. После прочтения становится ясна общая логика работы RP и шейдеров — ссылка на туториалы.
Universal render pipeline unity что это
The Universal Render Pipeline is a continuation of the LWRP, just with a new name. For creators, the transition from LWRP to Universal Render Pipeline should be relatively seamless. Projects that currently use the LWRP will upgrade to Universal Render Pipeline with very little intervention. Custom rendering effects and shaders written in LWRP will automatically upgrade to Universal Render Pipeline. You will have to manually upgrade shader paths only if you are using Shader.Find or UsePass in your custom shaders.
When upgrading to Universal Render Pipeline, you will also have to upgrade post-processing effects. Post-processing is now integrated directly into the pipeline; you do not need a separate package. We’ve improved the user experience, and it is more performant than PPv2. However, the post-processing does not currently support custom effects; we plan to add this support.
In the Universal Render Pipeline, post-processing features include Anti-aliasing, Depth of Field, Motion Blur, Panini projection, Bloom, Lens Distortion, Chromatic Aberration, Color Grading and Tonemapping, Vignette, Film Grain, and 8-bit Dithering.
Stay tuned for a detailed guide to upgrading the LWRP to URP.
Unity’s built-in render pipeline allowed developers to choose between forward and deferred rendering paths. Extensibility was achieved by injecting command buffers into specific events in the pipeline. However, it was not possible to add custom rendering strategies, and extending the existing ones was limited to a few injection points.
Universal Render Pipeline increases extensibility by introducing the concept of renderers. A renderer implements a set of features and lighting strategy.
In 2019.3, Universal Render Pipeline comes with a forward renderer that shades all lights in a single pass and a 2D renderer that supports multiple types or real-time lights. An optimized deferred renderer is coming soon.
When setting up a project, developers can now declare the list of renderers in the pipeline asset so that each camera can use a renderer from that list.
Developers can create their own renderers to extend the pipeline with additional rendering strategies such as Tile/Cluster-based rendering. By implementing a custom renderer for Universal Render Pipeline, instead of working on a custom rendering pipeline from scratch, the Universal Render Pipeline handles a lot of rendering boilerplate for you. Once a renderer is implemented, it’s all plug and play.
The development team behind Crest Ocean, which is available on the Asset Store, was able to extend the Universal Render Pipeline to create realistic oceans. Effects like this were hard to achieve before, but with explicit hooks, it’s now possible to extend rendering significantly without having to write a renderer from scratch.
Universal Render Pipeline is a leaner rendering solution than our previous built-in render pipeline, while also delivering improved quality. When upgrading a project from the built-in render pipeline to the Universal Render Pipeline, you should expect similar or improved performance.
We converted the Polygon Farm asset pack from the built-in render pipeline to Universal Render Pipeline and compared visuals and performance on an iPhone 6S. We tweaked both projects to make sure the quality and rendering settings matched. By using Universal Render Pipeline, we were able to achieve higher frame rates without reducing the visual quality.
If you convert a project and don’t get a performance improvement, the first thing to check is whether the quality settings between the two pipelines match. The Universal Render Pipeline controls all aspects of quality in the pipeline asset. The pipeline now supports setting a pipeline asset per quality setting. This way, you can scale quality between different platforms while centralizing all quality settings in the pipeline asset. This differs from the built-in renderer where the settings are scattered across Quality Settings and Graphics Tiers. When you convert a project to Universal Render Pipeline, the settings from your original project don’t get automatically upgraded. You must manually upgrade the quality settings.
If you have a case where the converted project matches quality, but you are experiencing worse performance with the Universal Render Pipeline, please submit a bug report.
We’re committed to evolving the Universal Render Pipeline. We want you to take advantage of features like VFX Graph, Shader Graph, Custom Render Passes, and the latest Post-Processing. The Universal Render Pipeline lets you develop once and deploy to a wide range of platforms while achieving the same or better quality and performance.
In 2020, we’re working towards feature parity with the Built-in renderer, including deferred renderer and camera stacking. You’ll be able to use the same set of features in your project, but not necessarily the same way.
While developing the Scriptable Render Pipeline, we took the time to redesign our rendering system. Some previous features will remain deprecated as we have developed better alternatives. Some examples of features that changed in Universal Render Pipeline are the rendering callbacks, grabpass, and camera stacking.
Besides evolving features, we are continually improving performance. Given the same quality settings, Universal Render Pipeline has equal or more performance than our previous rendering solution in most cases. Where that’s not the case, we’re treating those situations as regressions and processing them as bugs.
In 2021, we want to ensure that performance for all supported platforms is maintained while we grow the Universal Render Pipeline with features for high-end mobile and console platforms.
The Universal Render Pipeline does not replace or encompass the High Definition Render Pipeline (HDRP).
The Universal Render Pipeline aims to be the future default render pipeline for Unity. Develop once, deploy everywhere. It is more flexible, is more extensible and delivers higher performance than the built-in render pipeline, and has improved graphics quality.
HDRP delivers state-of-the-art graphics. HDRP is the best to use if your goal is more targeted – pushing graphics on high-end hardware, delivering performant powerful high-fidelity visuals.
You should choose the render pipeline to use for a project according to the features and platform requirements of your project.
You can start taking advantage of all the production-ready features and performance benefits today. Upgrade your projects using the upgrade tooling or start a new project using our Universal template from the Unity Hub.
Please send us feedback in the Universal Render Pipeline forum!