一.先看看整体效果
二.灰度滤镜
灰度滤镜实现原理是获取像素点的颜色值,通过改变该像素点的颜色值实现灰度滤镜,究其根本是通过RGB保持平衡填充,或者保留一个亮度值(即绿色,在人眼中,绿色的亮度是最显眼的,绿色值越深,在肉眼观察中图片越暗淡,这是眼睛的一种生理现象)
灰度滤镜算法:
1)浮点算法:Gray=R*0.3+G*0.59+B*0.11
2)整数⽅法:Gray=(R*30+G*59+B*11)/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;
varyingvec2TextureCoordsVarying;
const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);----->权重,该参数取值样本来自于GPUimage灰度滤镜参数
voidmain (void) {
vec4mask =texture2D(Texture, TextureCoordsVarying);
floatluminance =dot(mask.rgb, W);
gl_FragColor=vec4(vec3(luminance),1.0);
}
dot(mask.rgb, W)点乘,让原像素点的颜色值乘以权重,得到一个新的RGB颜色值,并填充。
仅取绿色:
precision highpfloat;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;
voidmain()
{
//获取对应纹理坐标系下色颜色值
vec4 mask=texture2D(Texture,TextureCoordsVarying);
//将RGB全部设置为G,即GRB全部取绿色值
gl_FragColor=vec4(mask.g,mask.g,mask.g,1.0);
}
其他算法,请参照服点算法,这里不一一举例了
三.万恶的马赛克
马赛克原理:把图片的一个相当大小的区域用同一个颜色值来表示,可以认为是大规模的降低图像的分辨率,从而让图像的一些细节隐藏起来
3.1正方形马赛克原理图:
当拿到蓝色块的纹理坐标,对应的在(16,16)范围内只显示该像素点的颜色值
片元着色器代码:
precision mediump float;
varyingvec2TextureCoordsVarying;
uniform sampler2D Texture;
constvec2TexSize =vec2(400.0,400.0);----->(该参数最少>=图片的宽高)
constvec2mosaicSize =vec2(16.0,16.0);---->(根据实际的情况,该参数尽量合适)
voidmain()
{
vec2intXY =vec2(TextureCoordsVarying.x*TexSize.x, TextureCoordsVarying.y*TexSize.y);
vec2XYMosaic =vec2(floor(intXY.x/mosaicSize.x)*mosaicSize.x,floor(intXY.y/mosaicSize.y)*mosaicSize.y);
//换算回纹理坐标
vec2UVMosaic =vec2(XYMosaic.x/TexSize.x, XYMosaic.y/TexSize.y);
vec4color =texture2D(Texture, UVMosaic);
gl_FragColor= color;
}
3.2六边形马赛克
思路: 我们要做的效果就是让⼀张图⽚,分割成由六边形组成,让每个六边形中的颜⾊相同(直接取六边形中⼼点像素RGB较⽅便,我们这⾥采⽤的就是这种⽅法)将它进⾏分割,取每个六边形的中⼼点画出⼀个矩阵。
首先我们设置举行的长宽:画出很多⻓和宽⽐例为 3:√3 的的矩形阵。然后我们可以对每个点进⾏编号,假如我们的屏幕的左上点为上图的(0,0)点,则屏幕上的任⼀点我们找到它所对应的那个矩形了,假定我们设定的矩阵⽐例为 3*LEN : √3*LEN ,那么屏幕上的任意点(x, y)所对应的矩阵坐标为(int(x/(3*LEN)), int(y/(√3*LEN)))。wx,wy -> 表⽰纹理坐标在所对应的矩阵坐标为 int wx = int(x /( 1.5 * length)); int wy = int(y /(TR * length))。
3:√3的来源:设置矩形的长宽比例值TR、TB(TB:TR 符合比例 3:√3)计算过程如下:
获取纹理坐标的x,y,根据纹理坐标计算对应的矩形坐标wx、wy,假设矩阵的比例为3*len:√3*len,那么纹理坐标(x,y)对应的矩阵坐标为:
根据行列的奇偶情况,求对应的中心点纹理坐标v1、v2
偶行偶列:(0,0)(1,1)/,即左上、右下
偶行奇列:(0,1)(1,0)\,即左下、右上
奇行偶列:(0,1)(1,0)\,即左下、右上
奇行奇列:(0,0)(1,1)/,即左上、右下
最终就两种情况:
最终汇总起来也只有2种情况,(0,0)(1,1) 和 (0,1)(1,0),如下图所示
其中单个矩阵中,4个点的坐标计算公式如下:
- 对于计算中的wx+1,拿(1,0)点来说,wx+1等同于(1,0)与(0,0)之间相差一个矩形的长,这个长度为1,为了得到(1,0)点的坐标,要在(0,0)点坐标的基础上,将wx增加一个长
- 对于计算中的wy+1,拿(0,1)点来说,wy+1等同于(0,0)与(0,1)之间相差一个矩形的高,这个长度为1,为了得到(0,1)点的坐标,要在(0,0)点坐标的基础上,将wy增加一个高
最后根据勾股定理,计像素点距离两个中心点的距离s1、s2根据距离公式求像素点距离两个中心点的距离s1、s2
片元着色器代码:
precision highp float;
uniform sampler2D Texture;
varyingvec2TextureCoordsVarying;
constfloatmosaicSize =0.03;
voidmain (void)
{
floatlength= mosaicSize;
floatTR =0.866025;//矩形的高的比例为√3,取值 √3/2 ,也可以直接取√3
floatTB =1.5;//矩形的长的比例为3,取值 3/2 = 1.5,也可以直接取3
floatx = TextureCoordsVarying.x;//取出纹理坐标
floaty = TextureCoordsVarying.y;//取出纹理坐标
intwx =int(x / TB /length);//根据纹理坐标计算出对应的矩阵坐标 //即 矩阵坐标wx = int(纹理坐标x/ 矩阵长),矩阵长 = TB*len//即 矩阵坐标wy = int(纹理坐标y/ 矩阵宽),矩阵宽 = TR*len
intwy =int(y / TR /length);
vec2v1, v2, vn;
if(wx/2*2== wx) {//判断wx是否为偶数,等价于 wx % 2 == 0
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));
}
}
floats1 =sqrt(pow(v1.x - x,2.0) +pow(v1.y - y,2.0));
floats2 =sqrt(pow(v2.x - x,2.0) +pow(v2.y - y,2.0));
if(s1 < s2) {
vn = v1;
}else{
vn = v2;
}
vec4color =texture2D(Texture, vn);
gl_FragColor= color;
}
3.3三角形马赛克
三角形马赛克是由六边形马赛克演变而来,得到三角形的前提,就是的先有六边形,然后将正六边形6等分,每个三角形都是正三角形,然后求出纹理坐标与中心点的夹角,同时求出三角形的中心点,根据夹角判断,夹角属于哪个三角形,就将该三角形的中心点颜色作为整个三角形的纹素
precision highp float;
uniform sampler2D Texture;
varyingvec2TextureCoordsVarying;
floatmosaicSize =0.03;
voidmain (void){
constfloatTR =0.866025;
constfloatPI6 =0.523599;
floatx = TextureCoordsVarying.x;
floaty = TextureCoordsVarying.y;
intwx =int(x/(1.5* mosaicSize));
intwy =int(y/(TR * mosaicSize));
vec2v1, v2, vn;
if(wx /2*2== wx) {
if(wy/2*2== wy) {
v1 =vec2(mosaicSize *1.5*float(wx), mosaicSize * TR *float(wy));
v2 =vec2(mosaicSize *1.5*float(wx +1), mosaicSize * TR *float(wy +1));
}else{
v1 =vec2(mosaicSize *1.5*float(wx), mosaicSize * TR *float(wy +1));
v2 =vec2(mosaicSize *1.5*float(wx +1), mosaicSize * TR *float(wy));
}
}else{
if(wy/2*2== wy) {
v1 =vec2(mosaicSize *1.5*float(wx), mosaicSize * TR *float(wy +1));
v2 =vec2(mosaicSize *1.5*float(wx+1), mosaicSize * TR *float(wy));
}else{
v1 =vec2(mosaicSize *1.5*float(wx), mosaicSize * TR *float(wy));
v2 =vec2(mosaicSize *1.5*float(wx +1), mosaicSize * TR *float(wy+1));
}
}
floats1 =sqrt(pow(v1.x - x,2.0) +pow(v1.y - y,2.0));
floats2 =sqrt(pow(v2.x - x,2.0) +pow(v2.y - y,2.0));
if(s1 < s2) {
vn = v1;
}else{
vn = v2;
}
vec4mid =texture2D(Texture, vn);
floata =atan((x - vn.x)/(y - vn.y));
vec2area1 =vec2(vn.x, vn.y - mosaicSize * TR /2.0);
vec2area2 =vec2(vn.x + mosaicSize /2.0, vn.y - mosaicSize * TR /2.0);
vec2area3 =vec2(vn.x + mosaicSize /2.0, vn.y + mosaicSize * TR /2.0);
vec2area4 =vec2(vn.x, vn.y + mosaicSize * TR /2.0);
vec2area5 =vec2(vn.x - mosaicSize /2.0, vn.y + mosaicSize * TR /2.0);
vec2area6 =vec2(vn.x - mosaicSize /2.0, vn.y - mosaicSize * TR /2.0);
if(a >= PI6 && a < PI6 *3.0) {
vn = area1;
}elseif(a >= PI6 *3.0&& a < PI6 *5.0) {
vn = area2;
}elseif((a >= PI6 *5.0&& a <= PI6 *6.0)|| (a<-PI6 *5.0&& a>-PI6*6.0)) {
vn = area3;
}elseif(a < -PI6 *3.0&& a >= -PI6 *5.0) {
vn = area4;
}elseif(a <= -PI6 && a> -PI6 *3.0) {
vn = area5;
}elseif(a > -PI6 && a < PI6)
{
vn = area6;
}
vec4color =texture2D(Texture, vn);
gl_FragColor= color;
}
最后附上Demo:链接: https://pan.baidu.com/s/1S7m5OKJFi77FcqDVaAZ0DQ 提取码: isns 复制这段内容后打开百度网盘手机App,操作更方便哦