随同着赛博朋克2077的火爆(各种意义上的),这种电子故障类的shader仿佛成为了一种时尚,因为你真不知道这是bug还是无意为之。明天咱们就来了了几款故障类shader的原理及实现吧!本期将介绍2种shader(色彩偏移与扫描偏移)下期咱们再说两种(抖动和摇摆),正当应用这四种shader你可能实现上面短片中的成果:

色彩偏移

最终成果

咱们都晓得,图片是由RGB三个通道的色彩叠加起来而成的。R+G失去黄,R+B失去洋红,G+B是青。

色彩偏移的原理就是把其中一个通道偏移一个间隔在叠加起来。比方挪动绿色通道:

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是横向偏移的间隔:

是不是you点抖音的感觉?那么为什么同种呈现的色彩是洋红和绿??那是因为咱们挪动了绿通道,而洋红就是剩下的蓝通道和红通道叠加的后果。这里咱们能够试验一下,如果挪动红通道。失去的抖动色彩就会是红色和青色:

gl_FragColor =vec4(color2.r, color1.g, color1.b,1.0);

扫描射线

这种成果会在产生逐条的偏移,相似小时候电视机调台时那种感觉(裸露年龄了)

这里咱们须要一个随机函数对不同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是一个很大的数时结构出出一种随机:

这种理念在须要生成躁点的shader中非常常见,再配合smoothstep,step,u_time能够写出很多难以置信的成果,当前咱们会常常遇到。

此时在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感兴趣,也能够看看上面的文章: