Phaser3 : Pipelineを使う

今回はカスタムパイプラインを使ってスプライトにシェーダを適応してみます。

カスタムパイプラインを宣言する

こちらのサンプルなどでカスタムパイプラインが使われていますが、typescriptではだいぶ書き方が違うようです。
まずはパイプライン用のオブジェクトを準備します。

public pipeline: Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline;

new Phaser.Renderer.WebGL.Pipelines.TextureTintPipelineでパイプラインオブジェクトを作成します。
gameにthis.game、rendererにthis.game.rendererをわたし、fragShaderにシェーダの実装を書きます。

//パイプラインを作成する
this.pipeline= new Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline({
    game: this.game,
    renderer: this.game.renderer,
    fragShader: [
        "precision mediump float;",

        "uniform float     time;",
        "uniform vec2      resolution;",
        "uniform sampler2D uMainSampler;",
        "varying vec2 outTexCoord;",

        "void main( void ) {",

        "vec2 uv = outTexCoord;",
        "//uv.y *= -1.0;",
        "uv.y += (sin((uv.x + (time * 0.5)) * 10.0) * 0.1) + (sin((uv.x + (time * 0.2)) * 32.0) * 0.01);",
        "vec4 texColor = texture2D(uMainSampler, uv);",
        "gl_FragColor = texColor;",

        "}"
    ].join('\n')
           
});


次にrendererにカスタムパイプラインを追加します。
rendererはPhaser.Renderer.Canvas.CanvasRendererとPhaser.Renderer.WebGL.WebGLRendererの共有型なのですが、Phaser.Renderer.Canvas.CanvasRendererにはaddpipeline関数がないようで、Phaser.Renderer.WebGL.WebGLRendererにキャストしなければなりませんでした。

setFloat2でパイプラインの初期値を設定し、スプライトにパイプラインを適応します。
スプライトはこちらのlayer9を使用しました。

edermunizz.itch.io

//rendererにカスタムパイプラインを登録する
(this.game.renderer as Phaser.Renderer.WebGL.WebGLRenderer).addPipeline("custom", this.pipeline)

//シェーダの値を設定する
this.pipeline.setFloat2('uResolution', this.game.config.width as number, this.game.config.height as number);

let forest = this.add.sprite(this.sys.canvas.width / 2, 200, "forest");

//スプライトにパイプラインを設定する
forest.setPipeline("custom");

最後にupdateでパイプラインのtimeを変動させます。

update() {
    this.pipeline.setFloat1('time', this.t);

    this.t += 0.005
}

実行結果がこちらです。 f:id:Phaser_3:20190118152154g:plain 波打つようなエフェクトが適応されています。
今回のソースはこちらです。

/// <reference path="../app.ts" />

namespace MyGame {



    export class MyScene1 extends Phaser.Scene {

        public pipeline: Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline;
        public t: number = 0;
        constructor() {
            super({ key: 'MyScene1', active: false });
        }

        preload() {
            //ノーマルマップ
            this.load.image("rect", "assets/images/rect3.png");
            this.load.image("forest", "assets/images/Layer_0000_9.png");
        }

        create() {

            //パイプラインを作成する
            this.pipeline= new Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline({
                game: this.game,
                renderer: this.game.renderer,
                fragShader: [
                    "precision mediump float;",

                    "uniform float     time;",
                    "uniform vec2      resolution;",
                    "uniform sampler2D uMainSampler;",
                    "varying vec2 outTexCoord;",

                    "void main( void ) {",

                    "vec2 uv = outTexCoord;",
                    "//uv.y *= -1.0;",
                    "uv.y += (sin((uv.x + (time * 0.5)) * 10.0) * 0.1) + (sin((uv.x + (time * 0.2)) * 32.0) * 0.01);",
                    "vec4 texColor = texture2D(uMainSampler, uv);",
                    "gl_FragColor = texColor;",

                    "}"
                ].join('\n')
            

            });

            //シェーダの値を設定する
            this.pipeline.setFloat2('uResolution', this.game.config.width as number, this.game.config.height as number);
             
            //rendererにカスタムパイプラインを登録する
            (this.game.renderer as Phaser.Renderer.WebGL.WebGLRenderer).addPipeline("custom", this.pipeline)

            let forest = this.add.sprite(this.sys.canvas.width / 2, 200, "forest");

            //スプライトにパイプラインを設定する
            forest.setPipeline("custom");

        }

        update() {
            this.pipeline.setFloat1('time', this.t);

            this.t += 0.005
        }
    }
}