[閱讀筆記] Unity shader 入門精要 #4

《Unity shader 入門精要》的讀書筆記,十二章到十五章。 十二章說明在 OnRenderImage 組合多個 RenderTexture  與 Shader 完成後製特效。 十三章說明深度紋理 (Depth Texture) 及 法線紋理 (Normal Texture) 及其應用。 十四章說明卡通、素描兩個風格渲染;第十五章說明噪聲的應用。

第十二章:後處理特效 (post-processing effect)

  • OnRenderImage
    • https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnRenderImage.html
    • 須掛載於 Camera 之下。
    • 會搭配 Graphics.Blit 來完成渲染,當前螢幕 src 可以渲染至一張 RenderTeture,或者顯示在螢幕上;如果設定了 Material,會將 src 以 _MainTex 為名傳遞給 Pass
    • 預設會在透明 Pass 之後執行,可以加上 ImageEffectOpaque Attribute 改成在 透明 Pass 之前執行。
    • 如果開啟了 AA,處理多張貼圖會有在不同平台是否翻轉的問題,書中 5.6.1 有解釋。
  • 用於 OnRenderImage 的 shader 常見設定
    • ZTest Always
    • Cull Off
    • ZWrite Off
  • 亮度值 luminance:
    • luminance = 0.2125 * r + 0.7154 * g + 0.0721 * b
    • (r, g, b) = (luminance , luminance , luminance ) 相當是一個的等亮度的灰階色,作為 色彩飽和度 (彩度) 為零的代表
  • 摺積 Convolution:
  • Bloom 特效:
    • 先利用一個值決定亮度較高的像素,儲存為一張 RenderTexture
    • 對這張儲存的 RenderTexture 進行高斯模糊
    • 混和原圖與處理後的 renderTexture
  • 運動模糊特效:
    • 利用一張 RenderTexture 累積疊加畫面
    • 疊加時以一定比例混和 RGB 通道
  • 本章提到的 Unity API
    • SystemInfo.supportImageEffects
    • SystemInfo.supportRenderTetures
    • shader.isSupport
    • RenderTexture.GetTemporary () 建立暫時的 RenderTexture
    • RenderTexture.ReleaseTemporary () 釋放暫時 RenderTexture 占用的資源
    • RenderTexture.MarkRestoreExpected () 避免沒有清空 RenderTexture 時 Unity 跳出警告。
  • 本章提到的 unity shader 內建功能
    • appdata_img 內建的 vertex shader 輸入結構,定義於 UnityCG.cginc 中
    • CGINCLUDE … ENDCG 用來在 SubShader 層級定義結構跟方法

第十三章:深度紋理 (Depth Texture) 及 法線紋理 (Normal Texture)

  • 深度紋理:
    • https://docs.unity3d.com/Manual/SL-CameraDepthTexture.html
    • 指攝影機在 NDC 空間中所取得的一張深度資訊。
    • 在 Deferred Rendering  中,會與法線紋理儲存在 G-buffer 中。
    • 在 Forward Rendering 可以利用 camera.deepTextureMode 設定,再由特定名稱的 shader 參數取得。
  • 深度紋理的採樣:
    • SAMPLE_DEPTH_TEXTURE (_CameraDepthTexture, i.uv) 進行採樣,i.uv 是目前像素的 uv 座標。
    • SAMPLE_DEPTH_TEXTURE_PROJ (_CameraDepthTexture, UNITY_PROJ_COORD (i.scrPos)) 進行採樣,i.scrPos 是來自 ComputeScreenPos() 計算並插值後得到的螢幕座標。
    • 採樣結果經過 LinearEyeDepth 或 Linear01Depth 取得視角空間下的線性深度。
  • 法線紋理:
    • 存取情況與深度紋理基本類似,如果取得一張 深度法線紋理,則深度存於 R、G 通道,法線存於 B、A 通道。
    • 適當調整攝影機位置,可以提高兩項紋理的精密度。
  • 深度法線紋理的採樣:
    • tex2D (_CameraDepthNormalsTexture, i.uv) 直接採樣。
    • DecodeDepthNormal (float4 data, out float depth, out float3, normal) 內建方法可以解析採樣內容。
  • 運動模糊特效 (方法二):
    • 利用深度紋理計算像素的移動速度。
    • 為了從 view space 回推 world space 座標,需要在腳本中先計算 視角*投影矩陣及反矩陣,Camera.woldToCameraMatrix、Camera.projectionMatrix 是可以利用的 Unity API。
    • 利用腳本傳遞過來的矩陣,以 currebtPos = (uv.xy * 2 - 1, depth * 2 - 1, 1) 來計算 **當前禎 上一禎 **的 NDC 座標,進而取得像素的移動速度,進行對應的模糊處理。
    • 此方法是適用於靜止物體,只考慮攝影機的效果。
  • Fog 特效
    • 介紹了另一個重建世界座標的方法:攝影機座標 + 線性深度 * 攝影機對進剪裁平面的射線
    • float4 worldPos = _WorldSpaceCameraPos + linearDepth * interpolatedRay
    • 依照世界座標的高 (worldPos.y) 決定物的繪製。
  • 邊緣檢測
    • 使用 Roberts kernel 對 深度紋理 及 法線紋理 進行處理,只要有一者達到閥值便繪製邊線。

第十四章:特殊風格渲染

  • 卡通風格渲染:區塊化的漸變貼圖 + 邊緣描繪 + 特殊的高光區塊處理
  • 素描風格渲染:
    • 需要多張 Tonal art map
    • 將漫反射的數值分區規劃成數個整數,分別代表要留白或使用的貼圖編號
  • 本章提到的 shader 方法
    • step (threshhold, value) 當 threshhold < value 時回傳 1,否則回傳 0
    • smoothstep (-w, w, value - threshhold),當地三個參數位於 (-w, w) 區間時,回傳 (0, 1) 之間的一個小數,否則跟 step 運作相同
    • fwidth (x)

第十五章:噪聲

  • 噪聲紋理 (noise map):一張有著隨機明暗分布的灰階貼圖
  • 噪聲紋理生成演算法:
  • 消融特效:
    • 噪聲紋理 + 透明測試
    • 當噪聲紋理採樣結果大於一個閥值,則剔除像素
    • 要特別處理 shadow caster
  • 水波特效:
    • 透過噪聲紋理來生成法線貼圖,需啟用 create from grayscale
    • 利用 _Time 變數與設定的 float2 speed 變數進行 uv 平移的動畫
    • 同樣透過 cubemap 實現反射與折射所需的採樣
  • Fog 特效:
    • 利用噪聲紋理與 FogDensity 做相乘,來製造雲霧的隨機分佈