OpenGL(十六)通过 卷积 实现: 边缘混合 、 Blur 和 高斯模糊

版权声明:本文为 松阳 (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和 卷积 算法来制作屏幕效果。


猜你喜欢

转载自blog.csdn.net/fansongy/article/details/79263735