带乒乓缓冲区的多步着色器中的条带问题在ShaderToy中不会发生

时间:2018-12-02 11:18:14

标签: opengl glsl webgl shader

我正在尝试实现一个Streak着色器,其描述如下: http://www.chrisoat.com/papers/Oat-SteerableStreakFilter.pdf

简短说明:在给定方向上采样具有1d内核的点。内核大小在每个步骤中呈指数增长。颜色值根据到采样点的距离加权并求和。结果是在该方向上具有平滑的尾部/拖尾/轻微条纹效果。这是碎片着色器:

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);
}

它将用于星空效果。这是在ShaderToy上实现良好的实现:

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

(注意:忽略Buffer A中的第一个着色器,由于afaik ShaderToy不允许上传自定义纹理,因此它只过滤掉输入纹理中的暗色以模拟星场)

但是当我在自己的代码中使用相同的着色器并使用乒乓FrameBuffers进行渲染时,它看起来就不同了。这是我自己的实现移植到WebGL:

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

我基本上创建了2个512x512缓冲区,根据算法在每次迭代中将着色器乒乓4倍增加内核大小,并在屏幕上呈现最终迭代。

问题是可见的条带,并且我的条纹/尾巴似乎更快地失去了亮度:(注意:图像有些不准确,条纹的长度相同/正确,其颜色值有误) problem

我在桌面OpenGl / LWJGL中已经为此苦苦挣扎了一段时间,我将其移植到WebGL / Javascript并上传到JSFiddle上,希望有人能发现问题所在。我怀疑这与纹理坐标或FrameBuffer配置有关,因为着色器完全相同。

1 个答案:

答案 0 :(得分:1)

之所以可以在Shadertoys上使用它,是因为它使用了浮点渲染目标。 只需使用gl.FLOAT作为帧缓冲区纹理的类型即可,问题已得到解决(我可以通过对JSFiddle进行上述修改来验证它)。

在您的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);