前言
在Unity的5.6版本之前的5.x中,主要使用了Geomerics公司的Enlighten【1】來提供實時全局照明以及烘焙全局照明,在5.6之后Unity引入了新的Lightmapper——Progressive來提供烘焙全局照明并且提供了更多的混合光照模式,但是Enlighten仍然是Unity中全局照明的主要提供者。
所以,本文就來聊聊Unity5.6以及Unity2017中和Enlighten、混合光照相關的話題吧。
直接光和間接光
大家都知道在Unity中,我們可以在場景中布置方向光、點光、聚光等類型的光源。但如果只有這些光,則場景內只會受到直接光的影響,而所謂的直接光簡單理解就是從光源發出的直接影響物體的光。如果只考慮直接光的影響,則會缺乏很多光影細節,導致視覺效果很“平”。而間接光則描述了光子在物體表面之間的反彈,能夠用來增加細節以及真實感。
例如上圖中,位于天花板燈直射光線之外的區域缺乏光照效果。表現為四壁上沒有明暗細節,相反此時直接光范圍之外都是均勻的黑色,而整個空間同樣也顯得十分平。
而增加了間接光之后進行渲染,可以看到光被物體表面反彈,彩色光從一個表面轉移到另一個表面。表現為紅色墻壁和綠色墻壁(在右側和紅墻相對,沒在畫面內)的顏色反映到了場景中的其他表面上,四壁也不再是均勻的黑色,而有了層次感。
全局照明和渲染方程
正如前文所說,在Unity中使用直接光是無法模擬光子在物體表面反彈的效果的,因此Unity使用了Enlighten所提供的全局照明(Global illumination)來提供間接光效果。
所謂的全局照明(縮寫為GI)是3D計算機圖形中使用的一組算法的通用名稱,旨在為3D場景添加更逼真的照明。這樣的算法不僅考慮直接來自光源的光(直接光),而且還考慮隨后來自相同源的光線被場景中的其他表面反射的情況,即間接光。
而全局照明可以用一個稱為渲染方程【2】的復雜方程來描述:
渲染方程定義了光線是如何離開表面上某個點的。但是各位也可以看到,這個積分方程太復雜以至于無法快速的計算結果。因此在具體的實現上,往往采用了一些近似的方法。
Unity中所使用的Enlighten采用的近似方法是輻射度算法,即假設存在一組有限的靜態元素和僅有漫射光傳輸來簡化計算。上面的渲染方程就可以簡化為下面這樣:
這樣,我們就可以將積分計算變為計算求其他元素的輻射度之和。
其中Bi指的是在i點最終的光,Le是i點本身的光,而兩個點之前有多少比例的光會被反彈,則有“form factor”來定義,即公式中的Fij,Lj是J點的光。而pi(輸入法問題,先寫成p)則是一個和i的材質屬性相關的參數。
這樣,這個方程就比較好理解了,同時計算相比之前的渲染方程也簡單了很多。
而有了簡化的方程之后,Enlighten在計算全局光照時,會將場景分組到便于并行處理的system中。接下來,每個system被切割成離散的cluster。
在計算光照時,Enlighten將場景視為一組cluster。而場景內的cluster則會以一種層級關聯的結構來組織,并且會對其映射的靜態幾何體的albedo進行采樣,之后在Light Transport階段計算cluster之間的關系以使得光在cluster之間進行傳遞。
這樣看上去全局照明方案已經完美的解決了間接光的問題,但是預計算實時GI的代價仍然很高,針對移動平臺這樣相對比較低端的設備,就需要有更加優化的解決方案。所以將靜態對象的光照信息烘焙到lightmap上,同時保持對動態對象使用實時光就變成了一個不錯的方案。而這就是我們下文中要說的混合光照。
混合光照
使用混合光照和直接使用烘焙的lightmap有什么區別呢?簡單來說,選擇“混合”烘焙模式,會將標記為靜態的GameObject受到的來自混合光源的光照信息保存為Lightmap。 然而,與標記為“烘焙”的燈光不同,混合光源也會為場景中的非靜態(動態)GameObject提供實時的直接光照。
在Unity5.x的版本中,光源就已經有了混合模式的選擇。但是直到Unity5.6版本,混合模式又變成了4種子模式。而到了Unity2017版本,則變成了3種子模式——shadowmask的兩種模式的設置被放到了Quality Setting內的Shadow下。如下圖所示,分別來自Unity5.5、Unity5.6以及Unity2017.3三個版本的Lighting窗口截圖。
可以看到Unity5.6之后的版本,混合光照的模式增加了Baked Indirect、Distance Shadowmask、Shadowmask、Subtractive這些子模式(2017版本后Distance Shadowmask的設置放到了Quality Setting中)。
首先我們可以先來看看Subtractive模式,因為Subtractive模式也是5.6之前Unity所使用的混合光照模式。
例如在Unity5.5中,我們如果將光源設置為mixed來開啟混合光照,和在5.6之后選擇Subtractive模式開啟混合光照是一樣的。
那么現在就可以安心的使用混合光照了嗎?
我們可以來看看一個在這種模式下常見的問題:
即使用點光開啟mixed模式時,左下角的動態對象cube并沒有產生由點光產生的實時陰影。
這個聽上去并不符合預期,因為mixed光照模式下對動態對象顯然要提供實時的光照效果,也就是預期應該是像下圖這樣產生點光造成的陰影。
那么這是為什么呢?這其實是因為在5.6之前的混合光照,以及5.6之后使用subtractive模式的混合光照只能在"只有"一個方向光(Directional light)的時候才能正常工作。
subtractive模式的另一個問題就是烘焙的結果中沒有高光,這是因為這種模式不僅僅烘焙了間接光,而且它還會烘焙直接光,因此也就無法提供高光效果了。所以可以看到在上面的截圖中,并沒有高光的效果。
正是由于這種混合光照模式的不足,所以Unity5.6之后又引入了更多的混合光照模式,以滿足大家的需求。
但是,作為開銷最小的一種混合光照模式,subtractive模式仍然有被保留的必要。在一些對性能要求高過對效果的要求時,subtractive模式仍然不失為一個不錯的選擇。
混合光照新模式-Shadowmask
Unity的新的混合光照機制的一個重要功能便是對Shadowmask【3】的支持了。混合光照開啟shadowmask模式的情況下,Unity會額外生成一套shadowmask貼圖,它每個紋素的4個通道可以分別用來保存4盞不同的光源。
如圖,這張shadowmask保存了2盞光源的信息,一個主方向光和一個點光。
Shadowmask的主要功能本質上十分容易理解,它解決了之前subtractive模式下無法完成的事情。Shadowmask不僅僅可以處理方向光,而且還可以正確的處理點光和聚光在混合光照條件下的表現。
可以看到左下角的動態對象cube產生了由mixed模式下的點光產生的實時陰影。
同時,由于沒有對直接光進行烘焙,因此能夠在運行時提供正確的高光效果。
而有些朋友如果打開Mixed Lighting的子mode選擇菜單的話,在5.6版本中還會看到另一個和shadowmask類似的選項——Distance Shadowmask。
那么Distance Shadowmask和Shadowmask又有什么區別呢?
這就和陰影距離(Shadow Distance)以及混合光照下陰影是如何產生的有關了。
我們在Edit->Project Settings->Quality設置中可以找到Shadow Distance的設置,在實時光模式下,只有在Shadow Distance范圍內的物體才會有陰影的影響。
而在混合光照-Shadowmask模式下,靜態物體和靜態物體之間的陰影是通過shadowmask貼圖來產生的。而對于靜態物體接收的動態物體產生的陰影,則只有在shadow distance范圍內動態物體才會產生實時的shadow map陰影。而動態物體之間的陰影,同樣需要在Shadow Distance范圍內來產生。至于動態物體如果要接收靜態物體的陰影,則需要借助light probe的幫助。
如上圖所示,在靜態的墻和地面之間,由shadowmask提供了陰影。
至于那三個動態物體cube,在沒有light probe的情況下,左下角的cube無法接受到靜態墻體的陰影。而右邊的兩個cube之間則有實時的shadow map陰影,并且它們也在靜態墻壁上投下了實時的shadow map陰影。
而如果使用Distance Shadowmask模式的話,各位猜猜哪一種陰影產生的方式會發生變化呢?
答案其實很簡單,首先肯定和Shadow Distance相關,其次肯定是和實時的shadow map和烘焙好的shadowmask之間的切換相關。嗯,答案呼之欲出——在distance shadowmask模式下,處于shadow distance范圍內的靜態物體也會實時的產生shadow map陰影,這一點和動態物體一樣,因此無論是靜態物體之間還是靜態物體和動態物體之間都會產生實時的shadow map陰影。而一旦超出了shadow distance的范圍,則靜態物體的陰影會從shadowmask中獲取。
如上圖所示,可以看到靜態的墻和地面之間的陰影邊緣銳利了,不像之前從Shadowmask獲取的陰影,由于分辨率的原因可能會更加模糊,此時已經是實時的Shadow Map陰影了,因此邊緣更加清晰銳利。而且左下角的cube已經可以接受到靜態墻體的實時陰影了。
不過正如我剛才提到的,Distance Shadowmask和Shadow Distance以及兩種陰影產生的方式有關,那么就有可能會出現一種瑕疵~即在Shadow Distance的內外,會有兩種不同的陰影,而Shadowmask產生的陰影由于分辨率的原因往往更加模糊,例如下面這樣:
可以看到墻壁產生了兩種不同的陰影。因此這個問題各位在開發過程中可能也要關注一下。
另外,Distance Shadowmask和Shadowmask相比,性能上的開銷顯然要更大一些,這也不難想象,畢竟還有很多靜態物體也會產生實時陰影嘛。那么我們可以簡單的對比一下兩者在Draw Call上的開銷:
可以看到,右側的Distance Shadowmask的drawcall開銷要遠遠高于shadowmask。因此,在移動設備上采用shadowmask而不是開銷更高的Distance Shadowmask對于追求性能的情況更加適用。當然,Unity2017之后,Distance Shadowmask和Shadowmask的設置已經移到了Quality Setting中了,這意味著我們可以在運行時動態的切換這兩種模式了。
void OnTriggerEnter(Collider other) { if(QualitySettings.shadowmaskMode == ShadowmaskMode.Shadowmask) { QualitySettings.shadowmaskMode = ShadowmaskMode.DistanceShadowmask; }else { QualitySettings.shadowmaskMode = ShadowmaskMode.Shadowmask; } }
當然,無論是Distance Shadowmask還是Shadowmask,它們都可以在Shadow Distance之外提供來自Shadowmask的陰影,雖然較之實時陰影要模糊一些。因此,對于需要遠方也要產生陰影效果的項目,Shadowmask模式是一個很好的選擇。
混合光照新模式-Baked Indirect
下面還剩下最后一個混合光照模式——Baked Indirect【4】。事實上這個混合模式的名字就已經十分直白了——它只烘焙間接光,其他的全部是實時的。Shadowmask貼圖?不存在的。
因此我們有了實時光、實時陰影等等。所以,在Shadow Distance的范圍之內和實時光下效果一樣,陰影是實時的shadow map,并且在shadow distance之外不會有陰影產生——哪怕是分辨率比較低的模糊陰影也沒有。
可以看到在Shadow Distance范圍內的墻的陰影十分清晰,但是在范圍之外則已經沒有陰影了。同時,這種混合模式的開銷也很大,因為它只烘焙了間接光,其他的全部是實時的。
總結
ok,讓我們對這幾種混合模式做一個小的總結吧~可以簡單的歸納為下面這個表格【5】。
評論
查看更多