一.先看看整体效果
二.缩放
我们先来看看顶点着色器代码:
attribute vec4 Position;
attributevec2TextureCoords;
varyingvec2TextureCoordsVarying;
uniform float Time;
const float PI = 3.1415926;
voidmain (void) {
float duration =0.6;
float maxAmplitude =0.3;
floattime =mod(Time, duration);
floatamplitude =1.0+ maxAmplitude *abs(sin(time * (PI / duration)));
gl_Position=vec4(Position.x * amplitude, Position.y * amplitude, Position.zw);
TextureCoordsVarying = TextureCoords;
}
uniform float Time时间戳,根据时间刷新,maxAmplitude =0.3最大缩放幅度,const float PI = 3.1415926,也就是π,我们先看看三角函数:
在0-π的范围,sin函数从0-1,再1-0,可以形象的描述放大又回到原来大小的过程
说明:把π度分成一个时间周期duration份,算出这个模在对应的幅度值,最后用最大缩放乘以sin函数,得到缩放的顶点坐标,最后提交给gl_Position;//x,y 放⼤; z和w保存不变 gl_Position = vec4(Position.x * amplitude, Position.y * amplitude, Position.zw);
三.灵魂出窍
1.根据时间计算变换进度:floatprogress =mod(Time, duration) / duration
2.透明度跟随时间的变换而变化: floatalpha = maxAlpha * (1.0- progress);
3.计算缩放效果:floatscale =1.0+ (maxScale -1.0) * progress;
4.任意一点的纹理坐标(x,y)缩放计算:floatweakX =0.5+ (TextureCoordsVarying.x -0.5) / scale; floatweakY =0.5+ (TextureCoordsVarying.y -0.5) / scale;
任意一点的坐标以中心点为参考点
5.混合: vec2weakTextureCoords =vec2(weakX, weakY);
vec4weakMask =texture2D(Texture, weakTextureCoords);
vec4mask =texture2D(Texture, TextureCoordsVarying);
gl_FragColor= mask * (1.0- alpha) + weakMask * alpha;
四.抖动
抖动的效果实际就是放大缩小,在该效果上我们让单个的像素点产生一点偏移:floatoffset =0.02;(偏移量不应太大,否则显示的纹理不够美观,甚至变形)
floatduration =0.7;变换周期
floatmaxScale =1.1;最大变换
floatoffset =0.02;偏移
float progress =mod(Time, duration) / duration;// 0~1
vec2 offsetCoords =vec2(offset, offset) * progress;
float scale =1.0+ (maxScale -1.0) * progress;
vec2 ScaleTextureCoords =vec2(0.5,0.5) + (TextureCoordsVarying -vec2(0.5,0.5)) / scale;
vec4 maskR =texture2D(Texture, ScaleTextureCoords + offsetCoords);
vec4 maskB =texture2D(Texture, ScaleTextureCoords - offsetCoords);
vec4 mask =texture2D(Texture, ScaleTextureCoords);
gl_FragColor=vec4(maskR.r, mask.g, maskB.b, mask.a);混合
五.闪白
闪白的原理就是混合白色+透明度的改变:
floatduration =0.6;
floattime =mod(Time, duration);
vec4whiteMask =vec4(1.0,1.0,1.0,1.0);
floatamplitude =abs(sin(time * (PI / duration)));
vec4mask =texture2D(Texture, TextureCoordsVarying);
gl_FragColor= mask * (1.0- amplitude) + whiteMask * amplitude;
六.毛刺
mod函数计算时间周期:floattime =mod(Time, duration *2.0);
计算振幅,范围是「0, 1]:floatamplitude =max(sin(time * (PI / duration)),0.0);
获取像素点随机偏移值,范围是[-1,1]:floatjitter = rand(TextureCoordsVarying.y) *2.0-1.0;// -1~1
判断是否需要偏移 & 计算纹理的x坐标
需要偏移,撕裂较大,即x的颜色偏移较大
不需要,撕裂较小,即x的颜色偏移值很微小
获取撕裂后的纹理坐标
计算撕裂后的3组纹素,并获取不同组中的RGBA值
片元着色器代码:
precision highp float;
uniform sampler2D Texture;
varyingvec2TextureCoordsVarying;
uniform float Time;
const float PI = 3.1415926;
floatrand(floatn) {
returnfract(sin(n) *43758.5453123);
}
voidmain (void) {
floatmaxJitter =0.06;
floatduration =0.3;
floatcolorROffset =0.01;
floatcolorBOffset =-0.025;
floattime =mod(Time, duration *2.0);
floatamplitude =max(sin(time * (PI / duration)),0.0);
floatjitter = rand(TextureCoordsVarying.y) *2.0-1.0;// -1~1
boolneedOffset =abs(jitter) < maxJitter * amplitude;
floattextureX = TextureCoordsVarying.x + (needOffset ? jitter : (jitter * amplitude *0.006));
vec2textureCoords =vec2(textureX, TextureCoordsVarying.y);
vec4mask =texture2D(Texture, textureCoords);
vec4maskR =texture2D(Texture, textureCoords +vec2(colorROffset * amplitude,0.0));
vec4maskB =texture2D(Texture, textureCoords +vec2(colorBOffset * amplitude,0.0));
gl_FragColor=vec4(maskR.r, mask.g, maskB.b, mask.a);
}
七。幻觉滤镜
顶点着色器代码:
precision highp float;
uniform sampler2D Texture;//一次幻觉效果的时长,即周期
varyingvec2TextureCoordsVarying;
uniform float Time;
const float PI = 3.1415926;
constfloatduration =2.0;
//这个函数可以计算出,在某个时刻图片的具体位置,通过它可以每经过一段时间,去生成一个新的mask//转圈产生幻影的单个像素点的颜色值
vec4 getMask(floattime,vec2textureCoords,floatpadding) {
//圆心
vec2translation =vec2(sin(time * (PI *2.0/ duration)),
cos(time * (PI *2.0/ duration)));
//新的纹理坐标 = 原始纹理坐标 + 偏移量 * 圆周坐标(新的图层与图层之间是有间距的,所以需要偏移)
vec2 translationTextureCoords = textureCoords + padding * translation;
//根据新的纹理坐标获取新图层的纹素
vec4 mask =texture2D(Texture, translationTextureCoords);
return mask;
}
//这个函数可以计算出,某个时刻创建的层,在当前时刻的透明度//进度:
float maskAlphaProgress(floatcurrentTime,floathideTime,floatstartTime) {
//mod(时长+持续时间 - 开始时间,时长)得到一个周期内的time
float time =mod(duration + currentTime - startTime, duration);
//如果小于0.9,返回time,反之,返回0.9
return min(time, hideTime);
}
voidmain (void) {
//将传入的时间戳转换到一个周期内,time的范围是【0,2】//获得时间周期
float time =mod(Time, duration);
//放大后的倍数
float scale =1.2;
//偏移量 = 0.083
float padding =0.5* (1.0-1.0/ scale);
//放大后的纹理坐标
vec2 textureCoords =vec2(0.5,0.5) + (TextureCoordsVarying -vec2(0.5,0.5)) / scale;
//新建层的隐藏时间 即新建层什么时候隐藏
float hideTime =0.9;
//时间间隔:隔0.2s创建一个新层
float timeGap =0.2;
//注意:只保留了红色的透明的通道值,因为幻觉效果残留红色//幻影残留数据//max RGB alpha//新图层的 R透明度
float maxAlphaR =0.5;// max R
float maxAlphaG =0.05;// max G
float maxAlphaB =0.05;// max B
vec4 mask = getMask(time, textureCoords, padding);
//获取新的图层的坐标,需要传入时间、纹理坐标、偏移量
float alphaR =1.0;// R
float alphaG =1.0;// G
float alphaB =1.0;// B
//最终图层颜色:初始化
vec4resultMask =vec4(0,0,0,0);
//循环:每一层循环都会得到新的图层的颜色,即幻影颜色//一次循环只是计算一个像素点的纹素,需要在真机运行。模拟器会卡,主要是模拟器上是CPU模拟GPU的
for(float f =0.0; f < duration; f += timeGap) {
float tmpTime = f;
vec4 tmpMask = getMask(tmpTime, textureCoords, padding);
//某个时刻创建的层,在当前时刻的红绿蓝的透明度//临时的透明度 = 根据时间推移RGB的透明度发生变化//获得临时的红绿蓝透明度
float tmpAlphaR = maxAlphaR - maxAlphaR * maskAlphaProgress(time, hideTime, tmpTime) / hideTime;
float tmpAlphaG = maxAlphaG - maxAlphaG * maskAlphaProgress(time, hideTime, tmpTime) / hideTime;
float tmpAlphaB = maxAlphaB - maxAlphaB * maskAlphaProgress(time, hideTime, tmpTime) / hideTime;
//累计每一层临时RGB * RGB的临时透明度//结果 += 临时颜色 * 透明度,即刚产生的图层的颜色
result Mask +=vec4(tmpMask.r * tmpAlphaR,
tmpMask.g * tmpAlphaG,
tmpMask.b * tmpAlphaB,
1.0);
alpha R -= tmpAlphaR;
alpha G -= tmpAlphaG;
alpha B -= tmpAlphaB;
}
result Mask +=vec4(mask.r * alphaR, mask.g * alphaG, mask.b * alphaB,1.0);
gl_FragColor= resultMask;
}