一、灰度滤镜
灰度滤镜的几种算法
- 浮点算法:
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;
示例1:仅取G值法,片元着色器代码:
precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;
void main()
{
vec4 mask = texture2D(Texture, TextureCoordsVarying);
gl_FragColor = vec4(mask.g, mask.g, mask.g, 1.0);
}
示例2:浮点算法,片元着色器代码:
precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;
const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);
void main()
{
vec4 mask = texture2D(Texture, TextureCoordsVarying);
float luminance = dot(mask.rgb, W);
gl_FragColor = vec4(vec3(luminance), 1.0);
}
另外,测试发现改变rgb的值也可实现类似其他颜色的滤镜,例如下面的代码会显示绿色
precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;
const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);
void main()
{
vec4 mask = texture2D(Texture, TextureCoordsVarying);
float r = mask.r * W.x;
float g = mask.g * W.y;
float b = mask.b * W.z;
gl_FragColor = vec4(vec3(r,g,b), 1.0);
}
二、浮雕滤镜
浮雕滤镜,片元着色器代码
precision mediump float;
varying vec2 TextureCoordsVarying;
uniform sampler2D Texture;
const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);
const vec2 TexSize = vec2(100.0, 100.0);
const vec4 bkColor = vec4(0.5, 0.5, 0.5, 1.0);
void main()
{
vec2 upLeftUV = vec2(TextureCoordsVarying.x-1.0/TexSize.x, TextureCoordsVarying.y-1.0/TexSize.y);
vec4 curColor = texture2D(Texture, TextureCoordsVarying);
vec4 upLeftColor = texture2D(Texture, upLeftUV);
vec4 delColor = curColor - upLeftColor;
float luminance = dot(delColor.rgb, W);
gl_FragColor = vec4(vec3(luminance), 0.0) + bkColor;
}
三、漩涡滤镜
图像漩涡主要是在某个半径范围里,把当前采样点旋转一定⻆度,旋转以后当前点的颜⾊就被旋转后的点的颜色代替,因此整个半径范围里会有旋转的效果。如果旋转的时候旋转⻆度随着当前点离半径的距离递减,整个图像就会出现漩涡效果。这⾥使⽤的了抛物线递减因⼦:(1.0-(r/Radius)*(r/Radius))
。
漩涡滤镜着色器代码
precision mediump float;
//PI
const float PI = 3.14159265;
//纹理采样器
uniform sampler2D Texture;
//旋转角度
const float uD = 100.0;
const float uR = 0.6;
//纹理坐标
varying vec2 TextureCoordsVarying;
void main()
{
//旋转正方形范围(测试好像不起作用)
ivec2 ires = ivec2(512, 512);
//获取旋转的直径
float Res = float(ires.s);
//纹理坐标
vec2 st = TextureCoordsVarying;
//获取 半径 = 直径 * 0.5
float Radius = Res * uR;
//准备旋转处理的纹理坐标 = 纹理坐标 * 直径
vec2 xy = Res * st;
//纹理坐标的一般
vec2 dxy = xy - vec2(Res/2., Res/2.);
float r = length(dxy);
//抛物线递减因子(1.0 - (r/Radius)*(r/Radius))
float attenValue = (1.0 - (r/Radius)*(r/Radius));
//当前角度
//tanθ=y/x , atan(T y, T x)
//加剧漩涡角度
//float beta = atan(dxy.y, dxy.x);
//加剧漩涡衰减角度
//float beta = atan(dxy.y, dxy.x)+ radians(uD) * 2.0;
float beta = atan(dxy.y, dxy.x) + radians(uD) * 2.0 * attenValue;
if(r <= Radius)
{
//获取纹理坐标旋转beta度
xy = Res/2.0 + r * vec2(cos(beta), sin(beta));
}
//st = 旋转后的纹理坐标/旋转范围
st = xy/Res;
//将旋转的纹理坐标替换原始纹理坐标TextureCoordsVarying 获取对应像素点的颜色
vec3 irgb = texture2D(Texture, st).rgb;
//将计算后的颜色填充到像素点中
gl_FragColor = vec4( irgb, 1.0);
}
注:这是一份带注释的代码块,如果着色器程序编译失败,则删除代码中的注释再试一次。
另外测试发现旋转正方形范围不起作用ivec2 ires = ivec2(512, 512);
本例中旋转角度uD
影响形变量uR
影响形变范围
马赛克滤镜
马赛克效果就是把图片的一个相对大小的区域用同一个点的颜色来表示。可以认为是大规模的降低图像的分辨率,而让图像的一些细节隐藏起来。
四、矩形马赛克滤镜
矩形马赛克,片元着色器代码
precision highp float;
//纹理采样器
uniform sampler2D Texture;
//纹理坐标
varying vec2 TextureCoordsVarying;
//纹理图片size
const vec2 TextSize = vec2(400.0, 400.0);
//马赛克size
const vec2 mosaicSize = vec2(16.0, 16.0);
void main()
{
//计算实际图像位置
vec2 intXY = vec2(TextureCoordsVarying.x * TextSize.x, TextureCoordsVarying.y * TextSize.y);
//floor(x) 内键函数,返回小于/等于x的最大整数值
vec2 XYMosaic = vec2(floor(intXY.x/mosaicSize.x)*mosaicSize.x, floor(intXY.y/mosaicSize.y)*mosaicSize.y);
//换算回纹理坐标
vec2 UVMosaic = vec2(XYMosaic.x/TextSize.x, XYMosaic.y/TextSize.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 len = mosaicSize;
float TR = 0.866025;
float x = TextureCoordsVarying.x;
float y = TextureCoordsVarying.y;
int wx = int(x / 1.5 / len);
int wy = int(y / TR / len);
vec2 v1, v2, vn;
if (wx/2 * 2 == wx) {
if (wy/2 * 2 == wy) {
v1 = vec2(len * 1.5 * float(wx), len * TR * float(wy));
v2 = vec2(len * 1.5 * float(wx + 1), len * TR * float(wy + 1));
}else {
v1 = vec2(len * 1.5 * float(wx), len * TR * float(wy + 1));
v2 = vec2(len * 1.5 * float(wx + 1), len * TR * float(wy));
}
}else {
if (wy/2 * 2 == wy) {
v1 = vec2(len * 1.5 * float(wx), len * TR * float(wy + 1));
v2 = vec2(len * 1.5 * float(wx + 1), len * TR * float(wy));
}else {
v1 = vec2(len * 1.5 * float(wx), len * TR * float(wy));
v2 = vec2(len * 1.5 * float(wx + 1), len * 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;
}
六、三角形马赛克滤镜
三角形马赛克,片元着色器代码
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 = color;
}
七、圆形马赛克滤镜
圆形马赛克,片元着色器代码
precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;
const vec2 TextSize = vec2(400.0, 400.0);
const vec2 mosaicSize = vec2(16.0, 16.0);
void main()
{
vec2 intXY = vec2(TextureCoordsVarying.x * TextSize.x, TextureCoordsVarying.y * TextSize.y);
vec2 XYMosaic = vec2(floor(intXY.x/mosaicSize.x)*mosaicSize.x, floor(intXY.y/mosaicSize.y)*mosaicSize.y) + 0.5*mosaicSize;
vec2 delXY = XYMosaic - intXY;
float delL = length(delXY);
vec2 UVMosaic = vec2(XYMosaic.x/TextSize.x, XYMosaic.y/TextSize.y);
vec4 _finialColor;
if(delL < 0.5*mosaicSize.x) {
_finialColor = texture2D(Texture, UVMosaic);
}else {
_finialColor = texture2D(Texture, TextureCoordsVarying);
}
gl_FragColor = _finialColor;
}
代码下载https://github.com/SPIREJ/OpenGLES_GLSL