Problem recreating shader

I’m trying to recreate the following shader from shadertoy using Phaser 3:

I managed to fix the errors I was getting but it just loads an empty black square when trying to load it on my scene. Here’s a sample code:

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

uniform float time;
uniform vec2 resolution;
uniform sampler2D iChannel0;
uniform sampler2D iChannel1;
uniform sampler2D iChannel2;

varying vec2 fragCoord;

float avg(vec4 color) {
    return (color.r + color.g + color.b)/3.0;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // Flow Speed, increase to make the water flow faster.
    float speed = 1.0;
    
    // Water Scale, scales the water, not the background.
    float scale = 0.8;
    
    // Water opacity, higher opacity means the water reflects more light.
    float opacity = 0.5;
 
    // Normalized pixel coordinates (from 0 to 1)
    vec2 uv = (fragCoord/resolution.xy);
    vec2 scaledUv = uv*scale;

    // Water layers, layered on top of eachother to produce the reflective effect
    // Add 0.1 to both uv vectors to avoid the layers stacking perfectly and creating a huge unnatural highlight
    vec4 water1 = texture2D(iChannel0, scaledUv + time*0.02*speed - 0.1);
    vec4 water2 = texture2D(iChannel0, scaledUv.xy + time*speed*vec2(-0.02, -0.02) + 0.1);
    
    // Water highlights
    vec4 highlights1 = texture2D(iChannel2, scaledUv.xy + time*speed / vec2(-10, 100));
    vec4 highlights2 = texture2D(iChannel2, scaledUv.xy + time*speed / vec2(10, 100));
    
    // Background image
    vec4 background = texture2D(iChannel1, vec2(uv) + avg(water1) * 0.05);
    
    // Average the colors of the water layers (convert from 1 channel to 4 channel
    water1.rgb = vec3(avg(water1));
    water2.rgb = vec3(avg(water2));
    
    // Average and smooth the colors of the highlight layers
    highlights1.rgb = vec3(avg(highlights1)/1.5);
    highlights2.rgb = vec3(avg(highlights2)/1.5);
    
    float alpha = opacity;
    
    if(avg(water1 + water2) > 0.3) {
        alpha = 0.0;
    }
    
    if(avg(water1 + water2 + highlights1 + highlights2) > 0.75) {
        alpha = 5.0 * opacity;
    }

    // Output to screen
    fragColor = (water1 + water2) * alpha + background;
}

void main(void)
{
    mainImage(gl_FragColor, fragCoord.xy);
    gl_FragColor.a = 1.0;
}
`;

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

  preload() {
    this.load.image("noise", "https://i.imgur.com/pZfKeRP.png");
    this.load.image("pic", "https://i.imgur.com/NQFMq6r.jpg");
    this.load.image("rocks", "https://i.imgur.com/fvHGrrU.png");
  }

  create() {
    const baseShader = new Phaser.Display.BaseShader(
      "BufferShader",
      fragmentShader
    );
    this.add
      .shader(baseShader, 0, 0, 800, 600, ["noise", "pic", "rocks"])
      .setOrigin(0, 0);
  }
}

const config = {
  type: Phaser.WEBGL,
  parent: "phaser-example",
  width: 800,
  height: 600,
  scene: Example
};

const game = new Phaser.Game(config);

Is there anything I’m doing wrong? Here’s the same sample codepen so you can see the problem.

Thanks.

1 Like

Hi @jahvi ,
You need to use POT (power of two) textures (64x64, 128x128, 512x512, 1024x1024, …).

Thanks but still no luck after resizing the images to 64x64:

My bad, I was using the wrong image sizes again. Thanks!

1 Like