用于模糊的 OpenGL ES 2.0 片段着色器速度慢且质量低

Posted

技术标签:

【中文标题】用于模糊的 OpenGL ES 2.0 片段着色器速度慢且质量低【英文标题】:OpenGL ES 2.0 fragment shader to blur is slow and low quality 【发布时间】:2010-12-04 19:58:05 【问题描述】:

我正在尝试为 iPad 编写模糊着色器。我有它的工作,但我对结果不是很满意。我得到非常不稳定的帧速率,并且当模糊量很高时,模糊看起来像废话。

关于如何改进的任何想法?

一些示例输出:

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;

这是框模糊输出(请注意,它只是水平模糊,但对于我想要的可能就足够了):

【问题讨论】:

【参考方案1】:

该着色器需要运行两次才能正常工作,您调用的 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 次纹理查找。

【讨论】:

是的,我认为这是我在调整代码方面的失误。谢谢。我认为我真的不需要完整的高斯来实现我的目的,因此简单的框模糊可能会足够好并且更快。【参考方案2】:

执行两个或更多框模糊通道可将质量提高到非常接近高斯模糊,同时保持相对较高的性能。盒子模糊也可以相对容易地加速。看看http://web.archive.org/web/20060718054020/http://www.acm.uiuc.edu/siggraph/workshops/wjarosz_convolution_2001.pdf

在任何情况下,在大多数移动场景中,您都可以使用比屏幕截图看起来明显的更低保真度的渲染。

【讨论】:

【参考方案3】:

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

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

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

【讨论】:

我决定试试盒子模糊。似乎工作得很好,但我还没有在我的 iPad 上尝试过,看看它是否足够快,但看起来还不错。我将在上面的答案中发布代码。谢谢

以上是关于用于模糊的 OpenGL ES 2.0 片段着色器速度慢且质量低的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL ES 2.0 符点精度

如何在 OpenGL ES 2.0 中获得“发光”着色器效果?

如何使用 OpenGL ES 2.0 着色器完成这些图像处理任务?

IOS:OpenGL ES 2.0 与 3.0 中动态分支着色器的性能

是否可以在顶点着色器内持续更改 iPhone OpenGL ES 2.0 上的 VBO 值?

如何在 OpenGL ES 2.0 中将视图/模型/投影矩阵传递给我的顶点着色器?