sydnal
sydnal

Reputation: 317

Banding Problem in Multi Step Shader with Ping Pong Buffers, does not happen in ShaderToy

I am trying to implement a Streak shader, which is described here: http://www.chrisoat.com/papers/Oat-SteerableStreakFilter.pdf

Short explanation: Samples a point with a 1d kernel in a given direction. The kernel size grows exponentially in each step. Color values are weighted based on distance to sampled point and summed. The result is a smooth tail/smear/light streak effect on that direction. Here is the frag shader:

precision highp float;

uniform sampler2D u_texture;

varying vec2 v_texCoord;

uniform float u_Pass;

const float kernelSize = 4.0;
const float atten = 0.95;

vec4 streak(in float pass, in vec2 texCoord, in vec2 dir, in vec2 pixelStep) {

    float kernelStep = pow(kernelSize, pass - 1.0);

    vec4 color = vec4(0.0);

    for(int i = 0; i < 4; i++) {
        float sampleNum = float(i);

        float weight = pow(atten, kernelStep * sampleNum);

        vec2 sampleTexCoord = texCoord + ((sampleNum * kernelStep) * (dir * pixelStep));
        vec4 texColor = texture2D(u_texture, sampleTexCoord) * weight;
        color += texColor;

    }
    return color;
}


void main() {
    vec2 iResolution = vec2(512.0, 512.0);

    vec2 pixelStep = vec2(1.0, 1.0) / iResolution.xy;

    vec2 dir = vec2(1.0, 0.0);

    float pass = u_Pass;

    vec4 streakColor = streak(pass, v_texCoord, dir, pixelStep);

    gl_FragColor = vec4(streakColor.rgb, 1.0);
}

It was going to be used for a starfield type of effect. And here is the implementation on ShaderToy which works fine:

https://www.shadertoy.com/view/ll2BRG

(Note: Disregard the first shader in Buffer A, it just filters out the dim colors in the input texture to emulate a star field since afaik ShaderToy doesn't allow uploading custom textures)

But when I use the same shader in my own code and render using ping-pong FrameBuffers, it looks different. Here is my own implementation ported over to WebGL:

https://jsfiddle.net/1b68eLdr/87755/

I basically create 2 512x512 buffers, ping-pong the shader 4 times increasing kernel size at each iteration according to the algorithm and render the final iteration on the screen.

The problem is visible banding, and my streaks/tails seem to be losing brightness a lot faster: (Note: the image is somewhat inaccurate, the lengths of the streaks are same/correct, its color values that are wrong) problem

I have been struggling with this for a while in Desktop OpenGl / LWJGL, I ported it over to WebGL/Javascript and uploaded on JSFiddle in hopes someone can spot what the problem is. I suspect it's either about texture coordinates or FrameBuffer configuration since shaders are exactly the same.

Upvotes: 0

Views: 591

Answers (1)

httpdigest
httpdigest

Reputation: 5797

The reason it works on Shadertoys is because it uses a floating-point render target. Simply use gl.FLOAT as the type of your framebuffer texture and the issue is fixed (I could verify it with the said modification on your JSFiddle).

So do this in your createBackingTexture():

// Just request the extension (MUST be done).
gl.getExtension('OES_texture_float');
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this._width, this._height, 0, gl.RGBA, gl.FLOAT, null);

Upvotes: 1

Related Questions