如何防止 Phaser 3 着色器随相机移动?

问题描述 投票:0回答:1

我在 Phaser 游戏中遇到着色器问题。我已将着色器应用为后期管道,希望它能够以水效果覆盖整个屏幕。但当我移动角色时,效果也会移动。这就像着色器粘在相机上而不是留在屏幕上。

我整理了一个快速演示,以便您明白我的意思。您可以使用箭头键四处移动并检查问题:https://phaser.io/sandbox/vFDT9xXy

这是相关的着色器代码:

const waterFragShader = `
#ifdef GL_ES
precision mediump float;
#endif

uniform float uTime;
uniform vec2 uResolution;
uniform sampler2D uMainSampler;

varying vec2 outTexCoord;

void main(void)
{
    vec2 uv = gl_FragCoord.xy / uResolution.xy;

    vec2 distortion = vec2(
      sin(uv.y * 10.0 + uTime) * 0.002,
      cos(uv.x * 10.0 + uTime) * 0.002
    );

    vec4 texture_color = texture2D(uMainSampler, uv + distortion);

    vec4 k = vec4(uTime)*0.6;
    k.xy = uv * 7.0;
    float val1 = length(0.5-fract(k.xyw*=mat3(vec3(-2.0,-1.0,0.0), vec3(3.0,-1.0,1.0), vec3(1.0,-1.0,-1.0))*0.5));
    float val2 = length(0.5-fract(k.xyw*=mat3(vec3(-2.0,-1.0,0.0), vec3(3.0,-1.0,1.0), vec3(1.0,-1.0,-1.0))*0.2));
    float val3 = length(0.5-fract(k.xyw*=mat3(vec3(-2.0,-1.0,0.0), vec3(3.0,-1.0,1.0), vec3(1.0,-1.0,-1.0))*0.5));

    float pattern = pow(min(min(val1,val2),val3), 7.0) * 2.0;
    vec4 pattern_color = vec4(1, 1, 1, pattern);
    vec4 color = vec4(pattern, pattern, pattern, pattern);

    gl_FragColor = mix(texture_color, pattern_color, pattern_color.a);
}
`;

class WaterPipeline extends Phaser.Renderer.WebGL.Pipelines
    .PostFXPipeline {
    constructor(game) {
        super({
            game,
            name: "Water",
            fragShader: waterFragShader,
        });
    }

    onPreRender() {
        this.set1f("uTime", this.game.loop.time / 1000);
    }

    onDraw(renderTarget) {
        this.set2f("uResolution", renderTarget.width, renderTarget.height);
        this.bindAndDraw(renderTarget);
    }
}

关于如何让这个着色器保持原样并覆盖整个屏幕,无论相机移动到哪里,有什么想法吗?

shader game-development phaser-framework phaserjs
1个回答
0
投票

我不是着色器专家,所以请对我的回答持保留态度。我最初会说不,这实际上不可能,因为失真是由当前图像生成的。

但是我记得你可以将变量传递到着色器中,所以如果你将玩家的位置作为偏移传递,扭曲似乎会移动。

简短演示:

(显示玩家偏移量;使用箭头键移动玩家=红色方块)

const waterFragShader = `
#ifdef GL_ES
precision mediump float;
#endif

uniform float uTime;
uniform vec2 uResolution;
uniform sampler2D uMainSampler;

varying vec2 outTexCoord;

// ADDED the OffSet Variable
uniform vec2 offSet; 

void main(void)
{
    vec2 uv = (gl_FragCoord.xy / uResolution.xy) + offSet ;

    vec2 distortion = vec2(
      sin(uv.y * 10.0 + uTime) * 0.002,
      cos(uv.x * 10.0 + uTime) * 0.002
    );

    vec4 texture_color = texture2D(uMainSampler, uv + distortion);

    vec4 k = vec4(uTime)*0.6;
    k.xy = uv * 7.0;
    float val1 = length(0.5-fract(k.xyw*=mat3(vec3(-2.0,-1.0,0.0), vec3(3.0,-1.0,1.0), vec3(1.0,-1.0,-1.0))*0.5));
    float val2 = length(0.5-fract(k.xyw*=mat3(vec3(-2.0,-1.0,0.0), vec3(3.0,-1.0,1.0), vec3(1.0,-1.0,-1.0))*0.2));
    float val3 = length(0.5-fract(k.xyw*=mat3(vec3(-2.0,-1.0,0.0), vec3(3.0,-1.0,1.0), vec3(1.0,-1.0,-1.0))*0.5));

    float pattern = pow(min(min(val1,val2),val3), 7.0) * 2.0;
    vec4 pattern_color = vec4(1, 1, 1, pattern + .2); // added .2 to make it more visible
    vec4 color = vec4(pattern, pattern, pattern, pattern);

    gl_FragColor = mix(texture_color, pattern_color, pattern_color.a);
}
`;

class WaterPipeline extends Phaser.Renderer.WebGL.Pipelines
    .PostFXPipeline {
    constructor(game) {
        super({
            game,
            name: "Water",
            fragShader: waterFragShader,
        });
        // Initialize the OffSet Variable
        this.offset = { x: 10, y: 10 };
    }

    setOffset(x,y){
        // Update OffSet Variable
        this.offset = { x, y};
    }

    onPreRender() {
        this.set1f("uTime", this.game.loop.time / 1000);
        // pass OffSet Variable to shader
        this.set2f("offSet", this.offset.x / 1000, this.offset.y/ 1000);
    }

    onDraw(renderTarget) {
        this.set2f("uResolution", renderTarget.width, renderTarget.height);
        this.bindAndDraw(renderTarget);
    }
}


class MainScene extends Phaser.Scene {

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

    create() {
        this.renderer.pipelines.addPostPipeline("Water", WaterPipeline);

        this.bg = this.add.rectangle(100, 100, 100, 100, 0x0000ff)
          .setPostPipeline("Water");

        this.player = this.add
            .rectangle(200, 100, 10, 10, 0xff0000)
            .setOrigin(0, 0);

        this.cameras.main.startFollow(this.player)
    }

    update() {
        const cursors = this.input.keyboard.createCursorKeys();
        if (cursors.left.isDown) {
            this.player.x -= 10;
        } else if (cursors.right.isDown) {
            this.player.x += 10;
        } else if (cursors.up.isDown) {
            this.player.y -= 10;
        } else if (cursors.down.isDown) {
            this.player.y += 10;
        }

        // Pass the players position
        this.bg.getPostPipeline("Water").setOffset(this.player.x, this.player.y)
    }

}

var config = {
    width: 540,
    height: 180,
    scene: [MainScene]
}; 

new Phaser.Game(config);

console.clear();
document.body.style = 'margin:0;';
<script src="//cdn.jsdelivr.net/npm/phaser/dist/phaser.min.js"></script>

可能有更好的方法,和/或着色器代码可能/将需要更多调整,但这是主要思想。

© www.soinside.com 2019 - 2024. All rights reserved.