OpenGl模糊 [英] OpenGl blurring

查看:72
本文介绍了OpenGl模糊的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用libgdx,并希望做出普通的高斯模糊后处理效果.遵循

解决方案

这不是由缺少线性插值引起的.该着色器沿每个轴仅执行9个纹理提取.您不能指望仅采样9次并获得更大内核的平滑模糊效果,因为您跳过了很多可能包含重要信息的像素.仅 radius = 1 有效.

要获得更大的模糊效果,您要么需要更大的内核,要么多次应用较小的内核.

要优化速度是否太慢,可以利用this guide I faced some issues with texture filtering. Here the images:

actual image:

blurred with radius = 1:

blurred with radius = 5:

In the simplest case, I just have a transparent frame buffer object with some objects rendered to it. Then I need to apply some shader effects to this, basically only blur and then render the result to the screen. I also want to adjust the blur radius, but if I set the radius to more than 1 it becomes looking very rough. Guess it should be used with some linear filtering, but it isn't here. So I just need the same effect applied with a soft blur and configurable radius, maybe some other shader-sided options. And I've also tried to explicitly assign Linear filtering to FBO textures, which doesn't change anything.

Fragment shader:

//"in" attributes from our vertex shader
varying vec4 vColor;
varying vec2 vTexCoord;

//declare uniforms
uniform sampler2D u_texture;
uniform float resolution;
uniform float radius;
uniform vec2 dir;

void main() {
    //this will be our RGBA sum
    vec4 sum = vec4(0.0);
    
    //our original texcoord for this fragment
    vec2 tc = vTexCoord;
    
    //the amount to blur, i.e. how far off center to sample from 
    //1.0 -> blur by one pixel
    //2.0 -> blur by two pixels, etc.
    float blur = radius/resolution; 
    
    //the direction of our blur
    //(1.0, 0.0) -> x-axis blur
    //(0.0, 1.0) -> y-axis blur
    float hstep = dir.x;
    float vstep = dir.y;
    
    //apply blurring, using a 9-tap filter with predefined gaussian weights
    
    sum += texture2D(u_texture, vec2(tc.x - 4.0*blur*hstep, tc.y - 4.0*blur*vstep)) * 0.0162162162;
    sum += texture2D(u_texture, vec2(tc.x - 3.0*blur*hstep, tc.y - 3.0*blur*vstep)) * 0.0540540541;
    sum += texture2D(u_texture, vec2(tc.x - 2.0*blur*hstep, tc.y - 2.0*blur*vstep)) * 0.1216216216;
    sum += texture2D(u_texture, vec2(tc.x - 1.0*blur*hstep, tc.y - 1.0*blur*vstep)) * 0.1945945946;
    
    sum += texture2D(u_texture, vec2(tc.x, tc.y)) * 0.2270270270;
    
    sum += texture2D(u_texture, vec2(tc.x + 1.0*blur*hstep, tc.y + 1.0*blur*vstep)) * 0.1945945946;
    sum += texture2D(u_texture, vec2(tc.x + 2.0*blur*hstep, tc.y + 2.0*blur*vstep)) * 0.1216216216;
    sum += texture2D(u_texture, vec2(tc.x + 3.0*blur*hstep, tc.y + 3.0*blur*vstep)) * 0.0540540541;
    sum += texture2D(u_texture, vec2(tc.x + 4.0*blur*hstep, tc.y + 4.0*blur*vstep)) * 0.0162162162;

    gl_FragColor = vColor * sum;
}

The full class

解决方案

This is not caused by a lack of linear interpolation. This shader is doing only 9 texture fetches along each axis. You can't expect to sample only 9 times and get a smooth blur with a larger kernel, because you are skipping over a lot of pixels which might contain important information. Only radius = 1 is valid.

For a larger blur, you either need a larger kernel, or apply the smaller kernel several times.

To optimize if this gets too slow, you can leverage the linear interpolation technique from this article. Because linear interpolation lets you compute an arbitrary weighted average between two adjacent texels for the price of one, you can get an equivalent filter that performs just 5 texture fetches instead of 9, or use 9 texture fetches to get a kernel of size 17. Cleverly sampling from a pyramid of downsampled images is also a possibility.

By the way, instead of this verbose thing:

vec2(tc.x - 4.0*blur*hstep, tc.y - 4.0*blur*vstep)

You can simply write:

tc - 4.0*blur*dir

And similar for the other 7 lines.

这篇关于OpenGl模糊的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆