OpenGL ES: 滤镜篇1 -GLSL 灰度,颠倒,旋涡,马赛克

前提: 使用GLSL实现滤镜的前提条件是可以用GLSL显示普通图片算法

灰度滤镜bash

原理: 图片的显示由三个颜色通道(rgb)决定,而灰度滤镜全部通道的值相同,也就是说只要获得亮度即可。下面提供5种方式实现灰度滤镜(前三种是利用权重来实现)

算法ui

  • 浮点算法: Gray = R * 0.3 + G * 0.59 + B * 0.11
  • 整数算法: Gray = (R * 30 + G * 59 + B * 11) / 100
  • 移位算法: Gray = (R * 76 + G * 151 + B * 28) >> 8
  • 平均值法: Gray = (R + G + B) / 3;
  • 仅取绿色: Gray = G

片元着色器代码实现:spa

precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;
//灰度计算比率 (借用GPUImage的值)
const highp vec3 ratio = vec3(0.2125, 0.7154, 0.0721);
void main (void) {
    vec4 mask = texture2D(Texture, TextureCoordsVarying);
    // Gray值
    float luminance = dot(mask.rgb, ratio);
    gl_FragColor = vec4(vec3(luminance), 1.0);
}
复制代码

颠倒滤镜3d

原理: 在Y轴上反转纹理坐标.

片元着色器代码实现:code

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

void main (void) {
//y轴坐标反转
    vec4 color = texture2D(Texture, vec2(TextureCoordsVarying.x, 1.0 - TextureCoordsVarying.y));
    gl_FragColor = color;
}
复制代码

旋涡滤镜orm

原理: 图形漩涡主要是在某个半径范围内,把当前采样点旋转必定角度,旋转之后当前点的颜色就被旋转后的点的颜色代替,所以整个半径范围里会有旋转的效果。 若是旋转的时候旋转角度随着当前点距离半径的距离递减,整个图像就会出现漩涡效果,如上图同样。 这里会使用抛物线递减因子: (1.0 - (r / Radius) * (r / Radius))

片元着色器代码实现:cdn

precision mediump float;
uniform sampler2D Texture;
//旋涡旋转角度
const float uD = 80.0;
//旋涡半径,范围(0 ~ 0.5)
const float uR = 0.5;
//纹理坐标
varying vec2 TextureCoordsVarying;

void main()
{
    //旋涡半径
    float Radius = uR;
    //当前纹理坐标
    vec2 xy = TextureCoordsVarying;
    //当前纹理到中心点的向量
    vec2 dxy = xy - vec2(0.5, 0.5);
    //当前纹理到中心点距离
    float r = length(dxy);
    //旋转角度变化
    float beta = atan(dxy.y, dxy.x) + radians(uD) * 2.0 * ( 1.0 -(r/Radius)*(r/Radius));
    //旋涡范围内的坐标变化
    if(r<=Radius)
    {
        xy = 0.5 + r * vec2(cos(beta), sin(beta));
    }
    //将旋转的纹理坐标替换原始纹理坐标TextureCoordsVarying 获取对应像素点的颜⾊. 
    vec3 irgb = texture2D(Texture, xy).rgb;
    //将计算后的颜⾊填充到像素点中 gl_FragColor
    gl_FragColor = vec4( irgb, 1.0 );
}

复制代码

马赛克滤镜blog

原理: 马赛克效果就是把图片的一个至关大小的区域用同一个点的颜色来表示,能够认为是大规模的下降图像的分辨率,而让图片的一些细节隐藏起来。

1.矩形马赛克 片元着色器代码实现:图片

precision mediump float;
varying vec2 TextureCoordsVarying;
uniform sampler2D Texture;
//马赛克矩形所占纹理范围比例
const vec2 mosaicSizeRatio = vec2(0.05, 0.05);

void main()
{
    //纹理范围能够切割多少个矩形马赛克
    vec2 totalXY = vec2(floor(1.0 / mosaicSizeRatio.x), floor(1.0 / mosaicSizeRatio.y));
    //当前纹理在哪一个矩形马赛克范围
    vec2 eachXY = vec2(floor(TextureCoordsVarying.x / mosaicSizeRatio.x), floor(TextureCoordsVarying.y / mosaicSizeRatio.y));
   //当前纹理块对应的纹理坐标
    vec2 UVMosaic = vec2(eachXY.x / totalXY.x, eachXY.y / totalXY.y);
    vec4 color = texture2D(Texture, UVMosaic);
    gl_FragColor = color;
}
复制代码

2.六边形马赛克

思路: 咱们须要作的效果就是让一张图片,分割成由六边形组成,让每一个六边形中的颜色相同,下面采用直接取六边形中心点像素来实现. 再次分割,取每一个六边形的中心点画出矩形阵,以下:

假定咱们设定的矩阵比例为 a LEN : bLEN ,那么屏幕上的任意 点(x, y)所对应的矩阵坐标为(int(x/(a LEN)), int(y/ (bLEN)))。

(wx, wy) 表示纹理坐标在所对应的矩阵坐标为:

wx = int(x/(a * length))

wy = int(y/(b * length))

根据行和列的奇偶数排列规则,计算一个矩形块内的任意点距离哪一个六边形的距离短,就属于哪一个六边形.

片元着色器代码实现:

precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;
/// 马赛克大小比率
const float mosaicSize = 0.05;

void main (void)
{
    //马赛克大小比率
    float length = mosaicSize;
    // 矩形b
    float TR = 0.866025;
    //当前纹理坐标
    float x = TextureCoordsVarying.x;
    float y = TextureCoordsVarying.y;
    //当前纹理坐标在所对应的矩阵坐标
    int wx = int(x / 1.5 / length);
    int wy = int(y / TR / length);
    //v1, v2为矩形顶点(六边形的中心点)的纹理坐标
    vec2 v1, v2, vn;
    //排列行,列的奇偶数判断规则
    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;
    
}
复制代码
相关文章
相关标签/搜索