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); }