Создание собственного конвейера рендеринга для мобильных устройств

Раздел:
Программирование
Unity, одна из ведущих платформ для разработки игр и приложений, предоставляет разработчикам гибкие инструменты для создания графики высокого качества.
Scriptable Render Pipeline (SRP) — это мощный механизм, который позволяет настраивать процесс рендеринга в Unity для достижения конкретных целей визуализации. Одно из общих применений SRP — это оптимизация производительности рендеринга для мобильных устройств. В последней статье мы более подробно рассмотрели, как работает рендеринг в Unity и практику оптимизации GPU.
В этой статье мы рассмотрим создание собственного Scriptable Render Pipeline, оптимизированного для мобильных устройств на платформе Unity. Мы погрузимся в основы работы с SRP, разработаем базовый пример и рассмотрим техники оптимизации для обеспечения высокой производительности на мобильных устройствах.

Введение в Scriptable Render Pipeline

Scriptable Render Pipeline (SRP) в Unity — это мощный инструмент, который позволяет разработчикам настраивать процесс рендеринга для достижения конкретных целей. Это модульная система, которая разделяет рендеринг на отдельные шаги, такие как рендеринг геометрии, освещения, эффектов и т. д. Это дает вам гибкость и контроль над вашим рендерингом, позволяя оптимизировать его для различных платформ и улучшать визуальное качество.
В основном SRP включает несколько предопределенных типов:
  • Built-in Render Pipeline (BRP): Это стандартный встроенный рендеринговый конвейер Unity. Он обеспечивает хорошее сочетание производительности и качества графики, но может быть недостаточно эффективным для мобильных устройств.
  • Universal Render Pipeline (URP): Этот конвейер предоставляет оптимизированное решение для большинства платформ, включая мобильные устройства. Он обеспечивает хорошее сочетание производительности и качества, но может потребовать дополнительной настройки для максимальной оптимизации для конкретных устройств.
  • High Definition Render Pipeline (HDRP): HDRP предназначен для создания высококачественных визуальных эффектов, таких как фотореалистичная графика, физически корректное освещение и т. д. Он требует больших вычислительных ресурсов и может быть неэффективным на мобильных устройствах, но хорош для ПК и консолей.
Создание собственного Scriptable Render Pipeline позволяет разработчикам создавать настраиваемые решения, оптимизированные для конкретных требований проекта и целевых платформ.

Планирование и проектирование SRP для мобильных устройств

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

Определение целей

Первый шаг — это определение целей нашего SRP для мобильных устройств. Некоторые из общих целей могут включать:
  • Высокая производительность: Обеспечение плавного и стабильного времени кадра на мобильных устройствах.
  • Эффективное использование ресурсов: Минимизация использования памяти и ЦП для максимизации производительности.
  • Хорошее качество графики: Предоставление приемлемого визуального качества с учетом ограничений мобильных устройств.

Архитектура и компоненты

Далее мы должны определить архитектуру и компоненты нашего SRP. Некоторые из ключевых компонентов могут включать:
  • Renderer (Рендерер): Основной компонент, ответственный за рендеринг сцены. Мы можем оптимизировать его для мобильных устройств, учитывая их характеристики.
  • Lighting (Освещение): Управляет освещением сцены, включая динамическое и статическое освещение.
  • Shading (Теневое отображение): Реализация различных техник затенения для достижения желаемого визуального стиля.
  • Post-processing (Постобработка): Применение постобработки к полученному изображению для улучшения его качества.

Оптимизация для мобильных устройств

Наконец, мы должны подумать об оптимизационных техниках, которые помогут нам достичь высокой производительности на мобильных устройствах. Некоторые из них включают:
  • Уменьшение количества отрендеренных объектов: Использование техник, таких как Level of Detail (LOD) и Frustum Culling, для снижения нагрузки на GPU.
  • Оптимизация шейдеров: Использование простых и эффективных шейдеров с минимальным количеством проходов.
  • Оптимизация освещения: Использование предварительно рассчитанного освещения и техник, таких как Light Probes, для снижения вычислительной нагрузки.
  • Управление памятью: Эффективное использование текстур и буферов для минимизации использования памяти.

Создание базового примера SRP для мобильных устройств

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

Шаг 1: Настройка проекта

Давайте начнем с создания нового проекта Unity и выбора настроек, оптимизированных для мобильных устройств. Мы также можем использовать Universal Render Pipeline (URP) в качестве основы для нашего SRP, так как он обеспечивает хорошую основу для достижения сочетания производительности и качества графики для мобильных устройств.

Шаг 2: Создание Рендерера

Давайте создадим основной компонент - Рендерер, который будет отвечать за отображение сцены. Мы можем начать с простого Рендерера, поддерживающего основные функции рендеринга, такие как рендеринг геометрии и применение материалов.
using UnityEngine;
using UnityEngine.Rendering;

// Наш Мобильный Рендерер
public class MobileRenderer : ScriptableRenderer
{
    public MobileRenderer(ScriptableRendererData data) : base(data) {}

    public override void Setup(ScriptableRenderContext context, ref RenderingData renderingData)
    {
        base.Setup(context, ref renderingData);
    }

    public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    {
        base.Execute(context, ref renderingData);
    }
}

Шаг 3: Настройка Освещения

Добавим поддержку освещения в наш Рендерер. Мы можем использовать простой подход на основе одного источника направленного света, который обеспечит приемлемое качество освещения с минимальной нагрузкой на GPU.
using UnityEngine;
using UnityEngine.Rendering;

public class MobileRenderer : ScriptableRenderer
{
    public Light mainLight;

    public MobileRenderer(ScriptableRendererData data) : base(data) {}

    public override void Setup(ScriptableRenderContext context, ref RenderingData renderingData)
    {
        base.Setup(context, ref renderingData);
    }

    public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    {
        base.Execute(context, ref renderingData);

        ConfigureLights();
    }

    void ConfigureLights()
    {
        CommandBuffer cmd = CommandBufferPool.Get("Setup Lights");
        if (mainLight != null && mainLight.isActiveAndEnabled)
        {
            cmd.SetGlobalVector("_MainLightDirection", -mainLight.transform.forward);
            cmd.SetGlobalColor("_MainLightColor", mainLight.color);
        }
        context.ExecuteCommandBuffer(cmd);
        CommandBufferPool.Release(cmd);
    }
}

Шаг 4: Применение Пост-обработки

Наконец, добавим поддержку пост-обработки для улучшения качества получаемого изображения.
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

public class MobileRenderer : ScriptableRenderer
{
    public Light mainLight;
    public PostProcessVolume postProcessVolume;

    public MobileRenderer(ScriptableRendererData data) : base(data) {}

    public override void Setup(ScriptableRenderContext context, ref RenderingData renderingData)
    {
        base.Setup(context, ref renderingData);
    }

    public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    {
        base.Execute(context, ref renderingData);

        ConfigureLights();
        ApplyPostProcessing(context, renderingData.cameraData.camera);
    }

    void ConfigureLights()
    {
        CommandBuffer cmd = CommandBufferPool.Get("Setup Lights");
        if (mainLight != null && mainLight.isActiveAndEnabled)
        {
            cmd.SetGlobalVector("_MainLightDirection", -mainLight.transform.forward);
            cmd.SetGlobalColor("_MainLightColor", mainLight.color);
        }
        context.ExecuteCommandBuffer(cmd);
        CommandBufferPool.Release(cmd);
    }

    void ApplyPostProcessing(ScriptableRenderContext context, Camera camera)
    {
        if (postProcessVolume != null)
        {
            postProcessVolume.sharedProfile.TryGetSettings(out Bloom bloom);
            if (bloom != null)
            {
                CommandBuffer cmd = CommandBufferPool.Get("Apply Bloom");
                cmd.Blit(cameraColorTarget, cameraColorTarget, bloom);
                context.ExecuteCommandBuffer(cmd);
                CommandBufferPool.Release(cmd);
            }
        }
    }
}
Таким образом, мы создали основной цикл с рендерингом, освещением и пост-обработкой. Затем вы можете использовать другие компоненты для настройки производительности вашего SRP.

Оптимизация и Тестирование

После завершения основного примера мы можем начать оптимизацию и тестирование нашего SRP для мобильных устройств. Мы можем использовать инструменты профилирования Unity для выявления проблемных мест и оптимизации производительности.
Примеры оптимизаций:
  • Сокращение полигонов: Используйте оптимизированные модели и техники LOD для уменьшения количества отображаемых полигонов. Сохраняйте количество вершин ниже 200K и 3M в кадре при сборке для ПК (в зависимости от целевого GPU);
  • Упрощение шейдеров: Используйте простые и эффективные шейдеры с минимальным количеством проходов. Минимизируйте использование сложных математических операций, таких как pow, sin и cos в пиксельных шейдерах;
  • Оптимизация текстур: Используйте сжатие текстур и уменьшите разрешение текстур для экономии памяти. Объединяйте текстуры с помощью атласов;
  • Профилирование и оптимизация: Используйте инструменты профилирования Unity для выявления проблемных мест и оптимизации производительности.

Тестирование на Мобильных Устройствах

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

Заключение

Создание собственного Scriptable Render Pipeline для мобильных устройств на платформе Unity - мощный способ оптимизации производительности рендеринга и улучшения визуального качества вашей игры или приложения. Правильное планирование, дизайн и оптимизация могут помочь вам достичь желаемых результатов и обеспечить отличный опыт для пользователей мобильных устройств.
И, конечно, спасибо за прочтение статьи, буду рад обсудить с вами различные аспекты оптимизации.