基於 Unity 引擎的遊戲開發進階之 場景渲染 & 光照進階
Unity 三維場景渲染
真實世界中陽光照射到樹木表面,經過樹木表面反射的光線,進入相機鏡頭。經過鏡頭的光線,最後照射到相機的感光元件上,感光元件記錄這些光線信息,保存為膠捲,或者量化為圖像文件。
遊戲場景是採用計算機技術描述的一個虛擬世界,這個虛擬世界與真實世界類似,場景中包含光、 物體以及相機、遊戲中的物體與場景光源發出的光線,發生反射或者折射現象,這些反射或者折射的光線,經過場景渲染過程,由虛擬相機記錄下來,生成虛擬相機所拍攝的照片。虛擬相機拍攝的照片顯示在電腦屏幕上,我們就看到了遊戲場景畫面。三維場景的渲染,本質上就是將計算機技術描述的 3D 場景,經過一系列計算過程,最終以 2D 圖像的形式呈現在顯示屏幕的過程。
Unity 場景渲染的要素:
- 光源
- 可繪製的遊戲對象
- 材質
- 攝像機
Unity 的四種基本光源:
- 點光源(Point Light)
- 方向光(Directional Light)
- 聚光燈(Spot Light)
- 面光源(Area Light)
我們通過設置光源的顏色、 強度以及它們在場景中的位置等參數,營造遊戲場景不同的光照效果。
可繪製的遊戲對象
大部分可繪製的遊戲對象都包含三個基本組件:
- Transform
- Mesh Filter
- Mesh Renderer
其中 Transform 描述了物體的位置、 朝向和縮放比;Mesh Filter 指定了物體模型的網格信息;Mesh Renderer 指定了物體的渲染方式,物體的材質在 Mesh Renderer 組件中設置。
材質
在 Unity 中,我們用材質定義物體與光線相互作用後 產生的視覺效果。
攝像機
在 Unity 中我們藉助虛擬相機來觀察遊戲場景,虛擬相機的參數給出了觀察者在何處以何種角度和投影方式,來觀察遊戲場景。
Unity 渲染技術
添加了光源、 可繪製的物體、 材質和相機後,Unity 引擎可以渲染出對應的遊戲場景畫面。在遊戲開發中,把這些簡單的要素堆積在一起,無法獲得逼真的遊戲畫面,為了獲得更佳酷炫、 逼真的遊戲視覺畫面,需要在遊戲場景中使用 Unity 引擎的高級渲染技術,比如說,全局光照,著色器技術。
Unity 光照進階
光源類型和屬性
如上文所說,Unity 的四種基本光源分別是點光源,方向光,聚光燈,面光源。
點光源:
- 從光源位置向所有方向發射出強度相等的光線
- 在傳輸過程中不斷的衰減,當傳輸距離達到預設的極限距離 range 時,光線強度衰減為0
- 適合模擬燈籠,火把等局部光源
方向光:
- 不會衰減,它以相同的強度和方向,照亮空間中的所有物體
- 位置信息沒有任何意義
- 常用來模擬那些體積較大,距離遊戲場景非常遠的光源,比如日光和月光
聚光燈:
- 聚光燈從光源位置開始向某個特定方向照射,照亮一個圓錐體的空間區域,在傳播過程中不斷衰減
- 通常用於模擬人造光源,比如手電筒,車燈,探照燈等
面光源:
- 使用一個矩形來定義,光線將從矩形的正面出發,照亮矩形前的一片區域
- 適用於模擬廣告燈箱等光源
- 不能作為實時光源
光源的屬性:
- 類型以及類型相關的屬性
- 烘培(Baking:烘培屬性 )
- 實時(Realtime)
- 烘培(Baked)
- 混合(Mixed)
- 顏色
- Color:光源的顏色
- Intensity:光源的強度
- Bounce Intensity:間接光照的強度
- 強度/反射強度
- 陰影
- 無陰影(No Shadows)
- 硬陰影(Hard Shadows)
- 軟陰影(Soft Shadows)
- 渲染類型
- Cookies:通過紋理,給光源添加一層遮罩,改變光斑形狀
Halo
勾選 Halo 屬性,Unity 會在光源所在位置繪製一個球形的光暈。
Flare
設置光源產生的鏡頭光暈效果。
Render Mode
光源的渲染方式
- 自動(Auto)
- 重要(Important)
- 不重要(Not Important)
對於重要的光源,Unity 會以逐像素的方式渲染被照射到物體。這種渲染更加精細,能夠產生陰影,但需要消耗較多的計算資源。對於不重要的光源, Unity 會以逐頂點,或者逐對象的方式來渲染被照射到的物體。這種渲染方式速度較快,但是質量不如逐向式的渲染方式,不能產生陰影。 Unity 會自動為重要程度為 Auto 的光源。
Culling Mask
選擇渲染方式 Culling Mask 設置光源所能照射到物體類型,可選項為當前項目中的 Layer。 只有被選中 Layer 包含的遊戲對象,才能受到這個光源的影響。
使用 Spot Light 模擬 FPS 遊戲中的手電筒效果。
這裡介紹一下 Flash Light Controller 腳本:
//玩家手電筒控制腳本public class FlashLightController : MonoBehaviour { private Light mylight; void Start () { //獲取玩家的聚光燈對象 mylight = GetComponent<Light> (); } void Update () { //根據玩家的輸入,開啟或關閉手電筒(調整聚光燈對象的亮度) if (CrossPlatformInputManager.GetButtonDown ("Fire3")) { if (mylight.intensity < 0.1) mylight.intensity = 5f; else mylight.intensity = 0.0f; } }}
陰影
陰影的產生
光線從光源出發,沿直線進行傳播。 在傳播過程中,光線遇到場景中的物體,在物體表面發生反射或者折射現象, 照亮了物體表面。 反射或折射發生後,如果光線改變傳播方向, 無法照射後續的物體,被照射物體就在後續物體區域產生了陰影。
我們換一種方式來理解陰影,假設有一台相機, 它和光源具有相同的位置,面向場景,此時相機觀察到的場景區域 就是被照亮的區域;反之,如果被相機觀察到的區域就會出現陰影。 Unity 也利用這種方法來渲染陰影。 它首先在光源位置放了一台臨時攝像機,渲染一遍場景, 渲染過程只計算當前視角下可見的物體的深度信息, 並以 shadowMap 的方法保存下來。shadowMap 記錄了場景中哪些物體離光源最近, 能夠被光線直接照射到。 場景中不在 shadowMap 圖像上的部分都是陰影區域。 最後當場景攝像機正式繪製場景時,參考這張 shadowMap 繪製出陰影。
Unity 渲染陰影的方法
- 設置光源的 Shadow Type 為 Hard Shadows 或者 Soft Shadows
- 設置 Shadow 的相關屬性
- 設置光源的 Render Mode 為 Auto 或者 Important
- 對於遮擋光線並在其他物體上產生陰影的對象,設置其 Mesh Renderer 組件的 Cast Shadows 為 On
- 對於接收陰影的物體,在 Mesh Renderer 組件中,勾選其 Receive Shadows 屬性
有時,即使正確地設置了光源和遊戲對象的相關屬性, 也依然無法看到陰影。 羅列了造成該問題的一些原因供大家檢查。
- 顯卡可能過於古老,不支持陰影的渲染;
- 項目質量設置中關閉了陰影;
- 產生陰影的光源的 Rendering Mode 設置為 Auto, 有些情況下 Auto 光源會被 Unity 自動判定為非 Important 光源, 或者無法產生陰影。 如果認為這個光源的陰影效果很重要, 可以把它強制改為 Important 光源;
- Unity 中的透明物體是無法產生陰影的;
- 接收陰影的物體使用了 Standard Shader,並且 Rendering Mode 改為 Transparent, 這種情況下無法生成陰影;
- 接收陰影的物體的材質使用了其它逐頂點的著色器,無法產生陰影。
日常開發過程中開啟了陰影之後,我們會發現物體表面上出現一些奇怪的條紋或者斑點, 這是由於 Unity 在計算陰影時,ShadowMap 的精度不足造成的。 我們把這種錯誤的條紋稱為馬赫帶。 我們在光源對象 Light 組件中,稍微調高 Bias 屬性的值,可以消除馬赫帶。 這裡需要注意,如果 Bias 值設置過大,會導致陰影面積減小,或者消失。
推薦閱讀:
※版本一席談:你挑擔來我牽馬,下路版本或將回歸
※《大神》的背景故事:天照大神和勾鏡劍三神器
※影游聯姻還有戲?華誼兄弟擬再購入英雄互娛股份
※盤點S6番外篇:就是你了!我的宿敵