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值来实现:
- 前三种属于权值法:处理后的图片比较逼真
- 浮点算法:
Gray = R * 0.3 + G * 0.59 + B * 0.11
【RGB的权重总和为1】 - 整数⽅法:
Gray = ( R * 30 + G * 59 + B * 11) / 100
【RGB的权重总和为100】 - 移位⽅法:
Gray = ( R * 76 + G * 151 + B* 28) >> 8
- 平均值法:
Gray = ( R + G + B ) / 3
【处理后的图片比较柔和】 - 仅取绿⾊:
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个不同颜色,现在只用一个颜色填充,整张图片看下来就模糊了。
步骤:
- 先把原图按我们设置的比例放大
- 根据比例计算每一个马赛克的大小,获得一个区域
- 把马赛克区域根据比例缩小,就拿到了原纹理图片中的位置
- 给这一个区域填充颜色
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个正三角形。
- 计算某一个像素点和中心点直接的夹角
- 求出6个正三角形的中心点
- 判断这个夹角属于哪个正三角形,就取哪个正三角形的颜色值
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;
}
网友评论