Shader特效——“Invaders Invaders(火星文雨)效果”的实现 【GLSL】

发表于2018-02-07
评论0 3.7k浏览
本篇文章给大家介绍下如果使用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);  
}  

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引