几款2077风格的shader(其一)【sh风ader格化】

伴随着赛博朋克2077的火爆(各类意义上的),这种电子故障类的shader彷佛成为了一种时尚,由于你真不知道这是bug仍是有意为之。今天咱们就来了了几款故障类shader的原理及实现吧!本期将介绍2种shader(颜色偏移与扫描偏移)下期咱们再说两种(抖动和摇晃),合理使用这四种shader你可以实现下面短片中的效果:segmentfault

image

颜色偏移

最终效果函数

咱们都知道,图片是由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感兴趣,也能够看看下面的文章:

相关文章
相关标签/搜索