Can't get a "Hello World" custom shader to work

Title. I made a super basic custom shader:

import 'phaser';

export class TestShader extends Phaser.Renderer.WebGL.Pipelines.PostFXPipeline {
    constructor(game: Phaser.Game)
    {
        super({
            game, 
            fragShader: `
                #DEFINE SHADER_NAME TEST_SHADER

                #ifdef GL_ES
                precision medimp float;
                #endif

                varying vec2 outTextCoord;
                uniform sampler2D uMainSampler;

                void main() {
                    gl_FragColor = vec4(1.0, 0.4, 0.723, 1.0);
                }`
        });
    }
}

and use it in a super basic way:

this.cameras.main.setPostPipeline(new TestShader(this.game));

and yet I still see no difference in my scene. Any idea what is going wrong? I literally can’t simplify this any further to test it.

For the shader, you will first need to add this new pipeline to the renderer like so:

this.renderer.pipelines.addPostPipeline('TestShader', TestShader);

This will make the pipeline available for you to use on the main camera.

Example: Shader example Phaser Sandbox Entry (v3.87)

class TestShader extends Phaser.Renderer.WebGL.Pipelines.PostFXPipeline {
    constructor(game)
    {
        super({
            game, 
            fragShader: `
                #define SHADER_NAME TEST_SHADER

                #ifdef GL_ES
                precision mediump float;
                #endif

                varying vec2 outTextCoord;
                uniform sampler2D uMainSampler;

                void main() {
                    gl_FragColor = vec4(1.0, 0.4, 0.723, 1.0);
                }`
        });
    }
}

class MainScene extends Phaser.Scene {

    constructor() {
        super({ key: "MainScene" });
    }

    preload() {
        this.load.image("earth", "https://cdn.phaser.io/sandbox/square-earth.png");
    }

    create() {
        this.earth = this.add.image(150, 150, "earth");
        this.renderer.pipelines.addPostPipeline('TestShader', TestShader);
        this.cameras.main.setPostPipeline('TestShader');
    }
}
2 Likes

Thanks for the response! Also, do you know how this works for PreFX shaders? (They seem to be set up slightly different…)

1 Like

For PreFX, we still need to add the pipeline to the renderer, but instead of adding the pipeline to the main camera, we would attach this to a game object.

The two main lines of code are:

        this.renderer.pipelines.add('TestShader', new TestShader(this.game));
        yourGameObject.setPipeline('TestShader');

Working example can be seen here: Shader example - PreFXPipeline Phaser Sandbox Entry (v3.87)

class TestShader extends Phaser.Renderer.WebGL.Pipelines.PreFXPipeline {
    constructor(game)
    {
        super({
            game, 
            fragShader: `
                #define SHADER_NAME TEST_SHADER

                #ifdef GL_ES
                precision mediump float;
                #endif

                varying vec2 outTextCoord;
                uniform sampler2D uMainSampler;

                void main() {
                    gl_FragColor = vec4(1.0, 0.4, 0.723, 1.0);
                }`
        });
    }
}

class MainScene extends Phaser.Scene {

    constructor() {
        super({ key: "MainScene" });
    }

    preload() {
        this.load.image("earth", "https://cdn.phaser.io/sandbox/square-earth.png");
    }

    create() {
        this.earth = this.add.image(this.scale.width / 2, this.scale.height / 2, "earth");
        this.renderer.pipelines.add('TestShader', new TestShader(this.game));
        this.earth.setPipeline('TestShader');
    }

}
2 Likes