Custom Filter

Demonstrates how to create and apply a custom GLSL fragment shader filter to a Game Object, using a Filter Controller to manage uniforms like time and speed.

Custom Filter, running
800 × 600
GitHub
const hueFragShader = `
#define SHADER_NAME HUE_FS

precision mediump float;

uniform sampler2D uMainSampler;
uniform float uTime;
uniform float uSpeed;

varying vec2 outTexCoord;
varying float outTexId;
varying vec4 outTint;
varying vec2 fragCoord;

void main()
{
    vec4 texture = texture2D(uMainSampler, outTexCoord);

    float c = cos(uTime * uSpeed);
    float s = sin(uTime * uSpeed);

    mat4 r = mat4(0.299, 0.587, 0.114, 0.0, 0.299, 0.587, 0.114, 0.0, 0.299, 0.587, 0.114, 0.0, 0.0,  0.0, 0.0, 1.0);
    mat4 g = mat4(0.701, -0.587, -0.114, 0.0, -0.299, 0.413, -0.114, 0.0, -0.300, -0.588, 0.886, 0.0, 0.0, 0.0, 0.0, 0.0);
    mat4 b = mat4(0.168, 0.330, -0.497, 0.0, -0.328, 0.035, 0.292, 0.0, 1.250, -1.050, -0.203, 0.0, 0.0, 0.0, 0.0, 0.0);

    mat4 hueRotation = r + g * c + b * s;

    gl_FragColor = texture * hueRotation;
}
`;

const FILTER_NAME = 'FilterColor';

const FilterColor = {
    Controller: class ControllerColor extends Phaser.Filters.Controller {
        constructor(camera) {
            super(camera, FILTER_NAME);
            this.hueSpeed = 0.001;
        }
        setHueSpeed(speed = 0.001) {
            this.hueSpeed = speed;
            return this;
        }
    },
    Filter: class FilterColor extends Phaser.Renderer.WebGL.RenderNodes.BaseFilterShader {
        constructor(manager) {
            super(FILTER_NAME, manager, null, hueFragShader);
        }
        setupUniforms(controller, drawingContext) {
            const programManager = this.programManager;
            programManager.setUniform('uTime', drawingContext.renderer.game.loop.time);
            programManager.setUniform('uSpeed', controller.hueSpeed);
        }
    }
};

class Example extends Phaser.Scene
{
    constructor ()
    {
        super();
    }

    preload ()
    {
        this.load.setBaseURL('https://cdn.phaserfiles.com/v410');
        this.load.image('fish', 'assets/tests/pipeline/fish.png');
        this.load.image('flower', 'assets/tests/pipeline/flower.png');
    }

    create ()
    {
        this.add.sprite(200, 300, 'fish');
        this.filterController = new FilterColor.Controller();
        const flower = this.add.sprite(400, 300, 'flower').enableFilters().filters.internal.add(this.filterController);
        this.add.sprite(600, 300, 'fish');
        this.input.on('pointerdown', () => {
            this.filterController.setHueSpeed(0.001 + Math.random() * 0.01);
        });
    }
}

const config = {
    scale: { mode: Phaser.Scale.FIT },
    type: Phaser.WEBGL,
    width: 800,
    height: 600,
    backgroundColor: '#0a0067',
    parent: 'game-container',
    scene: Example,
    renderNodes: { 'FilterColor': FilterColor.Filter }
};

let game = new Phaser.Game(config);

More in Renderer14 examples