(六)unity自帶的着色器源碼剖析之——————Unity3D的全局光照和陰影:上篇(全局照明GI和局部照明)

一、全局照明和局部照明

全局照明(global illumination,GI)是用於向三維場景中添加更爲逼真的光照效果的一組算法總稱。全局算法不僅考慮光源發出的光與被照亮物體之間的關係,即直接照明(direct illumination),還考慮光線從某一物體的表面傳遞到另一個物體的表面時的關係,即間接照明(indirect illmination)。而局部照明(local illumination)則只需要考慮直接照明即可,不考慮光線在物體之間的反射。直接照明和局部照明如下圖:

全局照明需要考慮的是全部入射到攝像機中的光線,而局部照明則只需要考慮進入攝像機中的那一部分直接照明的光線。

 光線追蹤是一種很合適實現全局照明的方法,這種技術通過跟蹤場景中的光線傳播的軌跡路徑來模擬真實世界中的景象。但光追技術目前太慢,不適合大多數需要渲染圖形的場合,只有在一些非實時的離線渲染上使用光線追蹤技術去實現全局照明,如動畫片等。目前,使用光柵器對給定頂點進行插值,生成片元,然後對片元進行着色操作,是生成實時圖像的標準方法。

隨着硬件性能的提升和渲染算法的不斷改進,視頻遊戲等實時渲染領域在一定程度上也可以使用全局照明的方式來渲染了。普遍的方法是隻爲在場景中靜止不動的物體預先針對間接照明進行計算,並把計算結果存儲起來,然後在運行時使用這些間接光照信息進行渲染。因爲待繪製物是靜止不產生變化的,所示這種方法產生的效果在運行時仍然是正確的。

這種預先計算間接光照效果,最後把效果以光照貼圖的方式存儲,產生一張貼圖的過程被比喻成“烘焙出一張糕餅”出來。所以unity把這種技術成爲烘焙式全局照明(baked GI),或者稱爲烘焙式光照貼圖(baked lightmapping)。這個光照貼圖最終結果是把場景中靜止的遊戲對象的光照效果信息合併成一張大的紋理,供運行時使用。烘焙式全局光照可以利用更多的預結算時間支持用區域面光源產生的光照效果,以及支持更加逼真柔和的陰影。

Unity5.0之後還增加了一種預計算實時全局照明的技術,和烘焙式全局照明類似,這種新技術仍然限於應用在靜態物體上,依然需要一個運行前預結算的階段。但在預結算階段中,除了“計算出當前光源發出的光線,沿着當前的傳播路徑照亮到本物體時的效果”之外,還要處理“如果在運行時有光線沿着別的傳播路徑傳遞到本物體表面時,光線應該沿着哪個方向傳遞出去”的問題,引擎會預計算所有可能的光線傳播路徑並存儲,在運行時,將當前的光源輸入預結算的光傳播路徑中,並計算光照效果。

由於存儲的是傳播路徑,因此使用預結算實時全局照明技術在運行時,光源的數量、類型、位置等屬性都可以改變。被照亮物體的材料屬性,如吸收光的能力,自己發射光的能力也可以改變。在運行時,間接照明的效果也會相應更新這一切只要保持物體是靜態的且形狀不發生改變即可。

使用預計算實時全局照明也能產生較爲柔和的陰影,但是除非場景很小,否則這些陰影的效果一般會比使用烘焙式全局照明所產生的陰影要粗糙些。

預結算實時全局照明是在運行時才執行最終的光照計算的,但是爲了達到實時渲染的要求,引擎已經將實現它的算法優化到了很短的時間內完成。在運行時,如果光源或者被照亮物體的相關屬性相比預計算階段發生了很劇烈的變化,則會需要更多的時間計算最終的光照效果,所以如果運行平臺的硬件性能非常有限,使用烘焙式全局照明可能會更高效些。

烘焙式全局照明和預計算實時全局照明都有一個侷限性,即只能對靜態物體進行操作,移動的物體無法將光線反射到其他物體上,反之亦然。最大程度上解決這個問題的方法是使用光照探針(light probe)拾取靜態物體的反射光。光探針是場景中的某個位置點,在烘焙階段或者預計算階段,在該位置點上測量或者探測光線,並在此位置記錄下相關的光照信息。在運行時,運動的物體將從離它最近的光探針中取出間接光照信息並使用上。

從前面可以看出,全局/局部照明和實時/預計算光照是兩組不同的概念。前者是對繪製效果能達到一個怎樣的仿真度的描述,後者則是執行繪製時所採取的不同算法。雖然對於目前的計算機硬件能力而言,絕大部分全局照明所產生的效果還需要使用預計算光照,以離線的方式實現。

二、引擎提供的光源類型

2.1 點光源

點光源(point light)指處在空間中某一個位置點,其大小本身可以忽略不計,並且其照亮的範圍是一個球體光源,光的亮度值隨與光源的距離變大而逐漸變小,當超過照亮範圍(effect range)時亮度值變爲0。點光源發出的光線在某點亮度值與某點到光源距離的平方成反比。

2.2 聚光燈光源

聚光燈光源(spot light)和點光源類似,聚光燈光源也有光源的位置點和作用範圍,與之不同的是聚光燈光源的照亮範圍是一個圓錐體,光源位置就在圓錐體的錐頂處。

2.3 有向平行光源

有向平行光源只有顏色和方向,沒有具體光源位置。不會隨着傳播距離發生衰減。

2.4 區域面光源

實際中光源本身都有一定表面積,並且有一定的照亮區域。面光源就是其中一種,照亮區域是由其所在的空間中的區域矩形所指定的,光從它的一側表面,均勻地向四面八方發射。對於區域面光源的照明計算相當耗費性能它不支持實時進行光照計算,因此在運行時不可使用,只能預先烘焙到光照貼圖中。

2.5 cookie

在影視中,經常通過燈光效果營造一種真實景象,但本質上是虛擬出來的景象,要營造這種效果,通常是遮蔽一部分光線,通過一部分光線,然後把產生的輪廓圖案投射到場景中去,因爲營造這種效果的設備及形成的效果很像做曲奇餅用的花紋模具,所以稱爲cookie。

unity3D支持在燈光效果中使用這種cookie技術。使用了cookie技術模擬了光從窗戶中穿透過來,投影到地面上。這種效果需要一個有向平行光光源和一個被稱爲cookie的紋理就能實現。cookie紋理中其實只有其Alpha通道數據,即透明值數據有效。因爲在設計cookie紋理時,通常是把它設計成一張灰度圖的形式,所以當導入一個cookie紋理時,Unity3D引擎提供了把cookie紋理的顏色亮度信息轉爲Alpha信息的導入選項。

三、使用實時模式光源進行全局照明

每當在Unity3D編輯器中新建一個表徵光源的遊戲對象時,這個光源都是實時的。該遊戲對象上掛接了Light組件,並且組件的Mode屬性設置爲Realtime。這種光源稱爲實時模式光源。實時是指在每一幀中,這些光源都直接爲引擎提供光照計算所需要的參數,引擎計算出當前場景的光照效果。場景中的光源或者物體如果發生移動,或者光源的顏色亮度等發生變化,光照效果可以立即得到更新。在Unity3D的Scene窗口和Game窗口中可以同時觀察到更新的光照效果。

默認地,實時模式光源所發出的光線不能從一個被照亮物體的表面反彈(bounce)到另一個物體的表面上。每一個物體只受光源影響,它們之間相互不照亮,相互不影響,即只產生直接照明,不產生間接照明。但Unity3D引擎支持使用實時全局照明,選擇Window->Lighting->Settings命令,在彈出的Lighting窗口把Scene選項卡的Realtime Lighting項的Realtime Global Illumination複選框選中。選中後,場景內所有的實時模式光源發出的光線同時能執行直接照明和間接照明,即可以進行全局照明。

當光源的位置和強度變換緩慢時,使用實時全局照明的光照計算方式是很有真實感的,但如果光源的位置或強度變化得過快,使用這種組合方式並不是一個高效率的方案。目前,Unity3D使用Enlighten渲染器來實現全局照明效果,和烘焙式全局照明相比,實時全局照明將會耗費大量的系統資源計算光照效果,所以這種方式更適用於中高端PC,或者PS4等最新主機平臺遊戲。

當Lighting窗口中的Realtime Lighting|Realtime Global Illumination複選框被選中,但某個實時模式光源不想爲全局照明中的間接照明部分提供貢獻時,可以將光源的Light組件中的Indiretional Multiplier屬性設置爲0,這意味着該光源不會爲間接照明提供貢獻。

當Lighting窗口中的Realtime Lighting|Realtime Global Illumination複選框被選中時,unity會使用Enlighten引擎爲靜態的物體預先計算他們之間的外表面到外表面的光線傳遞路徑,即預計算實時全局照明:

當啓用預計算的實時全局光照功能時,將場景中靜態的物體表面的光照效果保存成“光照數據資源”(lightig data asset),供運行時使用。Unity3D引擎可以在運行時產生和更新一組低分辨率的光照貼圖,從而達到一些單純使用烘焙式光照貼圖無法達成的動態光照效果。

實時光源可以照亮靜止和運動的遊戲對象,並且可以投射逼真的陰影。這些陰影顯示與否,取決於選擇Edit|Project Settings|Quality命令後,Quality Settings面板中的Shadow Distance項的取值,當生成陰影的位置到當前攝像機的距離大於此值時,此處就不顯示陰影。

如果光源能投射陰影(Light組件的Shadow Type屬性設置爲Soft Shadows或Hard Shadows),場景中的動態和靜態的遊戲對象所對應的深度信息都將被渲染成陰影貼圖(shadow map)。這些遊戲對象的材質中的着色器將會對這個貼圖進行採樣,以便它們可以互相投射實時陰影。

四、使用烘焙式光照貼圖進行全局照明

其掛接的Light組件的Mode屬性設置爲Baked的光源稱爲烘焙模式光源。Unity將會在運行前預先計算這些光源產生的直接照明和間接照明信息,烘焙到光照貼圖或光照探針上。前場景中靜態物體表面的顏色信息烘焙到光照貼貼圖,用以照亮動態物體的照明信息則烘焙到光照探針,在運行時不再重新計算這些照明信息。在烘焙出來的光照貼圖中,可以存儲靜止的遊戲對象投射到靜止的遊戲對象的陰影,可以在運行時直接使用而不需要去計算。

因爲所有的光照信息都是預計算的,在運行時無法獲得 烘焙模式光源發出光線的方向信息,所以不能產生鏡面反射(specular reflection)效果,烘焙模式光源也不會因爲場景的改變而使其光照效果發生變化。一個被烘焙模式光源照射下的運動的遊戲對象,無法向另一個無論運行或者靜止的遊戲對象投射陰影;被烘焙模式光源照射下的靜止的遊戲對象,可以投射較低分辨率的陰影到運行的遊戲對象上,能產生低分辨率的陰影,但要使用光照探針才能達到這種效果。

烘焙式貼圖在運行期是不可改變的。場景中的一個物體在使用光照貼圖去照亮它的同時,也可以使用實時光源,以顏色疊加的方式作用在它上面。所以,如果不想產生“同時用了光照貼圖和實時光源,場景變得比預料中更亮了”的問題,在烘焙光照貼圖完畢後,可以把場景中實時光源都去掉。

與使用實時光源相比,因爲烘焙式光照貼圖需要包含更詳細的直接照明,所以使用烘焙式光照貼圖要佔用更多的內存。

五、使用混合光照進行全局照明

其掛接的Light組件的Mode屬性設置爲Mixed的光源稱爲混合模式光源。混合模式光源可以在運行時改變其位置、朝向、大小、光的顏色和強度等屬性,但這種改變不能隨心所欲,有較大限制。混合模式光源可以照亮靜止和運行的遊戲對象,並且一直貢獻直接照明,可按選擇提供間接照明,被混合模式光源照射下的運動的遊戲對象總能在其他運動的遊戲對象上投射實時陰影。

在場景中,所有的混合模式光源將使用同一種光照模式(mixed lighting mode)。要設置混合光照模式,選擇Window|Lighting|Settings命令,彈出Lighting窗口,在Scene選項卡可以看到Mixed Lighting選項,這就是混合光照模式的設置選項。該選項下面有兩個子選項,分別是Baked Global Illumination複選框和Lighting Mode下拉列表:

如果一個光源本身並不需要參與遊戲的相關邏輯,那麼它可以考慮設置成混合模式的光源,因爲由混合模式光源提供的直接照明是在運行時計算,所以靜止的遊戲對象將會在最大程度上保持預期的視覺效果。

在混合光照模式下,Mixed Lighting選項下的Lighting Mode子選項有3種,它們分別是Baked Indirect、Shadowmask、Subtractive。

5.1 Baked Indirect照明模式

對於混合模式光源,當Lighting窗口中的Lighting Mode選項被設置爲Baked Indirect時,Unity3D僅對光源提供的間接照明部分進行預計算。而所有離當前攝像機距離小於Shadow Distance值的陰影,都是在運行時實時計算。在本模式下,物體之間陰影投射與接受的關係如下表所示:

5.2 Shadowmask照明模式

陰影蒙版(shadowmask)是一種紋理,它和與之搭配使用的光照貼圖紋理使用相同的uv採樣座標和紋理分辨率。陰影蒙版的每一個紋素中存儲着它對應的場景某位置點上至多四個光源在此的遮擋消息,即記錄着這一點中,有多少光源能照的到,對多個光源照不到的信息。至於爲什麼最多支持四個光源,原因是在目前的GPU架構中,一個紋理像素最多隻支持四個顏色通道,如RGBA。

在此模式下, Unity3D預先計算從靜止的遊戲對象投射到其他靜止的遊戲對象上的陰影,即由間接照明貢獻的陰影,並將它們存儲在一個單獨的陰影蒙版紋理中,因此Unity3D在陰影蒙版中存儲的唯一的陰影信息是靜止的遊戲對象投射到其他靜止的遊戲對象上的陰影。如果某處有超過四個光源產生陰影,則多出來的混合模式光源將會轉用烘焙式光照計算,具體哪個光源轉用烘焙式光照計算陰影由引擎決定。每個光探針可以存儲最多4個光源的遮擋信息。如果4個以上的光源發出的光線相交,其餘的混合模式光源則會(自動地)改爲使用烘焙模式,並且這些光照信息是預先計算好的。又因爲混合模式光源的陰影蒙版在運行時是有保留的,所以運動的遊戲對象所投下的陰影可以與預計算並存儲在陰影蒙版中的陰影正確的合成,而不會導致重複投影(double shadowing)的問題。

在這個模式中,間接照明效果和陰影衰減都存儲在了光照貼圖中,陰影被存儲在一張額外貼圖(陰影蒙版)上、當只有主定向光源時,所有被照亮的物體都會作爲紅色出現的陰影蒙版中。紅色是因爲陰影信息存儲在紋理的Red通道中,事實上,貼圖中至多可以存儲4個光照的陰影,因爲它只有4個通道。

在Shadowmask模式下,其他靜止的遊戲對象向一個靜止的遊戲對象投射陰影時,是不受Shadow Distance選項的範圍限制的。只有運動的遊戲對象向靜止的遊戲對象投射陰影時才受此限制,要在ShadowDistance範圍內才能生效。且此部分陰影是通過陰影貼圖實現的。同時運動的遊戲對象也可以從靜止的遊戲對象處接受陰影的投射,而這部分的陰影是通過光探針實現的,這些陰影的保真程度取決於場景中光探針的亮度。一般來說,陰影蒙版紋理貼圖分辨率比實時陰影貼圖的分辨率要低一些。

Unity3D引擎自動對靜態和動態遊戲對象生成的重疊陰影進行組合,因爲控制靜態遊戲對象的光照與陰影蒙版和控制動態遊戲對象的光照與陰影信息的陰影貼圖將會被編碼成遮蔽信息(occlusion information)。

在Shadowmask模式下,物體之間陰影投射和接受的關係如下:

5.3 Subtractive照明模式

在 Subtractive模式下,將光源的直接照明部分烘焙進光照貼圖,而將在其他模式下用來組合動態和靜態的陰影的信息丟棄。因爲所有的光源被烘焙進光照貼圖了,所以Unity3D引擎不會在運行時做任何光照計算。除了主有向平行光源之外,在其他混合模式光源的照射下,靜止的遊戲對象都不會產生任何鏡面反射或者高光效果,也無法接收從運動的遊戲對象投射來的陰影。運動的遊戲對象能被實時照明,並支持光澤反射,但這些運動的遊戲對象只能藉助於光探針才能從靜止的遊戲對象處接收陰影。

在 Subtractive模式下,主有向平行光(通常是太陽)是唯一的光源,它將運動的遊戲對象上的陰影實時地投射到靜止的遊戲對象。從靜止的遊戲對象投射到其他靜止的遊戲對象上的陰影會被烘焙到光照貼圖中,即便是主有向平行光也是如此。Unity3D引擎無法保證烘焙的陰影和實時陰影能正常的融合,所以在Lighting窗口設置了Realtime Shadow Color選項。Unity使用該選項指定的顏色組合實時陰影和預烘焙的陰影。

在 Subtractive模式下,物體之間陰影投射和接受關係如下:

 

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