Применение шейдера к объекту и к камере

В Phaser 3 шейдеры реализуются через объект Pipeline и позволяют создавать уникальные визуальные эффекты как для отдельных объектов, так и для всей сцены. В основе лежит WebGL, что обеспечивает высокую производительность и гибкость.

Шейдер может быть применён к спрайту, группе спрайтов или к камере. При этом различают два подхода: использование фрагментных шейдеров (fragment shader) для изменения цвета и текстуры, и вершинных шейдеров (vertex shader) для трансформации геометрии объектов.

Создание кастомного шейдера

Phaser 3 позволяет создавать свои пайплайны на основе Phaser.Renderer.WebGL.Pipelines.SinglePipeline. Базовый пример шейдера:

class MyShaderPipeline extends Phaser.Renderer.WebGL.Pipelines.SinglePipeline {
    constructor(game) {
        super({
            game: game,
            fragShader: `
            precision mediump float;
            uniform sampler2D uMainSampler;
            varying vec2 outTexCoord;

            void main() {
                vec4 color = texture2D(uMainSampler, outTexCoord);
                color.rg = color.rg * 0.5 + 0.5; // корректировка красного и зелёного каналов
                gl_FragColor = color;
            }`
        });
    }
}

После создания пайплайна его необходимо зарегистрировать в сцене:

this.renderer.addPipeline('MyShader', new MyShaderPipeline(this.game));

Применение шейдера к объекту

Чтобы применить шейдер к спрайту:

let sprite = this.add.sprite(400, 300, 'myTexture');
sprite.setPipeline('MyShader');

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

  • Любой объект, поддерживающий WebGL, может использовать пайплайн.
  • Для групп объектов можно применять шейдер к контейнеру: шейдер влияет на все дочерние элементы.
  • Параметры шейдера (uniforms) можно изменять динамически:
let pipeline = this.renderer.getPipeline('MyShader');
pipeline.setFloat1('time', this.time.now / 1000);

Применение шейдера к камере

Шейдер, применённый к камере, воздействует на всю сцену, видимую через эту камеру. Это удобно для эффектов постобработки, таких как размытие, инверсия цветов или волны.

let camera = this.cameras.main;
camera.setRenderToTexture('MyShader');

При необходимости можно передавать в шейдер параметры камеры:

camera.setRenderToTexture({
    pipeline: 'MyShader',
    clear: true,
    uniforms: {
        time: 0
    }
});

Динамическое обновление:

camera.pipeline.setFloat1('time', this.time.now / 1000);

Использование uniform-переменных

Uniform-переменные позволяют управлять поведением шейдера из JavaScript. Обычно используют:

  • float — одиночное число
  • vec2, vec3, vec4 — векторы
  • sampler2D — текстуры

Пример управления волновым эффектом:

pipeline.setFloat1('amplitude', 0.05);
pipeline.setFloat1('frequency', 10.0);

В шейдере это применяется для смещения текстуры:

vec2 uv = outTexCoord;
uv.y += sin(uv.x * frequency + time) * amplitude;
gl_FragColor = texture2D(uMainSampler, uv);

Комбинирование шейдеров

Phaser позволяет использовать несколько шейдеров одновременно:

  • Для объектов можно устанавливать разные пайплайны по отдельности.
  • Для камеры можно комбинировать эффекты через Render Texture: сначала рендер сцены в текстуру, затем применить второй шейдер.
let rt = this.add.renderTexture(0, 0, 800, 600);
rt.draw(this.add.sprite(400, 300, 'myTexture'));
rt.setPipeline('MyShader');

Оптимизация производительности

  • Минимизировать количество уникальных пайплайнов. Лучше один пайплайн для группы объектов.
  • Использовать шейдеры только там, где это необходимо.
  • Для эффектов камеры предпочтительно использовать Render Texture, чтобы шейдер обрабатывал сразу весь кадр, а не каждый объект по отдельности.

Взаимодействие с таймером и анимациями

Шейдеры часто используют время как uniform для создания анимации. В Phaser есть удобный источник времени:

this.time.addEvent({
    loop: true,
    callback: () => {
        pipeline.setFloat1('time', this.time.now / 1000);
    }
});

Так можно реализовать эффекты пульсации, волны, мерцания или цветовые переходы.

Работа с текстурами и альфа-каналом

При применении шейдера важно учитывать прозрачность. Phaser сохраняет альфа-канал объектов:

vec4 color = texture2D(uMainSampler, outTexCoord);
color.rgb *= 0.5; // затемнение
gl_FragColor = vec4(color.rgb, color.a); // сохраняем прозрачность

Это позволяет совмещать шейдеры с наложением спрайтов и эффектами частиц.

Практические примеры

  1. Эффект “старого телевизора” для камеры: шум, размытые полосы, инверсия цвета.
  2. Подсветка объекта при наведении: шейдер изменяет яркость или контраст.
  3. Динамическая вода или волны: смещение текстур спрайтов с помощью синусоидальных функций и времени.

Шейдеры в Phaser обеспечивают гибкий инструмент для создания уникальной визуальной атмосферы и интерактивных эффектов без существенной потери производительности. Их использование позволяет реализовать эффекты, которые сложно добиться стандартными средствами спрайтов и камер.