Shader特效——“Invaders Invaders(火星文雨)效果”的实现 【GLSL】
发表于2018-02-07
本篇文章给大家介绍下如果使用GLSL代码实现一个Invaders Invaders(火星文雨)的shader效果。
效果图:

GLSL代码及算法注释:
uniform float iGlobalTime;
uniform vec2 iMouse;
vec2 iResolution = vec2(512., 512.);
vec3 color = vec3(0.6, 0.1, 0.3); // red
// 一元随机函数
float rand(float x)
{
return fract(sin(x) * 4358.5453123);
}
// 二元随机函数
float rand(vec2 co)
{
return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5357);
}
// 火星文算法 —— _(┐「ε:)_
float invader(vec2 p, float n)
{
p.x = abs(p.x);
p.y = floor(p.y - 5.0);
// 2^x
float tmp = exp2(floor(p.x - 3.0 * p.y));
return step(p.x, 2.0)
* step(1.0, floor( mod(n / tmp, 2.0) ));
}
float ring(vec2 uv, float rnd)
{
float t = 0.6 * (iGlobalTime + 0.2 * rnd);
float i = floor(t / 2.0); // 确保圆心在某时间范围内不变
// 随机圆心位置
vec2 pos = 2.0 * vec2(rand(i * 0.123), rand(i * 2.371)) - 1.0;
// 动态放大半径:
// length(uv - pos)表示圆,t在增大,需要更大的uv才使得 diff 为 0,
// t有一定的随机性,可以实现圆环的闪烁效果
float diff = length(uv - pos) - mod(t, 2.0);
return 1. - smoothstep(0.0, 0.2, abs(diff) );
}
void main()
{
if (iMouse.x > 0.5)
color = vec3(0.2, 0.42, 0.68);
vec2 p = gl_FragCoord.xy;
vec2 xy = gl_FragCoord.xy / iResolution.xy;
vec2 uv = p / iResolution.xy - 0.5;
p.y += 120.0*iGlobalTime; // 下落的速度
float r = rand(floor(p/8.0)); // 控制火星文和光环的随机闪烁
// 用于生成火星文
vec2 ip = mod(p, 8.0) - 4.0;
// 背景中心到四周的颜色渐变
float a = -.2 * smoothstep(0.1, 0.8, length(uv));
// invader * 光环
float b = invader(ip, 809999.0*r) * (0.06 + 0.3*ring(uv,r));
// 火星文雨的闪烁高光
float c = color * invader(ip, 809999.0*r) * max(0.0, 0.2*sin(10.0*r*iGlobalTime));
a += b;
a += c;
gl_FragColor = vec4( color + vec3(a), 1.0);
}
简单的改造:

Desktop Wallpaper效果:
参考自:https://www.shadertoy.com/view/4dcGRn
效果图:

GLSL代码及算法注释:
// Desktop Wallpaper, fragment shader by movAX13h, Nov.2015
#define INVADERS 1
vec3 color = vec3(0.2, 0.42, 0.68); // blue 1
//vec3 color = vec3(0.1, 0.3, 0.6); // blue 2
//vec3 color = vec3(0.6, 0.1, 0.3); // red
//vec3 color = vec3(0.1, 0.6, 0.3); // green
float width = 32.0; // n = 512/32 = 16
float rand(float x) { return fract(sin(x) * 4358.5453); }
float rand(vec2 co) { return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 3758.5357); }
#ifdef INVADERS
float invader(vec2 p, float n)
{
p.x = abs(p.x);
p.y = -floor(p.y - 5.0);
//return step(p.x, 2.0) ;
//return floor(p.x + p.y*3.0);
//return n/exp2(floor(p.x + p.y*3.0));
//return mod(n/exp2(floor(p.x + p.y*3.0)), 2.);
//return floor(mod(n/exp2(floor(p.x + p.y*3.0)), 2.));
//return step(1.0, floor(mod(n/(exp2(floor(p.x + p.y*3.0))),2.0)));
return step(p.x, 2.0) * step(1.0, floor(mod(n/(exp2(floor(p.x + p.y*3.0))),2.0)));
}
#endif
uniform float time;
const vec2 iResolution = vec2(512., 512.);
void main()
{
vec2 p = gl_FragCoord.xy;
vec2 uv = p / iResolution.xy - 0.5;
float id1 = rand(floor(p.x / width)); // 影响当前像素(矩形内)的颜色
float id2 = rand(floor((p.x - 1.0) / width)); // 影响其邻近左侧像素的颜色
float a = 0.3*id1; // 当前矩形的颜色
a += 0.1*step(id2, id1 - 0.08); // 矩形左边界(如果当前像素比左侧淡,则亮边界)
a -= 0.1*step(id1 + 0.08, id2); // 矩形右边界(如果当前像素比左侧深,则亮边暗)
a -= 0.3*smoothstep(0.0, 0.7, length(uv)); // 渐变效果
#ifdef INVADERS
p.y += 20.0*time;
float r = rand(floor(p/8.0));
float inv = invader(mod(p,8.0)-4.0, 809999.0*r);
a += (0.06 + max(0.0, 0.2*sin(10.0*r*time))) * inv * step(id1, .3); // 分段显示invaders
//a += (0.06 + max(0.0, 0.2*sin(10.0*r*time))) * inv;
#endif
gl_FragColor = vec4(color+a, 1.0);
}
