Unity Shader——Writing Surface Shaders

從今天起,開始翻譯Unity關於shader的官方文檔。翻譯水平比較一般,目的主要是通過翻譯來提升對shader的見解,也讓其他人更容易的瞭解shader。以下開始正文內容:

 

編寫Surface Shaders

  和光交互的shader寫起來很複雜,有不同的光照類型、陰影選項、渲染路徑(正向渲染和延遲渲染),有時shader需要考慮所有的複雜性。

  Unity中的Surface Shader是一個代碼生成器,用它來寫光照shader(lit shader)相比於使用低階的頂點/像素shader(vertex/pixel shader)程序,會更加容易。注意Surface Shader中並沒有固定的語言和奇幻的東西(magic or ninjas involved)。它僅僅是生成原本必須由手工重複編寫的代碼。你也可以用Cg/HLSL來寫shader代碼。

  這裏有一些例子: Surface Shader ExamplesSurface Shader Custom Lighting Examples

它如何工作

  你定義一個“surface 函數”,其輸入是你所需要的任意UVs或數據,輸出是SurfaceOutput數據結構。SurfaceOutput簡單地描述了surface的屬性(properties of the surface),如反射率顏色(albedo color)、法線(normal)、散射(emission)、鏡面反射(specularity )等。

  Surface Shader編譯器會確定需要什麼輸入,有什麼輸出等,也會產生實際的頂點&像素shader(vertex&pixel shaders),以及渲染路徑來處理正向和延遲渲染。

  surface標準的輸出結構如下:

複製代碼
struct SurfaceOutput
2 {
3     fixed3 Albedo;  // 漫反射顏色
4     fixed3 Normal;  // 切線空間法線,如果賦值的話
5     fixed3 Emission;
6     half Specular;  // 高光強度,範圍是0-1
7     fixed Gloss;    // specular intensity
8     fixed Alpha;    // 透明度
9 };
複製代碼

  在Unity 5中,surface shader 也能使用物理光照模型。內建的標準和標準鏡面光照模型(見下文)分別使用以下輸出結構:

複製代碼
struct SurfaceOutputStandard
{
    fixed3 Albedo;      // 基礎 (漫反射或鏡面反射) 顏色
    fixed3 Normal;      // 切線空間法線,如果賦值的話
    half3 Emission;
    half Metallic;      // 0=非金屬, 1=金屬
    half Smoothness;    // 0=粗糙, 1=光滑
    half Occlusion;     // 遮擋(默認1)
    fixed Alpha;        // 透明度
};
struct SurfaceOutputStandardSpecular
{
    fixed3 Albedo;      // 漫反射顏色
    fixed3 Specular;    // 鏡面反射顏色
    fixed3 Normal;      // 切線空間法線,如果賦值的話
    half3 Emission;
    half Smoothness;    // 0=粗糙, 1=光滑
    half Occlusion;     // 遮擋(默認1)
    fixed Alpha;        // 透明度
};
複製代碼

例子

  參見:Surface Shader ExamplesSurface Shader Custom Lighting Examples and Surface Shader Tessellation

Surface Shader編譯指令

  Surface shader放在CGPROGRAM..ENDCG塊中,就像其他任何的shader一樣。不同處在於:

  • 它必須放在SubShader塊中,而不是Pass中。Surface shader將會自動編譯進多個pass中。
  • 它使用#pragma surface ...指令來指示它是Surface shader。

  #pragma surface指令如下:

#pragma surface surfaceFunction lightModel [optionalparams]

必須參數

  • surfaceFunction — 擁有surface shader代碼的Cg函數。此函數應有這樣的格式:void surf (Input IN, inout SurfaceOutput o),其中Input是你定義好的結構,它應該包含任何紋理座標以及surface函數所需的額外的自動變量。lightModel — 要使用的光照模型。內建的光照模型是基於物理的標準和標準鏡面光照模型,以及簡單的非物理Lambert(漫反射)和BlinnPhong(鏡面)光照模型。參見

Custom Lighting Models

  • 來學習如何編寫。
    • 標準光照模型使用SurfaceOutputStandard輸出結構,並匹配Unity中的標準(金屬工作流)shader。
    • 標準鏡面光照模型使用SurfaceOutputStandardSpecular輸出結構,並匹配Unity中的標準(高光設置)shader。
    • Lambert和BinnPhong光照模型是不基於物理的(來自Unity 4.x),但是使用它們的shader在低配電腦上能夠渲染地更快。

可選參數

  透明度和alpha測試(Transparency and alpha testing)由alpha和alphatest指令控制。通常透明度有兩種類型:傳統alpha混合(用於對象淡出)或更逼近物理的“混合預乘”(允許半透明的表面保持合適的鏡面反射)。開啓半透明度使得產生的surface shader代碼包含blending指令:基於給定的變量,開啓alpha裁剪將會在生成的像素shader中進行碎片丟棄。

  • alpha 或 alpha:auto —  將會選擇fade-transparency (同alpha:fade)作爲簡單的光照函數,選擇premultiplied transparency (同alpha:premul)作爲物理光照函數。
  • alpha:fade — 允許傳統的透明度漸隱。
  • alpha:premul — 允許預乘alpha透明度。
  • alphatest:VariableName — 允許alpha裁剪透明度。截斷值是一個名爲VariableName的float類型變量。你還可以使用addshadow指令來生成合適的投影通道。
  • keepalpha — 默認alpha通道中的不透明度爲1.0(白色),無論輸出結構中的Alpha是多少或者光照函數的返回值是多少。
  • decal:add — 附加的貼花shader(如terrain AddPass)。這對位於其他表面正上方和使用附加混合的對象來說是有意義的。
  • decal:blend — 半透明貼花shader。這對位於其他表面正上方和使用alpha混合的對象來說是有意義的。

  定製修改器函數(Custom modifier functions)能夠用來改變或者計算輸入的頂點數據,或者改變最終計算出的片段顏色。

  • vertex:VertexFunction — 定製頂點修改器函數. 此函數在生成的頂點shader的開始處被調用,可以修改或計算預頂點數據,參見 Surface Shader Examples
  • finalcolor:ColorFunction — 定製的最終顏色修改器函數。參見Surface Shader Examples

  陰影和鑲嵌(Shadows and Tessellation)— 附加指令,用於控制陰影和鑲嵌的處理。

  • addshadow — 生成一個投影通道。一般還要使用定製頂點修改器,這樣投影也能獲取任何程序上的頂點動畫。 當shader通過fallback來使用投影時,通常不需要任何特別的陰影處理。
  • fullforwardshadows — 支持 Forward 渲染路徑中所有的光照陰影模型。默認shader只支持正向渲染中來自單方向光產生的陰影。如果你需要用點光源或聚光光源來產生陰影,使用該指令。
  • tessellate:TessFunction — 使用DX11 GPU 鑲嵌; 該函數計算鑲嵌因子。詳情參見 Surface Shader Tessellation

  代碼生成選項 — 默認生成的surface shader代碼會嘗試去處理所有可能的光照/陰影/光照貼圖場景。儘管如此,在某些情況下你並不需要其中一些,你可以調整生成的代碼來跳過它們。這樣就能產生更小、加載速度更快的shader。

  • exclude_path:deferredexclude_path:forwardexclude_path:prepass - 對於給定的渲染路徑(分別是Deferred ShadingForward 和 Legacy Deferred),不生成相應的通道。
  • noshadow — 在此shader中關閉所有支持陰影功能。
  • noambient — 不應用任何環境光或光照探測(light probes)。
  • novertexlights — 不在正向渲染中應用任何光照探測或預頂點光照。
  • nolightmap — 在此shader中關閉所有支持光照貼圖功能。
  • nodynlightmap — 在此shader中關閉支持運行時動態全局光照(runtime dynamic global illumination)功能。
  • nodirlightmap - 在此shader中關閉支持方向光照貼圖功能。
  • nofog — 關閉內建的支持所有霧效果功能。
  • nometa — 不產生“meta”通道(該meta用來由光照貼圖和動態全局光照提取表面信息)。
  • noforwardadd — 關閉Forward 渲染附加通道。 這使得shader支持單方向完全光照,以及所有其他由每個頂點/SH計算的光照。同時使得shader更小。

  混合選項

  • softvegetation — 當柔性植被開啓時,surface shader纔會被渲染。
  • interpolateview — 在頂點shader中計算視線方向並進行插值,而不是在像素shader中進行計算。這使得像素shader更快,但會多消耗一個紋理插值器。
  • halfasview — 將half-direction 向量,而不是視線方向向量,傳遞給光照函數。Half-direction 將被逐頂點計算和單位化。這會更快,但不會完全正確。
  • approxview — 在Unity 5.0中被移除,請用interpolateview 替代。
  • dualforward - 在forward渲染路徑中使用dual lightmaps 。

  要了解使用上述不同選項所帶來確切的變化,使用Shader Inspector中的“Show Generated Code” 按鈕將會有所幫助。

Surface Shader 輸入結構

  輸入結構 Input 通常有shader所需的任意紋理座標。紋理座標必須命名爲“uv”+“紋理名稱”(或者以“uv2”開頭,來使用第二個紋理座標集)。 

輸入結構中還能放入一下額外的變量:

  • float3 viewDir — 將會包含視線方向,用來計算視差影響,邊緣光照等。
  • float4 with COLOR semantic — 將會包含每個頂點插值後的顏色。
  • float4 screenPos — 將會包含反射或屏幕空間影響下的屏幕空間座標。
  • float3 worldPos — 將會包含世界空間座標。
  • float3 worldRefl — 如果surface shader沒有賦值o.Normal,將會包含世界反射向量。參見例子:Reflect-Diffuse shader。
  • float3 worldNormal — 如果surface shader沒有賦值o.Normal,將會包含世界法向量。
  • float3 worldRefl; INTERNAL_DATA — 如果surface shader沒有賦值o.Normal,將會包含世界法向量。爲了獲得逐像素法線貼圖的反射向量,請使用WorldReflectionVector (IN, o.Normal)。參見例子: Reflect-Bumped shader。
  • float3 worldNormal; INTERNAL_DATA — 如果surface shader沒有賦值o.Normal,將會包含世界法向量。爲了獲得逐像素法線貼圖的法向量,請使用WorldNormalVector (IN, o.Normal)。

Surface shaders 和 DirectX 11

  目前,surface shader編譯管道的部分內容並不能理解 DirectX 11-特定的HLSL 語法, 所以如果你在使用HLSL特性,諸如StructuredBuffers, RWTextures 和其他非DX9 語法,你必須將之包含在只針對DX11的預處理器宏中。詳情參見Platform Specific Differences 。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章