[閱讀筆記] Unity shader 入門精要 #2
《Unity shader 入門精要》的讀書筆記,五到八章。 這幾章說明基本的 shader,並以簡單的光照、貼圖、透明混色等實作進行基礎應用。
第五章:基本語法
- 一段 Pass 的結構
1 | Pass { |
#pragma
用於指定兩種 shader 的 function name- Vertex shader 可用的傳入資料:
- POSITION、NORMAL、TEXCOORD0~3、TANGENT、COLOR
- https://docs.unity3d.com/Manual/SL-VertexProgramInputs.html
- Vertex shader 可傳遞給 Fragment Shader 的資料
- SV_POSITION 必備
- 另有 NORMAL、TEXCOORD0~7、COLOR0~1 等
- http://wiki.unity3d.com/index.php?title=Shader_Code
- Fragment Shader 的輸出需要有 SV_Target
- 在 Unity shader 定義的 properties 要在 CGPROGRAM 區塊中使用,需要再次宣告對應的型別、相同名稱的變數
- UnityCG.cginc 有內建結構跟方法可以調用
- 檔案位於 Unity 安裝處,CGIncludes 之中
- 5.3.2 版:https://gist.github.com/whaison/3e42351ceb828ec91075
- 其他
- 用
#if UNITY_UV_START+AT_TOP #endif
可以進行平台判斷 - 部分功能要用
#pragma target x.0
來指定版本,避免運行時錯誤
- 用
第六章:基礎光照
- 一般光照模型分常四部分:自發光、環境光、漫射光、高光反射光。
- 逐頂點光照效率較高,逐像素光照細節較佳。
- 計算 world normal:
normalize(mul(v.normal, (float3x3)_World2Object))
- 使用 _Object2World 的轉置反矩陣運算,相當於用 _World2Object 進行左乘法。
- 與光照相關的一些內建變數:
- UNITY_LIGHTMODEL_AMBIENT 環境光變數 。
- _LightColor0、_WorldSpaceLightPos0 與當下 Pass 相關的光照參數,需要加上對應的 LightMode Tag 才能使用
- _WorldSpaceCameraPos 世界座標下的攝影機位置
- 與光照相關的一些內建方法:
- WorldSpaceViewDir 輸入物件空間下的頂點座標,取得頂點往攝影機的方向向量 (世界空間座標)
- ObjSpaceViewDir 輸入物件空間下的頂點座標,取得頂點往攝影機的方向向量 (物件空間座標)
- UnityWorldSpaceViewDir 輸入世界座標,取得該點往攝影機的方向向量 (世界空間座標)
- UnityObjectToWorldNormal、UnityObjectToWorldDir、UnityWorldToObjectDir 轉換向量的所在座標空間,回傳值不為單位向量
- WorldSpaceLightDir、ObjSpaceLightDir、UnityWorldSpaceLightDir 取得往光照的方向,不需要考慮光照類型
第七章:基礎紋理貼圖 (texture)
- Unity uv 座標以左下為原點,右上為 (1, 1)。
- 一個 2D shader property 可以對應到兩個 CGPROGRAM 變數
_MainTex ("Name", 2D) = "white" {}
對應sampler2D _MainTex
及float4 _MainTex_ST
_MainTex_ST
用於縮放及平移,如:o.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
- 或者使用內建方法:
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
- 凹凸映射/凹凸貼圖 Bump mapping:實現表面位移 (displacement) 的技術
- 高度貼圖 height map
- 法線貼圖 normal map
- 漸變紋理貼圖:用一張漸變貼圖替代漫射光照的明暗,呈現不同的繪圖風格,此時貼圖採用 Clamp 設置。
- 遮罩紋理貼圖:利用一張貼圖特定通道的資訊,對物體表面的渲染進行局部調整,例如:調整物體局部的反光效果。
- 與紋理貼圖相關的一些內建變數:
- TANGENT_SPACE_ROTATION 由物件座標旋轉至切線座標
- 與紋理貼圖相關的一些內建方法:
- TRANSFORM_TEX(texcoord, sampler2D) 貼圖 uv 的縮放及平移
- tex2D (sampler2D, float2) 由貼圖中依照 uv 進行採樣,回傳一個 float4
- UnpackNormal (flaot4) 將貼圖從 rbg 對應成 normal map 向量,Asset 設定須為 Normal map
第八章:透明處理
- 使用 Alpha test 時,只會有完全透明與不透明兩種結果,但不會關閉深度寫入 (ZWrite),所以不影響深度測試 (Depth test) 檢查渲染順序。
- 通常會用上 clip(x),x 有任何分量為負則捨棄渲染
- 使用 Alpha blending 時,該物件的深度寫入 (ZWrite) 會被關閉,所以要對渲染順序進行控制。
- Unity 定義了五個渲染順序 Queue 的值,數字越小的越早渲染
- Background = 1000
- Geomtry = 2000,預設值
- AlphaTest = 2450
- Transparent = 3000,透明混和 (Alpha blending) 應該為於此處
- Overlay = 4000
- 所以透明處理的 Shader 應如此設定:
1 | // Alpha Test Subshader |
-
Unity 的 Blend 命令:Result = SrcFactor * SrcColor + DstFactor * DstColor
- Blend Off 沒有開啟混和,顏色會在緩衝中直接覆蓋
- Blend SrcFactor DstFactor 設定混和參數
- Blend SrcFactor DstFactor SrcFactorA DstFactorA 可以額外設定透明通道
- BlendOp BlendOperation
- 不同的寫入參數比較:https://github.com/ted10401/UnityBlending
- 各種BlendOp:https://docs.unity3d.com/ScriptReference/Rendering.BlendOp.html
-
關閉深度寫入的透明效果 Shader 在比較複雜的模型上會出現呈現錯誤,可以加上一個額外的 Pass 在透明 shader 之前,**先 **進行深度寫入
- ZWrite On 開啟深度寫入
- ColorMask 0 關閉所有顏色通道
- 不過依照我的理解,另外開啟 ZWrite 只是讓單一模型渲染正常,半透明模型之間的渲染還是會有機會出錯
-
如果要讓模型呈現更好的透明效果,可能會需要開啟雙面渲染
- Cull Off 指令會關閉單面渲染的剔除,但這樣不能保證渲染順序合理
- 可分成兩個 Pass,先渲染背面 (Cull Front),再渲染正面 (Cull Back)
- https://docs.unity3d.com/Manual/SL-CullAndDepth.html