幾款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感興趣,也能夠看看下面的文章:

相關文章
相關標籤/搜索