Unity3D 的物理渲染和光照模型
為什么地球在兩極嚴寒,而在赤道火熱?這個問題,仿佛與著色器毫不相干,但卻是理解光照模型怎樣工作的基礎。正如這個教程前面部分所解釋的,表面著色器使用數學模型來預測光照在三角形上怎樣反射。總的來說,Unity 引擎支持兩種著色技術,一個是啞光著色器,一個是鏡面材料著色器。前一種對于不透明表面的支持很完美,而后一種則用來模擬反射對象。這些光照模型背后的數學可能非常復雜,但是如果你想創造屬于你自己的光照效果,你就得理解它們是如何工作的。直到 Unity 版本 4.x,默認的漫射光照模型都基于朗伯反射(Lambertian reflectance)的。
漫反射面:郎伯模型
回到最開始的問題,兩極冷的原因就在于它受照射的陽光比赤道區域少。這是由于它們受到太陽的斜射。下圖顯示了八角形兩極區域受到的光線明顯少于正面區域。
 
 
藍線代表了正交法向量單位長度。橙線表示了光線的方向。光通量的衰減取決于光線方向與法向向量的夾角。在郎伯模型( Lambertian model )中,它的值等于垂直的入射光線。
 
 
其可以表述為:
     \[I= \left \| L \right \| \, cos \alpha = cos \alpha\]
式中, \left \| L \right \| 為 L(這個量是之前定義過的)的長度 ,然后 \alpha 為 N 和 L 的夾角。這個算子在向量代數中被叫做點積 ,在前邊的文章中也已經簡單介紹了。正式的寫法應該是這個樣子的:
     \[A \cdot B = \left \| A \right \| \, \left \| B \right \| \, cos \alpha\]
在 Cg/HLSL 中都可以使用點操作符。其將返回一個從 -1 到 1 的數,當兩向量正交時將返回 0,并且當它們平行時 \pm 為 1。我們將使用其作為一個乘法系數,代表了從一個光源接收到多少三角光(三角函數光,即正弦余弦的意思,意會!)。 
朗伯著色器(Lambertian shader)
我們現在已經有必要來理解一個朗伯模型在著色器中是如何實現的。Cg/HLSL 允許用一個自定義的函數替換標準的朗伯模型。在第8行,在指令 #pragma surface 中使用 SimpleLambert,強制著色器搜索叫做 LightingSimpleLambert 的函數:
Shader "Example/SimpleLambert" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM
pragma surface surf SimpleLambert
struct Input {
float2 uv_MainTex;
};
sampler2D _MainTex;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
}
half4 LightingSimpleLambert (SurfaceOutput s, half3 lightDir, half atten) {
half NdotL = dot (s.Normal, lightDir);
half4 c;
c.rgb = s.Albedo  _LightColor0.rgb  (NdotL  atten  2);
c.a = s.Alpha;
return c;
}
ENDCG
} 
Fallback "Diffuse"
}
Shader "Example/SimpleLambert" {Properties {_MainTex ("Texture", 2D) = "white" {}}SubShader {Tags { "RenderType" = "Opaque" }CGPROGRAM#pragma surface surf SimpleLambertstruct Input {float2 uv_MainTex;};sampler2D _MainTex;void surf (Input IN, inout SurfaceOutput o) {o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;}half4 LightingSimpleLambert (SurfaceOutput s, half3 lightDir, half atten) {half NdotL = dot (s.Normal, lightDir);half4 c;c.rgb = s.Albedo  _LightColor0.rgb  (NdotL  atten  2);c.a = s.Alpha;return c;}ENDCG}Fallback "Diffuse"}</pre> 
從19到25行 展示了朗伯模型如何簡單地在一個表面著色器中再實現。NdotL 為光顏色的強度系數(相乘)。參數衰減器用于調制光強。其需要被兩個量乘是最初 Unity3D 用于仿真某些特效的技巧。這在 Aras Pranckevi?ius 中有解釋,在Unity4中留存了下來為了向后兼容。最終在 Unity5 進行了修復,所以如果你在 Unity5 上再實現一個朗伯模型的時候,僅僅只要乘上一個量就行啦。 
理解標準發光模型的原理是改變其不可或缺的步驟。許多可選的著色技術事實上仍然使用朗伯模型作為其第一步。 
Toon shading
最近在游戲中常用的風格之一即是Toon shading(又稱 cel shading).這是一種非逼真渲染風格,通過改變了光在一個模型上反射實際情況來給人以手繪的感覺。為了達到這樣的效果,我們需要用一個自定義模型來替換至今使用的標準光照模型。最常見用于達到這種效果的方法就是使用加性紋理,在下面的著色器中叫做_RampTex。 
Shader "Example/Toon Shading" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
_RampTex ("Ramp", 2D) = "white" {}
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM
pragma surface surf Toon
struct Input {
float2 uv_MainTex;
};
sampler2D _MainTex;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
}
sampler2D _RampTex;
fixed4 LightingToon (SurfaceOutput s, fixed3 lightDir, fixed atten)
{
half NdotL = dot(s.Normal, lightDir); 
NdotL = tex2D(_RampTex, fixed2(NdotL, 0.5));
fixed4 c;
c.rgb = s.Albedo  _LightColor0.rgb  NdotL  atten  2;
c.a = s.Alpha;
return c;
}
ENDCG
} 
Fallback "Diffuse"
}
Shader "Example/Toon Shading" {Properties {_MainTex ("Texture", 2D) = "white" {}_RampTex ("Ramp", 2D) = "white" {}}SubShader {Tags { "RenderType" = "Opaque" }CGPROGRAM#pragma surface surf Toonstruct Input {float2 uv_MainTex;};sampler2D _MainTex;void surf (Input IN, inout SurfaceOutput o) {o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;}sampler2D _RampTex;fixed4 LightingToon (SurfaceOutput s, fixed3 lightDir, fixed atten){half NdotL = dot(s.Normal, lightDir);NdotL = tex2D(_RampTex, fixed2(NdotL, 0.5));fixed4 c;c.rgb = s.Albedo  _LightColor0.rgb  NdotL  atten  2;c.a = s.Alpha;return c;}ENDCG}Fallback "Diffuse"}</pre> 
 
 
LightingToon模型計算了光強的朗伯系數NdotL并使用ramp紋理以將其離散化。該例子中僅映射了四級光強階。不同的ramp紋理將細化地獲得不同的toon shading變形。 
 
 
鏡面: Blinn-Phong模型
朗伯模型并不能仿真鏡面反射材料。這種情況下就需要另一種技術; Unity4.x 采用了 Blinn-Phong 模型. 不需要計算法向量 和光矢量
 和光矢量  的點積, 而是通過
的點積, 而是通過 和視角
和視角 的角平分矢量
的角平分矢量  來計算 :
 來計算 : 
 
 
     ![Rendered by QuickLaTeX.com \[\mathrm{Lambertian\,model:} \,\,\,\ I = N \cdot L\]](http://static.oschina.net/uploads/img/201507/03152618_AQXQ.jpg) 
 
     ![Rendered by QuickLaTeX.com \[\mathrm{Blinn-Phong\,model:} \,\,\,\ I = \left ( N \cdot H \right )^{specular} \cdot gloss\]](http://static.oschina.net/uploads/img/201507/03152619_YBwk.jpg) 
 
     ![Rendered by QuickLaTeX.com \[H = \frac{L+V}{\left| L +V\right|}\]](http://static.oschina.net/uploads/img/201507/03152621_Z7VW.jpg) 
 
數量  通過
 通過  和
 和 設置進一步計算。如果你想深入了解Unity中光照模型的計算, 可以下載其內置著色器的源碼. 朗伯和Blinn-Phong表面函數都是在Lighting.cginc文件中計算的。而在 Unity5 中需要在遺產著色器(Legacy shaders)中尋找。
 設置進一步計算。如果你想深入了解Unity中光照模型的計算, 可以下載其內置著色器的源碼. 朗伯和Blinn-Phong表面函數都是在Lighting.cginc文件中計算的。而在 Unity5 中需要在遺產著色器(Legacy shaders)中尋找。 
在Unity5中物理渲染 
就像本文在前面提出的那樣, Uniy4.x使用朗伯光照模型作為其默認著色器。Unity5中發生了改變, 其引入了 物理渲染 (PBR). 這個名字聽起來相當有趣啊, 但是與其它光照模型沒有什么不同。相比于朗伯反射, PBR提供了一個更加逼真的光線物體作用模型。術語physically 來源于,PBR考慮了材料的物理屬性, 比如能量守恒以及光的散射。Unity5為藝術家和開發者提供了兩種不同的方法,用于創建他們的PBR 材料: 金屬工作流 和 鏡面工作流。在前者中,一個材料對光的反射取決于其是什么樣的金屬(或者說,含有多少金屬的量)。 
簡單來說就是,光是電磁波啊,其行為因接觸到的是導體還是絕緣體而不同(電磁波唱由電場和磁場組成,但電場屬性實際上比磁場屬性更重要)。在鏡面工作流中, 所提供的是鏡面映射。盡管被當做兩個不同的東西呈現出來, 金屬材料和鏡面材料實際上以不同的方式初始化同一個著色器;Marmoset 上有一個很好的例程展現了同樣的材料如何通過金屬和鏡面工作流分別創建。這也是為什么當第一次接觸 Unity5 著色器時會因為源代碼中出現了同一事物卻有兩個工作流現象時會產生誤解。 Joe Wilson 創建了一個相當清晰的例程來知道我們的藝術家:如果你想學習怎么通過 PBR 創建非常逼真的材質,這將是非常好的開始喲。如果需要更詳細的技術信息,在 Unity5 博客里關于 PBR 的地方猛戳a very well done primer 。 
 
 
Unity5 中新光照模型名字既簡單又標準。取這個名字是因為現在 PBR 是每一個 Unity3D 中新建對象的初始材料。而且,每一個新建的著色器文件會被自動配置為一個 PBR 表面著色器: 
Shader "Custom/NewShader" {
Properties {
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
pragma surface surf Standard fullforwardshadows
// Use shader model 3.0 target, to get nicer looking lighting
pragma target 3.0
sampler2D _MainTex;
struct Input {
float2 uv_MainTex;
};
half _Glossiness;
half _Metallic;
fixed4 _Color;
void surf (Input IN, inout SurfaceOutputStandard o) {
// Albedo comes from a texture tinted by color
fixed4 c = tex2D (_MainTex, IN.uv_MainTex)  _Color;
o.Albedo = c.rgb;
// Metallic and smoothness come from slider variables
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
}
ENDCG
} 
FallBack "Diffuse"
}
Shader "Custom/NewShader" {Properties {_Color ("Color", Color) = (1,1,1,1)_MainTex ("Albedo (RGB)", 2D) = "white" {}_Glossiness ("Smoothness", Range(0,1)) = 0.5_Metallic ("Metallic", Range(0,1)) = 0.0}SubShader {Tags { "RenderType"="Opaque" }LOD 200CGPROGRAM// Physically based Standard lighting model, and enable shadows on all light types#pragma surface surf Standard fullforwardshadows // Use shader model 3.0 target, to get nicer looking lighting#pragma target 3.0sampler2D _MainTex;struct Input {float2 uv_MainTex;};half _Glossiness;half _Metallic;fixed4 _Color;void surf (Input IN, inout SurfaceOutputStandard o) {// Albedo comes from a texture tinted by colorfixed4 c = tex2D (_MainTex, IN.uv_MainTex)  _Color;o.Albedo = c.rgb;// Metallic and smoothness come from slider variableso.Metallic = _Metallic;o.Smoothness = _Glossiness;o.Alpha = c.a;}ENDCG}FallBack "Diffuse"}</pre> 
14行將告知 Unity3D 該表面著色器將使用 PBR 光照模型。17行 意味著該著色器將使用高級特性,因而其將不同在落后的硬件上使用。同樣的, SurfaceOutput 也不能同 PBR 一起使用;而是必須使用  SurfaceOutputStandard。 
PBR 表面輸出 
在 SurfaceOutputStandard 中不光是 Albedo,Normal,Emission 和 Alpha 這些屬性,還有三個新的: 
- 
半金屬性: 物體該具有怎樣的金屬含量。同常為0或1,但對于一些奇怪的材料可以使用中間的值。這個將決定光如何在材料上發生反射; </li>
- 
半平滑性:決定表面平滑程度, 從0到1; </li>
- 
半吸收性:指定 AO 特效大小。 </li> </ul>你應當通過 SurfaceOutputStandardSpecular 使用鏡面流,其使用 float3 鏡面替換了半金屬性。注意當朗伯反射存在一個半鏡面場,其在 PBR 中的鏡面屬性就是一個 float3。這符合鏡面反射光波的 RGB 顏色值屬性 。 Unity 中使用的著色技術迄今為止已經介紹了四種不同的著色技術。為了避免混淆,可以參考下表中所示,順序分別為:著色技術,表面著色器名,表面輸出結構體名和內置著色器名稱。 
 Unity4 及以下 Unity5 及以上 </tr>漫射 Lambertian reflectance Lambert, SurfaceOutput Bumped Diffuse 
 </td>![Rendered by QuickLaTeX.com \[I = N \cdot L\]](http://static.oschina.net/uploads/img/201507/03152632_wsYI.jpg)  Physically Based Rendering (Metallic) Standard, SurfaceOutputStandard Standard </td> </tr>反射 Blinn–Phong reflection BlinnPhong, SurfaceOutput Bumped Specular 
 </td>![Rendered by QuickLaTeX.com \[I = \left ( N \cdot H \right )^{specular} \cdot gloss\]](http://static.oschina.net/uploads/img/201507/03152633_hBxG.jpg)  Physically Based Rendering (Specular) Standard, SurfaceOutputStandardSpecular Standard (Specular setup) </td> </tr> </tbody> </table>PBR 背后的方程非常復雜。如果你對背后的數學比較感興趣,維基百科中的渲染方程和這篇文章 將是非常好的起點。 如果你導入 Unity3D 包 (包含了該例程中用到的著色器), 你將注意到內置 “Bumped Diffuse” 著色器是怎么產生一個與其最初實現“Simple Lambert”非常不同的結果。這是因為 Unity3D 的著色器增加了額外的特性,比如正常的映射。 結論本文介紹了用于表面著色的自定義光照模型。通過一個關于如何修改獲得不同特性的真實例子簡單解釋了朗伯和 Blinn-Phong 模型。有必要注意下單純的漫射材料實際上在生活中是不存在的:即使是你所想到的最鈍的材料也會有一些鏡面反射。漫射材料在過去中非常普遍,因為計算鏡面反射開銷太大。 本文也介紹了什么是 PBR,以及在 Unity5 中如何使用。PBR 著色器與表面著色器沒有什么區別,僅僅是帶有了一個非常高級的光照模型。 
 本文地址:http://www.oschina.net/translate/physically-based-rendering-and-lighting-models-in-unity3d 原文地址:http://www.alanzucconi.com/2015/06/24/physically-based-rendering-and-lighting-models-in-unity3d/ 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!相關經驗相關資訊sesese色
