版权声明:本文为 松阳 (blog.csdn.net/fansongy) 原创文章,转载必须注明出处: https://blog.csdn.net/fansongy/article/details/79263735
卷积
卷积 (Convolution)是两个变量在某范围内相乘后求和的结果。卷积计算通常用来处理边缘的颜色或整体的混色。作为采样之后的处理,可以供很多功能使用。因此在图像效果处理时,它还是应用比较广泛的。
区域缩暗
通过最简单的像素采样,可以将图片中整体的锐利度降低,通过在一个3x3的区域取颜色,并取出区域中的最小色值,可以实现整体变暗,并且边界会像内缩一段距离。
void main()
{
vec4 minValue = vec4(1.0);
int coreSize=3;
int halfSize=coreSize/2;
float texelOffset = 1/100.0;
for(int y=0;y<coreSize;y++)
{
for(int x = 0;x<coreSize;x++)
{
vec4 currentAlpha = texture2D(U_MainTexture,V_Texcoord+vec2((-halfSize+x)*texelOffset,(-halfSize+y)*texelOffset));
minValue = min(minValue,currentAlpha);
}
}
gl_FragColor=minValue;
}
区域加亮
与区域缩暗相反,取域中最亮的值就可以加亮整体效果,另外边界也会加大。
void main()
{
vec4 maxValue = vec4(0.0);
int coreSize=10;
int halfSize=coreSize/2;
float texelOffset = 1/100.0;
for(int y=0;y<coreSize;y++)
{
for(int x = 0;x<coreSize;x++)
{
vec4 currentAlpha = texture2D(U_MainTexture,V_Texcoord+vec2((-halfSize+x)*texelOffset,(-halfSize+y)*texelOffset));
maxValue = max(maxValue,currentAlpha);
}
}
gl_FragColor=maxValue;
}
高斯模糊
当加在算子中加入权重,就是高斯模糊的效果,比如:
1,2,1
2,4,2
1,2,1
然后在求和之后除以算子的总和16。
void main()
{
vec4 color = vec4(0.0);
int coreSize=3;
int halfSize=coreSize/2;
float texelOffset = 1/100.0;
float kernel[9];
kernel[6] = 1; kernel[7] = 2; kernel[8] = 1;
kernel[3] = 2; kernel[4] = 4; kernel[5] = 2;
kernel[0] = 1; kernel[1] = 2; kernel[2] = 1;
int index = 0;
for(int y=0;y<coreSize;y++)
{
for(int x = 0;x<coreSize;x++)
{
vec4 currentColor = texture2D(U_MainTexture,V_Texcoord+vec2((-1+x)*texelOffset,(-1+y)*texelOffset));
color += currentColor*kernel[index];
index++;
}
}
color/=16.0;
gl_FragColor=color;
}
这样就按原理实现了高斯模糊,但实际过程中并不会这样算。因为遍历的成本太高了。通常拆成两个一维向量,这样时间复杂度就由NxNxWxH
下降为2xNxWxH
(W为图像的宽,H为图像的高)。另外这些权重又是对称的,因此对于一个5x5的高斯核,只需要记录三个值就可以计算 卷积 了。有时我们也会将水平和竖直的模糊拆分到两个Pass中方便进行效果调整。如果为了节省Drawcall,就会在同一个元片中混合,但也应水平和竖直分别处理,因为它们的像素偏移可能会不同。
void main()
{
float weight[3] = {0.4026,0.2442,0.0545};
float texelOffset = 1/100.0;
//only show vertical here...
float uv[5];
uv[0]=V_Texcoord;
uv[1]=uv + vec2(0.0, texelOffset*1.0 );
uv[2]=uv - vec2(0.0, texelOffset*1.0 );
uv[3]=uv + vec2(0.0, texelOffset*2.0 );
uv[4]=uv - vec2(0.0, texelOffset*2.0 );
fixed3 sum = tex2D(U_MainTexture,uv[0]).rgb *weight[0];
for(int i = 1;i<3;++i)
{
sum += tex2D(U_MainTexture,uv[2i-1]).rgb * weight[i];
sum += tex2D(U_MainTexture,uv[2i]).rgb * weight[i];
}
gl_FragColor=sum;
}
上面的代码只是垂直方向的 卷积 计算,相同的办法可以算出水平的效果,最后如果需要混合到一起即可。
总结
本文介绍了如何利用RTT和 卷积 算法来制作屏幕效果。
![](https://learnopengl.com/img/advanced-lighting/bloom_example.png)