美文网首页
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