OpenGL ES

OpenGL ES 案例之马赛克滤镜

2020-08-20  本文已影响0人  爱看书de图图

  结合实际案例,我们来实现各种滤镜效果,首先看一下效果:


  这里的基础功能搭建,和不通着色器的调用,我们不在赘述,跟上一篇案例一模一样。OpenGL ES案例之GLSL分屏滤镜。接下来我们注重讲述各个滤镜效果的实现原理,简单的一笔带过,复杂的我们详细描述。希望大家都可以看懂。
灰度滤镜

  灰度滤镜的原理算法如下公式,比较常用的是第一种,至于第五种的意思,就是只取绿色,因为人眼对绿色敏感度较高,绿色越少灰度越高。灰度滤镜的实现方法有很多,比如GPUImage,或者系统自带的CoreImage

precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

//RGB的变换因子,即权重值
const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);
void main(){
    //获取对应纹理坐标系下色颜色值
    vec4 mask = texture2D(Texture, TextureCoordsVarying);
    //将颜色mask 与 变换因子相乘得到灰度值
    float luminance = dot(mask.rgb, W);
    //将灰度值转换为(luminance,luminance,luminance,mask.a)并填充到像素中
    gl_FragColor = vec4(vec3(luminance), 1.0);
}
颠倒滤镜

  颠倒滤镜比较简单,就是改变纹理的映射关系即可。

 vec4 color = texture2D(Texture, vec2(TextureCoordsVarying.x, 1.0 - TextureCoordsVarying.y));
马赛克滤镜

  马赛克滤镜这里设置三种马赛克图形。

正方形马赛克

  假定我们纹理图片如上图所示,马赛克的作用就是把其他颜色都换成临近的红色,来达到模糊的效果。算法步骤:

1.扩大纹理,比如扩大400倍
2.把扩大后的纹理比上马赛克的size,然后向下取整再乘以马赛克的size以达到模糊效果
3.把纹理缩小到原始大小

precision mediump float;
varying vec2 TextureCoordsVarying;
uniform sampler2D Texture;
const vec2 TexSize = vec2(400.0, 400.0);
const vec2 mosaicSize = vec2(16.0, 16.0);
void main()
{
    vec2 intXY = vec2(TextureCoordsVarying.x*TexSize.x, TextureCoordsVarying.y*TexSize.y);
    vec2 XYMosaic = vec2(floor(intXY.x/mosaicSize.x)*mosaicSize.x, floor(intXY.y/mosaicSize.y)*mosaicSize.y);
    vec2 UVMosaic = vec2(XYMosaic.x/TexSize.x, XYMosaic.y/TexSize.y);
    vec4 color = texture2D(Texture, UVMosaic);
    gl_FragColor = color;
}
六边形马赛克

  六边形马赛克原理:我们看上图,六边形马赛克图如左边所示,当我们把它分割以后,我们观察绿色框框内的青色矩形,我们知道,这些图形可以看做是如右图的两种AB图形组成的。

偶行偶列 /,矩形A,顶点为左上,右下
偶行奇列 \,矩形B,顶点为左下,右上
奇行奇列 /,矩形A,顶点为左上,右下
奇行偶列 \,矩形B,顶点为左下,右上

  那么我们所去的所有像素点都会落在AB矩形中,在这里我们用A矩形来举例说明。假设我们取了像素点X,那么A矩形代表六边形的顶点就是顶点1和顶点2,所以像素点X的取值必然是在顶点1和顶点2中选择一个。然后我们采用临近原则,由于d2小于d1,所以我们这里取得像素中心点的纹理就是顶点2的色值。对应的原理也适用于B矩形,B矩形对应的六边形的顶点就是左下和右上方的顶点。
  AB矩形的宽高比我们知道是3比根号3,如果像素点X的坐标是(x,y),那么对应的像素点X在矩阵中的坐标就为(int(x /( 1.5 * length)),int(y /(TR * length)))


  四个顶点的映射坐标就是下图:
  片元着色器代码:
precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;
//六边形的边长
const float mosaicSize = 0.03;

void main(){
    
    float length = mosaicSize;
    //矩形的高的比例为√3,取值 √3/2 ,也可以直接取√3
    float TR = 0.866025;
    //矩形的长的比例为3,取值 3/2 = 1.5,也可以直接取3
    float TB = 1.5;
    
    //取出纹理坐标
    float x = TextureCoordsVarying.x;
    float y = TextureCoordsVarying.y;
    
    //根据纹理坐标计算出对应的矩阵坐标 
    //即 矩阵坐标wx = int(纹理坐标x/ 矩阵长),矩阵长 = TB*len
    //即 矩阵坐标wy = int(纹理坐标y/ 矩阵宽),矩阵宽 = TR*len
    int wx = int(x / TB / length);
    int wy = int(y / TR / length);
    vec2 v1, v2, vn;
    
    //判断wx是否为偶数,等价于 wx % 2 == 0
    if (wx/2 * 2 == wx) {
        if (wy/2 * 2 == wy) {//偶行偶列
            //(0,0),(1,1)
            v1 = vec2(length * TB * float(wx), length * TR * float(wy));
            v2 = vec2(length * TB * float(wx+1), length * TR * float(wy+1));
        }else{//偶行奇列
            //(0,1),(1,0)
            v1 = vec2(length * TB * float(wx), length * TR * float(wy+1));
            v2 = vec2(length * TB * float(wx+1), length * TR * float(wy));
        }
    }else{
        if (wy/2 * 2 == wy) {//奇行偶列
            //(0,1),(1,0)
            v1 = vec2(length * TB * float(wx), length * TR * float(wy+1));
            v2 = vec2(length * TB * float(wx+1), length * TR * float(wy));
        }else{//奇行奇列
            //(0,0),(1,1)
            v1 = vec2(length * TB * float(wx), length * TR * float(wy));
            v2 = vec2(length * TB * float(wx+1), length * TR * float(wy+1));
        }
    }
    //利用距离公式,计算中心点与当前像素点的距离
    float s1 = sqrt(pow(v1.x-x, 2.0) + pow(v1.y-y, 2.0));
    float s2 = sqrt(pow(v2.x-x, 2.0) + pow(v2.y-y, 2.0));
    
    //选择距离小的则为六边形的中心点,且获取它的颜色
    vn = (s1 < s2) ? v1 : v2;
    //获取六边形中心点的颜色值
    vec4 color = texture2D(Texture, vn);
    gl_FragColor = color;
}
三角形马赛克

  三角形马赛克原理:三角形马赛克是由六边形马赛克演变而来,把六边形六等分,就得到了三角形马赛克。

    //获取像素点与中心点的角度
   float a = atan((x-vn.x)/(y-vn.y));
    
    //判断夹角,属于哪个三角形,则获取哪个三角形的中心点坐标
    vec2 area1 = vec2(vn.x, vn.y - mosaicSize * TR / 2.0);
    vec2 area2 = vec2(vn.x + mosaicSize / 2.0, vn.y - mosaicSize * TR / 2.0);
    vec2 area3 = vec2(vn.x + mosaicSize / 2.0, vn.y + mosaicSize * TR / 2.0);
    vec2 area4 = vec2(vn.x, vn.y + mosaicSize * TR / 2.0);
    vec2 area5 = vec2(vn.x - mosaicSize / 2.0, vn.y + mosaicSize * TR / 2.0);
    vec2 area6 = vec2(vn.x - mosaicSize / 2.0, vn.y - mosaicSize * TR / 2.0);
    
    if (a >= PI6 && a < PI6 * 3.0) {
        vn = area1;
    }else if (a >= PI6 * 3.0 && a < PI6 * 5.0){
        vn = area2;
    }else if ((a >= PI6 * 5.0 && a <= PI6 * 6.0) || (a < -PI6 * 5.0 && a > -PI6 * 6.0)){
        vn = area3;
    }else if (a < -PI6 * 3.0 && a >= -PI6 * 5.0){
        vn = area4;
    }else if (a <= -PI6 && a > -PI6 * 3.0){
        vn = area5;
    }else if (a > -PI6 && a < PI6){
        vn = area6;
    }
    //获取对应三角形重心的颜色值
    vec4 color = texture2D(Texture, vn);
    // 将颜色值填充到片元着色器内置变量gl_FragColor
    gl_FragColor = color;
上一篇下一篇

猜你喜欢

热点阅读