Переключение и определение активного рендерера

В PixiJS рендеринг управляется через объекты Renderer или Application, которые создают контекст WebGL или Canvas для отображения графики. Каждый рендерер отвечает за свой холст (canvas) и поддерживает собственный цикл обновления сцены. В крупных проектах может возникнуть необходимость иметь несколько рендереров и переключаться между ними в зависимости от условий (например, разные слои интерфейса или разные игровые сцены).

Создание и инициализация рендереров

Рендерер создаётся через конструктор PIXI.Renderer:

const renderer1 = new PIXI.Renderer({
    width: 800,
    height: 600,
    backgroundColor: 0x1099bb
});

const renderer2 = new PIXI.Renderer({
    width: 400,
    height: 300,
    backgroundColor: 0xffcc00
});

document.body.appendChild(renderer1.view);
document.body.appendChild(renderer2.view);

Ключевые моменты:

  • width и height определяют размеры холста.
  • backgroundColor задаёт цвет фона рендерера.
  • renderer.view — это HTML-элемент <canvas>, который вставляется в DOM.

Определение активного рендерера

В PixiJS нет встроенного глобального флага «активного рендерера», поэтому активный рендерер определяется вручную через переменную:

let activeRenderer = renderer1;

// Переключение рендерера
activeRenderer = renderer2;

Использование такой переменной позволяет централизованно управлять рендерингом сцены:

activeRenderer.render(stage);

Где stage — корневой контейнер PIXI.Container для объектов сцены.

Переключение рендереров в цикле анимации

При необходимости динамического переключения рендереров в анимации важно корректно управлять контекстом:

function animate() {
    requestAnimationFrame(animate);

    // Обновление сцены
    updateScene(stage);

    // Выбор рендерера на основе условий
    if (someCondition) {
        activeRenderer = renderer1;
    } else {
        activeRenderer = renderer2;
    }

    activeRenderer.render(stage);
}

animate();

Особенности:

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

Сценарии использования нескольких рендереров

  1. Разделение UI и игрового мира Один рендерер можно использовать для интерфейса, другой — для основного мира. Это облегчает работу с различными размерами холста и слоями.

  2. Разные разрешения для мобильных и десктопных версий Позволяет создавать отдельные рендереры с оптимизированными размерами и настройками производительности.

  3. Отдельные эффекты постобработки Один рендерер для базовой сцены, другой для эффектов, например, размытия или фильтров.

Работа с приложением PIXI.Application

Если используется PIXI.Application, активный рендерер можно получить через свойство app.renderer:

const app1 = new PIXI.Application({ width: 800, height: 600 });
const app2 = new PIXI.Application({ width: 400, height: 300 });

let activeApp = app1;

activeApp.renderer.render(stage);

// Переключение
activeApp = app2;
activeApp.renderer.render(stage);

Отличия от чистого Renderer:

  • PIXI.Application создаёт свой рендерер автоматически.
  • Управляет циклом анимации через app.ticker.
  • Позволяет легко добавлять контейнеры и интерактивные события.

Рекомендации по управлению активным рендерером

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

Практическая оптимизация

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

Итоговая структура управления

const renderers = [renderer1, renderer2];
let activeIndex = 0;

function switchRenderer() {
    activeIndex = (activeIndex + 1) % renderers.length;
}

function mainLoop() {
    requestAnimationFrame(mainLoop);

    updateScene(stage);

    renderers[activeIndex].render(stage);
}

mainLoop();

Такой подход обеспечивает простое и контролируемое переключение между рендерерами без конфликтов и потери производительности.