伴随着赛博朋克2077的火爆(各类意义上的),这种电子故障类的shader彷佛成为了一种时尚,由于你真不知道这是bug仍是有意为之。今天咱们就来了了几款故障类shader的原理及实现吧!本期将介绍2种shader(颜色偏移与扫描偏移)下期咱们再说两种(抖动和摇晃),合理使用这四种shader你可以实现下面短片中的效果:segmentfault
最终效果函数
咱们都知道,图片是由RGB三个通道的颜色叠加起来而成的。R+G获得黄,R+B获得洋红,G+B是青。工具
颜色偏移的原理就是把其中一个通道偏移一个距离在叠加起来。好比移动绿色通道:spa
void main () { // Color drift float drift = sin ( u_time) * u_colorDrift * .04; // Offset vec2 offset = vec2(drift,.0); vec4 color1 = texture2D (u_image0, uv); vec4 color2 = texture2D (u_image0, uv + offset); gl_FragColor = vec4 (color1.r, color2.g, color1.b, 1.0); }
其中u_time是当前时间,保证持续抖动,u_colorDrift是横向偏移的距离:code
是否是you点抖音的感受?那么为何同种出现的颜色是洋红和绿??那是由于咱们移动了绿通道,而洋红就是剩下的蓝通道和红通道叠加的结果。这里咱们能够实验一下,若是移动红通道。获得的抖动颜色就会是红色和青色:orm
gl_FragColor =vec4(color2.r, color1.g, color1.b,1.0);
这种效果会在产生逐条的偏移,相似小时候电视机调台时那种感受(暴露年龄了)blog
这里咱们须要一个随机函数对不一样y进行不一样的偏移(图中能够看出,对y方向相同的点偏移是一致的)。这里咱们须要一个hash函数:图片
float hash21 (float x, float y) { return fract (sin (dot (vec2 (x, y), vec2 (12.9898, 78.233))) * 43758.5453); }
核心思想是经过fract(sin(x)*a)当a是一个很大的数时构造出出一种随机:ci
这种理念在须要生成躁点的shader中十分常见,再配合smoothstep,step,u_time能够写出不少难以置信的效果,之后咱们会常常遇到。rem
此时在main函数中咱们已经能够完成代码逻辑了:
void main(){ float y = uv.y; float jitter = hash21 (y, .0) * 2. - 1.; vec2 offset = fract (vec2 (uv.x + jitter, .0)); vec4 color = texture2D (u_image0, offset); gl_FragColor = color; }
offset加上fract是保证偏可以连续:
图中上为没有加fract的效果,下为加了fract的效果,咱们使用扫描偏移时,因为不至于偏移到半个屏幕,因此不加fract效果也未必很明显,但后面说的两种属性(抖动和摇晃)是很容易移动半个屏幕的,因此必须加上fract。
最后因为咱们须要经过参数控制扫描射线效果,因此咱们还须要加上一个阀门函数。
jitter *= step (u_scan,abs (jitter)) ;
其中step函数,用于尖锐的过分,y = step(a,x)当x大于a时y=1;不然等于0:
a等于0.5时
调换x与a的顺序相反:
咱们来分析一下step (u_scan, abs (jitter));由于 abs (jitter)是一个值域介于0-1,当u_scan趋近于0时,step (u_scan, abs (jitter))就更大几率等于1;当u_scan趋近于1时,step (u_scan, abs (jitter))就更大几率等于0;
因此经过控制u_scan的值就能控制,jitter *= step (u_scan,abs (jitter)) 输出随机数的稠密程度:
u_scan分别取0,0.5,0.9时函数的稠密程度(取1就彻底归零了,有兴趣的小伙伴能够试试)。可是咱们实习完u_scan在0的时候最小,1的时候最大。这个效果正好与咱们所指望的相反。因此咱们还须要再添加一个函数
float scan = clamp (1.0 - u_scan * 1.2, 0., 1.); jitter *= step (scan, abs (jitter));
其实这里用float scan = 1.0 - u_scan也是能够的。clamp函数只是保证输出在[0,1]之间。
最后咱们把上面两个效果合并:
precision mediump float; /* 变量申明 */ varying vec2 uv; uniform sampler2D u_image0; uniform float u_scan; uniform float u_colorDrift; uniform float u_time; /* 工具函数 */ float hash21 (float x, float y) { return fract (sin (dot (vec2 (x, y), vec2 (12.9898, 78.233))) * 43758.5453); } void main () { float x = uv.x; float y = uv.y; // Scan line jitter float jitter = hash21 (y, u_time) * 2. - 1.; float scan = clamp (1.0 - u_scan * 1.2, 0., 1.); jitter *= step (u_scanY, abs (jitter)) ; // Color drift float drift = sin (u_time * 666. + jump) * u_colorDrift * .04; // Offset vec2 offset1 = fract (vec2 (uv.x + jitter , 0.)); vec2 offset2 = fract (vec2 (uv.x + jitter + drift , 0.)); vec4 color1 = texture2D (u_image0, offset1); vec4 color2 = texture2D (u_image0, offset2); gl_FragColor = vec4 (color1.r, color2.g, color1.b, 1.0); }
下期咱们来讲说横向和纵向的抖动和摇晃吧。
相关文章:
热成像
像素风
若是你对shader感兴趣,也能够看看下面的文章: