OpenGL ES 2.0 片段着色器模糊效果缓慢且质量低下。

6

我正在尝试为iPad编写模糊着色器。我已经让它工作了,但是我对结果并不满意。当模糊程度很高时,我的帧率非常低且模糊效果看起来很差。

有什么想法可以改善吗?

以下是一些示例输出:

alt text

uniform sampler2D texture;
varying mediump vec2 fragTexCoord;
varying mediump vec3 eyespaceNormal;

varying highp float blurAmount;

void main(void)
{
    highp vec2 gaussFilter[7];
    gaussFilter[0] = vec2(-3.0, 0.015625);
    gaussFilter[1] = vec2(-2.0, 0.09375);
    gaussFilter[2] = vec2(-1.0, 0.234375);
    gaussFilter[3] = vec2(0.0, 0.3125);
    gaussFilter[4] = vec2(1.0, 0.234375);
    gaussFilter[5] = vec2(2.0, 0.09375);
    gaussFilter[6] = vec2(3.0, 0.015625);

    highp float blurSize = blurAmount * 1.0;

    /////////////////////////////////////////////////
    // 7x1 gaussian blur fragment shader
    /////////////////////////////////////////////////

    highp vec4 color = vec4(0,0,0,1);

    for( int i = 0; i < 7; i++ )
    {
        color += texture2D( texture, vec2( fragTexCoord.x+gaussFilter[i].x*blurSize, fragTexCoord.y+gaussFilter[i].x*blurSize ) )*gaussFilter[i].y;
    }

    gl_FragColor = color;
}

编辑: 可能需要使用盒子模糊。 这是该着色器的盒子模糊版本:

highp vec4 color = vec4(0,0,0,1);

color += texture2D(texture, vec2(fragTexCoord.x, fragTexCoord.y - 4.0*blurAmount)) * 0.05;
color += texture2D(texture, vec2(fragTexCoord.x, fragTexCoord.y - 3.0*blurAmount)) * 0.09;
color += texture2D(texture, vec2(fragTexCoord.x, fragTexCoord.y - 2.0*blurAmount)) * 0.12;
color += texture2D(texture, vec2(fragTexCoord.x, fragTexCoord.y - blurAmount)) * 0.15;
color += texture2D(texture, vec2(fragTexCoord.x, fragTexCoord.y)) * 0.16;
color += texture2D(texture, vec2(fragTexCoord.x, fragTexCoord.y + blurAmount)) * 0.15;
color += texture2D(texture, vec2(fragTexCoord.x, fragTexCoord.y + 2.0*blurAmount)) * 0.12;
color += texture2D(texture, vec2(fragTexCoord.x, fragTexCoord.y + 3.0*blurAmount)) * 0.09;
color += texture2D(texture, vec2(fragTexCoord.x, fragTexCoord.y + 4.0*blurAmount)) * 0.05;

gl_FragColor = color;

这是盒式模糊的输出结果(请注意,这只是水平模糊,但对我想要的可能已经足够了): alt text
3个回答

10
那个着色器需要运行两次才能正常工作,你所称的 `blurSize` 应该是一个 `vec2`,其值应该为 `vec2(0, 1.0/height)` 用于垂直模糊,而对于水平模糊,则为 `vec2(1.0/width, 0)`。
参见http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=240334 进行双遍模糊的想法在于它将大幅减少纹理查找次数,从而提高速度。使用7x7核大小的双遍模糊需要进行14次纹理查找,但如果在嵌套循环中完成,则需要进行49次纹理查找。

是的,我认为那是我在调整代码时犯的错误。谢谢。我想对于我的目的,我并不真正需要一个完整的高斯模糊,所以简单的盒式模糊可能足够好并且更快。 - Brian

3

1

你的代码到底在做什么并不清楚。你使用了texture2D,这表明是一个2D滤镜。然而,你的卷积矩阵只有一个维度,并且你只循环了一次。我可能错了,但似乎你正在对角线上应用模糊效果。如果它是一个2D滤镜,那么你需要两个(嵌套)循环分别用于x和y来覆盖2D区域。

关于变量blurSize - 它的名称有点误导人。模糊的大小取决于你的卷积矩阵。你的矩阵宽度为7像素。这决定了大小。该变量更像是模糊的“强度”,只能淡化卷积矩阵的效果。如果给定的值过高,将会出现伪影。

我不是专家,也没有写过除了“hello world”曼德博集合之外的任何像素着色器。如果我没错的话,那么模糊着色器是最难加速的之一。我看到的大多数实时模糊都是box-blurs。尝试从这里移植一些代码:gameDev thread


我决定尝试一下盒状模糊。看起来效果还不错,但我还没有在iPad上尝试过,以查看它是否足够快,但外观还不错。我将在我的答案中发布代码。谢谢。 - Brian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接