「这是我参与2022首次更文挑战的第22天,活动详情查看:2022首次更文挑战」
毛刺
毛刺效果实现原理是通过修改纹理坐标产生随机偏移量。但是产生偏移左右偏移的量是微小的并且是个别y轴上的像素需要发生偏移。因此需要设置一个随机数生成器,设定一个闸值,这个闸值应该是比较小的并且小于闸值才能进行偏移。
const float PI = 3.1415926;
float rand(float n) {
return fract(sin(n) * 43758.5453123);
}
void main() {
vec2 uv = gl_FragCoord.xy / iResolution.xy;
//最大抖动上限
float maxJitter = 0.06;
//一次毛刺效果的时长
float duration = 0.3;
//红色颜色偏移
float colorROffset = 0.01;
//绿色颜色偏移
float colorBOffset = -0.025;
float time = mod(iTime, duration * 2.0);
//振幅,随着时间变化,范围是[0, 1]
float amplitude = max(sin(time * (PI / duration)), 0.0);
//像素随机偏移范围 [-1,1]
float jitter = rand(uv.y) * 2.0 - 1.0; // -1~1
//判断是否需要偏移,如果jitter范围 < 最大范围*振幅
bool needOffset = abs(jitter) < maxJitter * amplitude;
float textureX = uv.x + (needOffset ? jitter : (jitter * amplitude * 0.006));
vec2 textureCoords = vec2(textureX, uv.y);
vec4 mask = texture(iChannel1, textureCoords);
vec4 maskR = texture(iChannel1, textureCoords + vec2(colorROffset * amplitude, 0.0));
vec4 maskB = texture(iChannel1, textureCoords + vec2(colorBOffset * amplitude, 0.0));
gl_FragColor = mask;
}
毛刺效果同时增加上色差效果,最终呈现效果为最佳。
vec4 mask = texture(iChannel1, textureCoords);
vec4 maskR = texture(iChannel1, textureCoords + vec2(colorROffset * amplitude, 0.0));
vec4 maskB = texture(iChannel1, textureCoords + vec2(colorBOffset * amplitude, 0.0));
gl_FragColor = vec4(maskR.r, mask.g, maskB.b, mask.a);
灵魂出窍
灵魂出窍效果实现原理是通过两个纹理叠加,根据时间上层纹理做缩放并且不断变化其不透明度来逐渐显现。之前在缓动函数介绍中已经知道如何实现缩放效果,灵魂出窍效果就是在其基础之上再多个纹理对象叠加就能够实现了。
void main() {
vec2 uv = gl_FragCoord.xy / iResolution.xy;
// 持续时间
float duration = 0.7;
// 最大透明度
float maxAlpha = 0.4;
// 最大缩放系数
float maxScale = 1.8;
// 时间
float progress = mod(iTime, duration) / duration; // 0~1
// 当前透明度
float alpha = maxAlpha * (1.0 - progress);
// 当前缩放值
float scale = 1.0 + (maxScale - 1.0) * progress;
// 中心位置
float weakX = 0.5 + (uv.x - 0.5) / scale;
float weakY = 0.5 + (uv.y - 0.5) / scale;
vec2 weakTextureCoords = vec2(weakX, weakY);
// 放大后的纹理
vec4 weakMask = texture(iChannel1, weakTextureCoords);
vec4 mask = texture(iChannel1, uv);
// 纹理叠加
gl_FragColor = mask * (1.0 - alpha) + weakMask * alpha;
}
故障
故障效果其实有点像是毛刺效果的衍生。毛刺效果偏移数较多且每个偏移高度都比较小,故障效果的偏移高度会更大一些。除此之外毛刺采用一维随机函数而故障效果是利用二维随机函数。同样是通过随机函数生成需要被偏移的Y轴并且通过闸值函数判断是否进行偏移操作。
//2D随机数生成器
float random2d(vec2 n) {
return fract(sin(dot(n, vec2(12.9898, 4.1414))) * 43758.5453);
}
float randomRange (in vec2 seed, in float min, in float max) {
return min + random2d(seed) * (max - min);
}
// 判断闸值函数 是否在故障内
float insideRange(float v, float bottom, float top) {
return step(bottom, v) - step(top, v);
}
float AMT = 0.1; //故障数 0-1. 最大10
float SPEED = 0.2; //0 - 1 speed
void main() {
vec2 uv = gl_FragCoord.xy / iResolution.xy;
vec3 outCol = texture(iChannel1, uv).rgb;
float time = floor(iTime * SPEED * 60.0);
float maxOffset = AMT/2.0;
vec2 uvOff = uv;
float hOffset = 0.;
for (float i = 0.0; i < 10.0 * AMT; i += 1.0) {
float sliceY = random2d(vec2(time , 2345.0 + float(i)));
float sliceH = random2d(vec2(time , 9035.0 + float(i))) * 0.25;
hOffset = randomRange(vec2(time , 9625.0 + float(i)), -maxOffset, maxOffset);
uvOff.x += hOffset;
// 判断是否在故障内 在故障中就需要对x轴做偏移操作
if (insideRange(uv.y, sliceY, fract(sliceY+sliceH)) == 1.0){
outCol = texture(iChannel1, uvOff).rgb;
}
}
gl_FragColor = vec4(outCol,1.0);
}
只有故障偏移好像看起来效果并不凸显,同时再结合色差偏移达到特效最佳效果。
outCol.r = texture(iChannel1, uvOff + vec2(colorROffset + hOffset, 0.0)).r;
outCol.b = texture(iChannel1, uvOff + vec2(colorBOffset + hOffset, 0.0)).b;