GPUImagePixellateFilter
马赛克滤镜。
我们先来看mod函数的定义:
m o d ( x , y ) = x − y ∗ f l o o r ( x y ) mod(x,y) = x - y * floor(\frac xy) mod(x,y)=x−y∗floor(yx)
假设 y = 1 y=1 y=1,即 m o d ( x , 1 ) = x − 1 ∗ f l o o r ( x 1 ) mod(x,1)= x - 1 * floor(\frac x{1}) mod(x,1)=x−1∗floor(1x),生成图像如下:
从图像中可以看出mod(x,y)
的结果增量和x
的增量在变量周期范围内是相同的。所以对于下面的代码:
vec2 uv = fragCoord/iResolution.xy;
// 马赛克的尺寸
vec2 sampleFactor = vec2(.05,.05);
// 采样位置
vec2 samplePos= uv - mod(uv,sampleFactor);
fragColor = texture(iChannel0,samplePos);
samplePos
在一个采样周期内是不变的,samplePos
始终等于每一个采样周期开始时uv
的值。
使用 mod函数还可以生成黑白马赛克:
vec2 uv = fragCoord/iResolution.xy;
float m = mod(floor(uv.x * 10.) + floor(uv.y * 10.),2.);
vec3 col = vec3(0.);
col += m;
fragColor = vec4(col,1.0);
GPUImagePixellatePositionFilter
环形范围马赛克滤镜。
有了上面的分析,GPUImagePixellatePositionFilter
的实现就很简单了:
vec2 uv = fragCoord/iResolution.xy;
// 获取和中心点的距离
float d = length(uv - .5);
// 环形半径为0.3
if (d < 0.3){ // 显示马赛克
// 马赛克的尺寸
vec2 sampleFactor = vec2(.05,.05);
// 采样位置
vec2 samplePos= uv - mod(uv,sampleFactor);
fragColor = texture(iChannel0,samplePos);
}else{
// 显示原图像
fragColor = texture(iChannel0,uv);
}
GPUImagePolarPixellateFilter
旋转马赛克滤镜。
上述两种马赛克的实现都是在纹理
坐标下生成的,这次要在极坐标
下来生成马赛克。
纹理坐标 转 极坐标
// 坐标范围扩充为 [-1,1]
vec2 uv = (2. * fragCoord - iResolution.xy)/iResolution.xy;
// 利用反正切函数获取角度 θ 范围 [-π,π]
float phi = atan(uv.y,uv.x);
// 获取半径 r
float r = length(uv);
// 获取x、y
uv.x = r * cos(phi);
uv.y = r * sin(phi);
在极坐标下可以绘制出很多漂亮的图形,如三叶草:
在极坐标下绘制马赛克即是旋转形态的马赛克。
// [-1,1]
vec2 uv = (2. * fragCoord - iResolution.xy)/iResolution.xy;
float r = length(uv);
float phi = atan(uv.y,uv.x);
// 采样像素
float samplePixel = 0.05;
// 加0.03是防止 r = 0时 留出空白区域
r = r - mod(r,samplePixel) + 0.03;
phi = phi - mod(phi,samplePixel);
uv.x = r * cos(phi);
uv.y = r * sin(phi);
// (uv * 0.5 + 0.5):水平和垂直方向扩大2倍并向左下角移动0.5个单位长度
fragColor = texture(iChannel0,uv * 0.5 + 0.5);
总结
在马赛克的绘制中mod函数起到了很关键的作用,谨记之。