美文网首页
OpenGL ES 案例-灰度+颠倒+马赛克

OpenGL ES 案例-灰度+颠倒+马赛克

作者: MrDemon_ | 来源:发表于2020-08-16 21:54 被阅读0次

1、顶点着色器

attribute vec4 Position;
attribute vec2 TextureCoords;
varying vec2 TextureCoordsVarying;

void main (void) {

    TextureCoordsVarying = TextureCoords;
    gl_Position = Position;

}

以下是不同滤镜的片元着色器代码

2、正常

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

void main (void) {
    vec4 mask = texture2D(Texture, TextureCoordsVarying);
    gl_FragColor = vec4(mask.rgb, 1.0);
}

3、灰度

灰度滤镜,说白了就是调整了每个像素显示颜色的亮度,使得整张图片显示一个颜色。

灰度滤镜的实现原理是让RGB值保持一个平衡并填充,或者只保留一个亮度值,即绿色,在人眼中,绿色的亮度是最显眼的,绿色值越深,在肉眼观察中图片越暗淡,这是眼睛的一种生理现象。

有5种方法可以通过调整RGB值来实现:

  • 前三种属于权值法:处理后的图片比较逼真
  1. 浮点算法:Gray = R * 0.3 + G * 0.59 + B * 0.11 【RGB的权重总和为1】
  2. 整数⽅法:Gray = ( R * 30 + G * 59 + B * 11) / 100 【RGB的权重总和为100】
  3. 移位⽅法:Gray = ( R * 76 + G * 151 + B* 28) >> 8
  4. 平均值法:Gray = ( R + G + B ) / 3 【处理后的图片比较柔和】
  5. 仅取绿⾊:Gray = G 【这种方式最方便简单,且易用】
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);

    //将 像素颜色 与 变换因子 相乘 得到灰度值(向量和向量 点乘 得到标量)
    float luminance = dot(mask.rgb, W);

    //将原本的r,g,b,a 最终转换成 灰度值 填充到像素里。即(luminance,luminance,luminance,1.0)
    gl_FragColor = vec4(vec3(luminance), 1.0);
}

4、颠倒

通过上一个案例,我们可以简单地来实现了,直接Y值取反就实现了~

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

void main (void) {

    vec2 uv = TextureCoordsVarying.xy;
    vec4 mask = texture2D(Texture, vec2(uv.x,1.0-uv.y));
    gl_FragColor = vec4(mask.rgb, 1.0);
}

5、正方形马赛克

马赛克的原理:把图片的一个相当大小的区域用同一个颜色值来表示,可以认为是大规模的降低图像的分辨率,从而让图像的一些细节隐藏起来。

举例说明:100x100的图片,每10x10的区域本里可能有100个不同颜色,现在只用一个颜色填充,整张图片看下来就模糊了。

步骤:

  1. 先把原图按我们设置的比例放大
  2. 根据比例计算每一个马赛克的大小,获得一个区域
  3. 把马赛克区域根据比例缩小,就拿到了原纹理图片中的位置
  4. 给这一个区域填充颜色
image.png
precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;
//TextureCoordsVarying原本传进来
//假定纹理图片有这么大
const vec2 TexSize = vec2(400.0, 400.0);
//然后一个马赛克占得位置这么大,其实是算的一个比例
const vec2 mosaicSize = vec2(16.0, 16.0);

void main (void) {
    //1、计算实际纹理的像素点位置。
    //其实也是个相对的值,因为TextureCoordsVarying原本的值并不能确定每一个像素点的位置,放大后更好找
    vec2 intXY = vec2(TextureCoordsVarying.x*TexSize.x, TextureCoordsVarying.y*TexSize.y);
    //2、计算一个小马赛克的大小,即一个色块的位置
    /*
    floor(x)函数:返回一个 小于或者等于x的最大的整数,也就是向下取整
    floor(intXY.x/mosaicSize.x)*mosaicSize.x 拿到小马赛克的X
    floor(intXY.y/mosaicSize.y)*mosaicSize.y 拿到小马赛克的Y
     */
    vec2 XYMosaic = vec2(floor(intXY.x/mosaicSize.x)*mosaicSize.x, floor(intXY.y/mosaicSize.y)*mosaicSize.y);
    //3、换算成在纹理坐标中真正的位置
    vec2 UVMosaic = vec2(XYMosaic.x/TexSize.x, XYMosaic.y/TexSize. y);
    //4、拿到⻢赛克后的纹理坐标中的颜⾊值,然后进行填充
    vec4 mask = texture2D(Texture, UVMosaic);
    gl_FragColor = vec4(mask.rgb, 1.0);
} 

6、六边形马赛克

六边形马赛克原理:将一张图片分割成由六边形组成,再取每个六边形的中心点画出一个个的矩形,根据矩形的奇偶排列情况求出对应的2个中心点,并计算纹理坐标与两个中心点的距离,根据距离判断,采取就近原则,当前的六边形就采用近的中心点的颜色值。

说直白点,一个图片分成N个六边形,然后找出所有六边形中心点连线能组个一个个矩阵,这样的矩形根据中心点排布,可分为4种,然后看每一个像素点的位置, 距离哪个中心点更近,这样像素就取那个中心点的颜色,最终,一个六边形同色块的马赛克就形成了。

image

看几行几列,是为了计算对应的两个中心点,方便后面取值。

image

如何计算某一个像素点在这四种矩形中的具体坐标呢?

image

然后,计算这个点到两个中心点v1和v2的距离,距离谁比较近,取谁的颜色值就完成了。

  • s1 = √((v1.x-x)² + (v1.y-y)²)
  • s2 = √((v2.x-x)² + (v2.y-y)²)
precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;
//定义一个马赛克边长
const float mosaicSize = 0.03;
void main (void) {

    float length = mosaicSize;
    //根据3:√3设定宽高
    //定义矩形的宽
    float TB = 1.5;
    //定义矩形的高
    float TR = 0.866025;

    //拿到当前纹理坐标
    float x = TextureCoordsVarying.x;
    float y = TextureCoordsVarying.y;

    //换算成在矩形中的坐标
    int wx = int(x / TB / length);
    int wy = int(y / TR / length);

    //定义中心点v1  v2 和最终选的的点
    vec2 v1, v2, vn;

    //分4种情况判断取这个点的颜色值。就要先拿到对应2个中心点坐标
    //wx/2 * 2 == wx 就是偶数行   wy/2 * 2 == wy就是偶数列
    if (wx/2 * 2 == wx) {

        if (wy/2 * 2 == wy) {
            //(0,0),(1,1)
            v1 = vec2(length * 1.5 * float(wx), length * TR * float(wy));
            v2 = vec2(length * 1.5 * float(wx + 1), length * TR * float(wy + 1));
        } else {
            //(0,1),(1,0)
            v1 = vec2(length * 1.5 * float(wx), length * TR * float(wy + 1));
            v2 = vec2(length * 1.5 * float(wx + 1), length * TR * float(wy));
        }
    }else {
        if (wy/2 * 2 == wy) {
            //(0,1),(1,0)
            v1 = vec2(length * 1.5 * float(wx), length * TR * float(wy + 1));
            v2 = vec2(length * 1.5 * float(wx + 1), length * TR * float(wy));
        } else {
            //(0,0),(1,1)
            v1 = vec2(length * 1.5 * float(wx), length * TR * float(wy));
            v2 = vec2(length * 1.5 * 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));

    //比较,哪个距离小,这个像素点的颜色就取哪个中心点颜色
    if (s1 < s2) {
        vn = v1;
    } else {
        vn = v2;
    }
    vec4 color = texture2D(Texture, vn);

    gl_FragColor = color;
}

7、三角形马赛克

三角形马赛克是在六边形马赛克的基础上得到的,是把正六边形马赛克进行6等分,得到6个正三角形。

  1. 计算某一个像素点和中心点直接的夹角
  2. 求出6个正三角形的中心点
  3. 判断这个夹角属于哪个正三角形,就取哪个正三角形的颜色值
image image
precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;
//定义一个马赛克边长
const float mosaicSize = 0.03;
void main (void) {

    float length = mosaicSize;
    //根据3:√3设定宽高
    //定义矩形的宽
    float TB = 1.5;
    //定义矩形的高
    float TR = 0.866025;
    //π/6的值
    const float PI6 = 0.523599;
    //拿到当前纹理坐标
    float x = TextureCoordsVarying.x;
    float y = TextureCoordsVarying.y;

    //换算成在矩形中的坐标
    int wx = int(x / TB / length);
    int wy = int(y / TR / length);

    //定义中心点v1  v2 和最终选的的点
    vec2 v1, v2, vn;

    //分4种情况判断取这个点的颜色值。就要先拿到对应2个中心点坐标
    //wx/2 * 2 == wx 就是偶数行   wy/2 * 2 == wy就是偶数列
    if (wx/2 * 2 == wx) {

        if (wy/2 * 2 == wy) {
            //(0,0),(1,1)
            v1 = vec2(length * 1.5 * float(wx), length * TR * float(wy));
            v2 = vec2(length * 1.5 * float(wx + 1), length * TR * float(wy + 1));
        } else {
            //(0,1),(1,0)
            v1 = vec2(length * 1.5 * float(wx), length * TR * float(wy + 1));
            v2 = vec2(length * 1.5 * float(wx + 1), length * TR * float(wy));
        }
    }else {
        if (wy/2 * 2 == wy) {
            //(0,1),(1,0)
            v1 = vec2(length * 1.5 * float(wx), length * TR * float(wy + 1));
            v2 = vec2(length * 1.5 * float(wx + 1), length * TR * float(wy));
        } else {
            //(0,0),(1,1)
            v1 = vec2(length * 1.5 * float(wx), length * TR * float(wy));
            v2 = vec2(length * 1.5 * 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));

    //比较,哪个距离小,这个像素点的颜色就取哪个中心点颜色
    if (s1 < s2) {
        vn = v1;
    } else {
        vn = v2;
    }

    //计算像素和中心点vn的夹角
    float a = atan((x - vn.x)/(y - vn.y));

    //计算6个正三角形的中心点
    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 = color;

}

相关文章

网友评论

      本文标题:OpenGL ES 案例-灰度+颠倒+马赛克

      本文链接:https://www.haomeiwen.com/subject/ukvxjktx.html