我正在使用 libgdx 并希望制作一个常见的高斯模糊后处理效果。关注 this指南 我在纹理过滤方面遇到了一些问题。这里的图像:
实际图像:
用半径 = 1 模糊:
半径为 5 的模糊:
在最简单的情况下,我只有一个透明的帧缓冲区对象,其中一些对象呈现给它。然后我需要对此应用一些着色器效果,基本上只是模糊然后将结果渲染到屏幕上。我也想调整模糊半径,但如果我将半径设置为大于 1,它看起来会非常粗糙。猜想它应该与一些线性过滤一起使用,但它不在这里。所以我只需要使用软模糊和可配置半径应用相同的效果,也许还有其他一些着色器方面的选项。而且我还尝试将线性过滤显式分配给 FBO 纹理,这不会改变任何内容。
片段着色器:
//"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;
}
全class
最佳答案
这不是由于缺少线性插值造成的。该着色器沿每个轴仅执行 9 次纹理提取。您不能期望仅采样 9 次并使用更大的内核获得平滑的模糊,因为您跳过了可能包含重要信息的大量像素。只有 radius = 1
已验证。
对于更大的模糊,您需要更大的内核,或者多次应用较小的内核。
如果这太慢,要优化,您可以利用 this article 中的线性插值技术。 .因为线性插值可以让你以一个的价格计算两个相邻纹素之间的任意加权平均值,你可以得到一个等效的过滤器,它只执行 5 次纹理提取而不是 9 次,或者使用 9 次纹理提取来获得大小为 17 的内核。从下采样图像的金字塔中采样也是一种可能性。
顺便说一句,而不是这个冗长的事情:
vec2(tc.x - 4.0*blur*hstep, tc.y - 4.0*blur*vstep)
你可以简单地写:tc - 4.0*blur*dir
其他 7 行也类似。
关于OpenGL模糊,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64837705/