“⻢赛克效果”就是把图⽚的⼀个相当⼤⼩的区域⽤同⼀个点的颜⾊来表示,可以认为是⼤规模的降低图像的分辨率,⽽让图像的⼀些细节隐藏起来。
precision highp float;
// 纹理坐标
uniform sampler2D Texture;
// 纹理采样器
varying vec2 TextureCoordsVarying;
// 纹理图片size
const vec2 TexSize = vec2(400.0, 400.0);
// 马赛克size
const vec2 MosaicSize = vec2(16.0, 16.0);
void main(){
// 计算实际图像位置
vec2 intXY = vec2(TextureCoordsVarying.x * TexSize.x, TextureCoordsVarying.y * TexSize.y);
// floor(x) 内建函数,返回小于/等于x最大的整数,即向下取整
// floor(intXY.x/mosaicSize.x)*mosaicSize.x 计算出一个小马赛克的坐标
vec2 XYMosaic = vec2(floor(intXY.x/MosaicSize.x)*MosaicSize.x, floor(intXY.y/MosaicSize.y)*MosaicSize.y);
// 换算回纹理坐标,此时的纹理坐标是小马赛克的部分的纹理坐标,即某一个色块
vec2 UVMosaic = vec2(XYMosaic.x/TexSize.x, XYMosaic.y/TexSize.y);
// 获取到马赛克后的纹理坐标的颜色值
vec4 color = texture2D(Texture, UVMosaic);
// 将马赛克颜色值赋值给gl_FragColor
gl_FragColor = color;
}
滤镜算法
precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;
// 六边形的边长
const float mosaicSize = 0.03;
void main() {
float length = mosaicSize;
// 矩形的高的比例为√3,取值 √3/2 ,也可以直接取√3
float TR = 0.866025;
// 矩形的长的比例为3,取值 3/2 = 1.5,也可以直接取3
float TB = 1.5;
// 取出纹理坐标
float x = TextureCoordsVarying.x;
float y = TextureCoordsVarying.y;
// 根据纹理坐标计算出对应的矩阵坐标
// 即矩阵坐标 wx = int(纹理坐标x/ 矩阵长),矩阵长 = TB*len
// 即矩阵坐标 wy = int(纹理坐标y/ 矩阵宽),矩阵宽 = TR*len
int wx = int(x / TB / length);
int wy = int(y / TR / length);
vec2 v1, v2, vn;
// 判断wx是否为偶数,等价于 wx % 2 == 0
if (wx/2 * 2 == wx) {
if (wy/2 * 2 == wy) {
// 偶行偶列 (0,0),(1,1)
v1 = vec2(length * TB * float(wx), length * TR * float(wy));
v2 = vec2(length * TB * float(wx+1), length * TR * float(wy+1));
} else {
// 偶行奇列 (0,1),(1,0)
v1 = vec2(length * TB * float(wx), length * TR * float(wy+1));
v2 = vec2(length * TB * float(wx+1), length * TR * float(wy));
}
}else{
if (wy/2 * 2 == wy) {
// 奇行偶列 (0,1),(1,0)
v1 = vec2(length * TB * float(wx), length * TR * float(wy+1));
v2 = vec2(length * TB * float(wx+1), length * TR * float(wy));
} else {
// 奇行奇列 (0,0),(1,1)
v1 = vec2(length * TB * float(wx), length * TR * float(wy));
v2 = vec2(length * TB * 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));
// 选择距离小的则为六边形的中心点,且获取它的颜色
vn = (s1 < s2) ? v1 : v2;
// 获取六边形中心点的颜色值
vec4 color = texture2D(Texture, vn);
gl_FragColor = color;
}
三角形滤镜算法是在六边形滤镜算法的步骤上再增加以下步骤:
precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;
float mosaicSize = 0.03;
void main (void) {
const float TR = 0.866025;
const float PI6 = 0.523599;
float x = TextureCoordsVarying.x;
float y = TextureCoordsVarying.y;
int wx = int(x/(1.5 * mosaicSize));
int wy = int(y/(TR * mosaicSize));
vec2 v1, 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));
}
}
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 mid = texture2D(Texture, vn);
// 获取像素点与中心点的角度
float a = atan((x - vn.x)/(y - vn.y));
// 判断夹角,属于哪个三角形,则获取哪个三角形的中心点坐标
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
gl_FragColor = color;
}
GLSL滤镜之马赛克滤镜效果实现