带有 Ping Pong 缓冲区的多步着色器中的条带问题在 ShaderToy 中不会发生
Banding Problem in Multi Step Shader with Ping Pong Buffers, does not happen in ShaderToy
我正在尝试实现 Streak 着色器,如下所述:
http://www.chrisoat.com/papers/Oat-SteerableStreakFilter.pdf
简短说明:在给定方向上使用一维内核对点进行采样。内核大小在每一步中呈指数增长。颜色值根据到采样点的距离进行加权并求和。结果是在该方向上出现平滑的 tail/smear/light 条纹效果。这是片段着色器:
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
(注意:忽略缓冲区 A 中的第一个着色器,它只是过滤掉输入纹理中的暗淡颜色以模拟星空,因为 afaik ShaderToy 不允许上传自定义纹理)
但是当我在自己的代码中使用相同的着色器并使用 ping-pong FrameBuffers 进行渲染时,它看起来不一样了。这是我自己移植到 WebGL 的实现:
https://jsfiddle.net/1b68eLdr/87755/
我基本上创建了 2 个 512x512 缓冲区,ping-pong 着色器在每次迭代时根据算法将内核大小增加 4 倍,并在屏幕上渲染最终迭代。
问题是明显的条带,我的 streaks/tails 似乎亮度下降得更快:(注意:图像有些不准确,条带的长度是 same/correct,它的颜色错误的价值观)
我在 Desktop OpenGl / LWJGL 中为此苦苦挣扎了一段时间,我将其移植到 WebGL/Javascript 并上传到 JSFiddle,希望有人能发现问题所在。我怀疑它与纹理坐标或 FrameBuffer 配置有关,因为着色器完全相同。
它在 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);
我正在尝试实现 Streak 着色器,如下所述: http://www.chrisoat.com/papers/Oat-SteerableStreakFilter.pdf
简短说明:在给定方向上使用一维内核对点进行采样。内核大小在每一步中呈指数增长。颜色值根据到采样点的距离进行加权并求和。结果是在该方向上出现平滑的 tail/smear/light 条纹效果。这是片段着色器:
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
(注意:忽略缓冲区 A 中的第一个着色器,它只是过滤掉输入纹理中的暗淡颜色以模拟星空,因为 afaik ShaderToy 不允许上传自定义纹理)
但是当我在自己的代码中使用相同的着色器并使用 ping-pong FrameBuffers 进行渲染时,它看起来不一样了。这是我自己移植到 WebGL 的实现:
https://jsfiddle.net/1b68eLdr/87755/
我基本上创建了 2 个 512x512 缓冲区,ping-pong 着色器在每次迭代时根据算法将内核大小增加 4 倍,并在屏幕上渲染最终迭代。
问题是明显的条带,我的 streaks/tails 似乎亮度下降得更快:(注意:图像有些不准确,条带的长度是 same/correct,它的颜色错误的价值观)
我在 Desktop OpenGl / LWJGL 中为此苦苦挣扎了一段时间,我将其移植到 WebGL/Javascript 并上传到 JSFiddle,希望有人能发现问题所在。我怀疑它与纹理坐标或 FrameBuffer 配置有关,因为着色器完全相同。
它在 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);