[The Art of Code] Rainy Window Tutorial In One Night

River Wang
二流遊戲開發
Published in
Nov 13, 2020

認真講年輕時就開始看 Shadertoy 裡的大神各種騷操作/神展示,多年前也試著把幾個效果放在 Game Engine 裡試看看效果氣氛。2017年在 Shadertoy 上公開的這段雨下在毛玻璃的效果很有名。

也曾經有人對此效果製作說明文章並移植到 Unity 環境,可惜我時間不夠所以一直沒有把這個 Shadertoy 搞懂。但現在大神已經在自己的 [Youtube Channel] 中公開整個 shader 技術教學了!所以只要耐心看完大神的教學,
基本上不但 Source Code 都給你抄,連每個階段的開發設計原理都解釋得很詳盡。真的是太佛啦!

我趁著近期終於有時間好好學,在看過這兩段教學後,便將自己的學習過程制作為開源專案公開出來,也許可以幫助到更多人。

在這個專案中我從教學影片看到的 Shader 開發過程,分成 14 個主題階段,包裝成 14 個 shader/material,所以在場景中只要更換對應主題的 material,就可以看到該主題的 Shader 效果/結果。

01_GridsMaterial (01_grids.shader): 教學如何針對一個 UV 區域分成網格狀分布 (Grid Layout)。

02_DropsMaterial (02_drops.shader): 使用 smoothstep() 定義雨滴形狀,並使用 _Time 內建時間變數帶入 sin wave 移動雨滴位置。

03_MovingMaterial (30_moving.shader): 透過移動所有整體 UV,並調整網格移動速度以達到整體雨滴效果是往下墜落;並且也調整雨滴移動的 sin wave pattern,達成更自然的雨滴下墜動態。

04_TrailsMaterial (04_trails.shader): 開發雨滴滑落時後方遺落的液低軌跡。

05_WiggleMaterial (05_wiggle.shader): 開始考量雨滴 X 方向的移動動態 pattern,並且調整雨滴外形讓其下垂外型更加自然。

06_RandomMaterial (06_random.shader): 定義亂數產生器函式,針對每個網格產生固定的亂數結果,達成對每個網格各自的亂數控制。

07_RandomDropsMaterial (07_randdrops.shader): 將各自往格產生的亂數數值代入以控制雨滴的動態亂數變化。

08_FogTrailMaterial (08_fogtrail.shader): 同樣使用 smoothstep() 計算出雨滴的液滴軌跡霧化外形。

09_DistortMaterial (09_distort.shader): 先以輸入的貼圖為背景,開始測試雨滴扭曲效果。原本計算出來的雨滴強度外形,將其視為 UV Offset 偏移量代入 Texture Fetch 指令,並且在計算 Offset 時候將雨滴外形強度與雨滴現在相對位置做相乘計算,達成讓相對位置成為控制 Offset 扭曲強度的影響因素。

10_FogblurMaterial (10_fogblur.shader): 使用 Mipmap 影像資料達成背景霧化控制效果 (輸入影像設定建議 ‘FilterMode’ = ‘Trilinear’,已達成 Mipmap 層級之間影像連續內插變化的效果,但不確定是不是 bug,沒有預期中的 Mipmap 影像內容變化效果,比較像是 ‘FilterMode’ = ‘Bilinear’ 的結果)。在使用 tex2Dlod() 存取 Mipmap 層級影像時考量雨滴後方拖液的液低軌跡霧化區域,以此變化量來控制要存取的 Mipmap 影像層級內插控制數值。

11_LayersRainMaterial (11_layersrain.shader): 基本功能元素都已經大致完成 (雨滴、液滴軌跡、霧化軌跡、雨滴動態、背景影像 Mipmap 控制霧化等)。此階段 shader 僅是將所有開發功能包裝成 API 重複使用,達到多層次下雨控制效果。

12_GrabScreenMaterial (12_grabscrn.shader): 接著要開發窗戶效果,因此繪圖對象 (Quad)需要能透視後方背景影像。此階段 shader 僅示範很簡單的 GrabPass 用法。

13_ScreenblurMaterial (13_screenblur.shader): 正確繪製透視背景螢幕畫面後,搭配原本的所有雨滴效果便可達成背景被雨滴扭曲的視覺效果。但是因為目前可取得的背景畫面 (RenderTexture) 不存在 Mipmap 影像資訊,因此無法像之前使用 tex2Dlod() 來控制影像霧化效果。故在此階段 shader 直接開發多次疊代的霧化影像處理功能,來達成霧化效果。

14_RainmipmapMaterial (14_rainmipmap): 最終階段考量視野遠近時,雨滴效果也應該實現 Mipmap 概念效果,因此使用 fwidth() 計算 Fragment Shader 中每個 Pixel 之間的變異差距,視為控制遠近 Mipmap 影響力的控制參數。

整個教學專案內容介紹至此,感謝 The Art of Code 大神持續分享最酷的教學,我獲益良多。

最後因為近期剛好在學習 Egret Engine,當然就順便移植到 Egret 專案中當一次練習,也好久沒寫 WebGL (GLSL ES) shader codes了。此專案也同步公開於 Github repo當中。

--

--

River Wang
二流遊戲開發

學生時代就跳入 Computer Grpahics 領域,其他技術好像都不想學/學不來,工作也找 Graphics 相關內容,但幾年後第二份工作才真的投入遊戲產業,不過也是個失敗的經驗。目前雖然逃離遊戲慘業,但也沒混出什麼出息,仍然在混口飯吃,並幻想著某天自己終於有時間開始完成自己想做的遊戲作品。