GLSL 的各種着色器效果


Site Defunct

注意!截止到 16/9/2019 ,這個博客已經被搬遷到了 這里 。以后我的東西都會發在那里。拜拜啦!

GLSL 的各種着色器效果

從 SR 來的 Map!

GLSL 很牛逼

首先,我要說的是,GLSL 很牛逼。我知道大家都知道,但是今天我就來給大家展示一哈我為了我那個作業做的着色器(們),其中有很大一部分都是從 ShaderToy 上參考的!

Vignette

Vignette 我不知道咋翻譯,他的中文是小插圖?這也太奇怪了吧…… 但是總而言之,我們是可以知道 Vignette 的作用是可以讓遠離中心的地方(屏幕邊緣)變黑,然后整個看起來就有點像 70 年代的電影一樣的東西:

vignette

這個着色器一般在靜物,或者是復古的六七十年代的東西的時候渲染起來效果很好。他的原理很簡單,就是遠離中心的就變黑:

vec2 uv = 1.0 - uv.yx;
float vig = uv.x * uv.y * 15.0; // 15.0 是 intensity vig = pow(vig, 0.2);

gl_FragColor = vec4(pixel * vig, 1.0);

其中,intensity 的作用就是讓結果曝光,如果太大會過度曝光,而太小又會太暗。在 intensity 的下一行的 0.2 可以說是擴大范圍,如果這個數字越大,暗的范圍就越大。最后,用輸出的像素和 vignette 值相乘就可以了。

ScanLine

ScanLine 就是掃描線。在老機器里面,掃描線經常是清晰可見的。現在由於科技呀,他進步了,掃描線就沒了。但是假如還是為了這個美感的話,我們很容易用現代的,數學的方法把以前的 缺陷 給渲染出來。

scanline!

實現 ScanLine 的方法有很多種。我這里用我自個兒的,其實不大高效,因為用了 if 。

vec2 realUV = vec2(uv.x * resolution.x, uv.y * resolution.y); // gl_FragCoord pixel.rgb -= (
    mod(realUV.y, 2.0) <= 1.0 ? 
    0.1 :
    0.0
);

gl_FragColor = vec4(pixel, 1.0);

這個賊明顯,就是看看 realUV (gl_FragCoord) 的 y 值對 2 取余。如果是 1.0 的話,就直接把對應的像素哪一行 變暗

假如你喜歡的話,可以把 time 加上去,這樣掃描線就會一直往下(上)移動:

vec2 realUV = vec2(uv.x * resolution.x, uv.y * resolution.y); // gl_FragCoord pixel.rgb -= (
    mod(realUV.y + ceil(time * <移速>), 2.0大專欄  GLSL 的各種着色器效果 class="p">) <= 1.0 ? 
    0.1 :
    0.0
);

gl_FragColor = vec4(pixel, 1.0);

你想掃描線移多快,就自個兒調移速吧。我覺得 20.0 還不錯的。

實現掃描線的方法還有很多種。我找到的有 這種這種 ,還有 這種是我參考的做法

Pixelate

Pixelate 是像素化的意思。我 ShaderToy 上沒找到,自個兒想的。如果有的話可以告訴我一哈,三克油!

像素化!!

我的做法其實很簡單。我把屏幕分成比分辨率更小的小塊,然后判斷要渲染的點在哪個小塊里頭,對應采樣那個小塊的左上角的那個像素。(也就是強行下降分辨率):

vec2 realUV = vec2(uv.x * resolution.x, uv.y * resolution.y); // gl_FragCoord vec2 fakeUV = floor(realUV / 8.0) * 8.0;
vec2 uv = fakeUV / resolution.xy;
vec4 pixel = texture2D(texture, uv);

可以看到,我們就是把真實坐標除了 8.0 以后,舍掉了一切的小數點,然后把他恢復成了原來的坐標。帥不?

Frosted Glass

還記得 Windows7 Aero 的酷炫毛玻璃效果嗎?現在咱們也能大概實現它的效果啦!看回來我們的頭圖:

從 SR 來的 Map!

看到了嗎?下面的對話框那里就是毛玻璃的效果。

其實毛玻璃的效果不難,就是瞎取樣。這個來自 這里 。我們來看看:

float rand(vec2 uv) {
    float a = dot(uv, vec2(92.0, 80.0));
    float b = dot(uv, vec2(41.0, 62.0));
    float x = (sin(a) + cos(b)) * 51.0;
    return fract(x);
}

void main() {
    // ... 拿到 uv     vec2 rnd = vec2(rand(uv), rand(uv));
    uv += rnd * 0.05;
    gl_FragColor = texture2D(texture, uv);
}

rand() 可以說是一個偽隨機函數吧?輸入 uv ,然后通過 uv 和兩個奇怪的向量點乘,並且把他們的正弦值和余弦值相加,然后放大 51 倍(這個可以改),最后舍棄掉整數部分,返回小數點后就可以了。回到 main 可以發現,結果被進一步減小了 - 為了不過分采樣(就是離得太遠)。這樣就能讓采樣稍稍偏離原來的位置了!

當然,除此之外,其實你可以發現,假如不乘那個 51 ,然后點乘的那兩個向量比較小的話 —— 就可以呈現出晶體的效果了:

晶體

帥不帥?快點兒去自己試試吧!

沒了

上頭就是我用的所有的着色器了。其實要模仿舊的 CRT 顯示屏的話,這里還有:

玩得開心!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM