寫在前面
昨天從美術的角度出發,對AO貼圖參與到次世代模組化流程中的過程進行了學習。今天從圖形學角度學習環境光遮蔽。
封面圖截取自實時渲染GI|Ambient Occlusion:AO、SSAO、HBAO
1 AO
AO,即Ambient Occlusion,環境光遮蔽(感覺叫間接光遮蔽更好kkk),被設計出來模拟全局光照,模拟物體之間産生的陰影,在不打光的時候就能增加體積感。它是實作全局光照中部分物體局部光照和陰影真實化的一種技術方式,函數實作方式并非嚴格遵循現實的實體模型,但其效率高、效果好的優點還是被目前遊戲廣泛采用(叙述參考自環境光遮蔽)。
1.1 AO技術的發展*
這裡可能題外話比較多,不僅僅是遊戲層面的。
- 3D軟體:實際上,AO這項技術是在2002年被提出的,早期應用在了各種3D軟體上,需要預渲染、速度還慢,并沒有一開始就用在遊戲上
- 動畫:2005年獲得奧斯卡提名的《鲨魚故事》(Shark Tale)運用了類似原理的Ambient Occlusion技術
- 繪畫領域:AO畫法——通過繪制AO圖層來獲得3D繪畫效果
- 遊戲:AO技術(SSAO)真正用于遊戲其實是在2007年
接下來涉及的内容都會是遊戲領域的應用了。
1.2 AO解決的問題
這部分可以結合2.2小節一起了解。
補足光線彈射的不足
對于遊戲畫面來說,如果不開AO,系統預設唯一光源是太陽or月亮,其他在現實生活中本應該是真實光源的火把、路燈等,本身都是可以小範圍、固定的陰影,但在遊戲制作中為了節省性能肯定不會每個光源都給個真實的點光源,一般都是一個個模型(總不能每個小光源都渲染出來吧),這樣這些小範圍光源産生的陰影一定是沒辦法渲染出來的。需要AO去幫助解決。
物體凹凸感
對于一些有細節雕刻的物體,例如大的建築物,如果不開SSAO,整個物體表面看上去會很“平”、沒有凹凸感,就像是一張平平的貼圖(但其實低模實際上就是平平的kkk),不真實。開SSAO後,那種凹凸感就出來了。
拿老頭環畫面舉例(用了《艾爾登法環》PC版優化指南提供的素材,侵删):
上(AO關閉) 下(AO開到最高)
2 AO理論
AO Theory雖古早但不能不學!AO理論衍生自反射方程——AO影響光照計算的過程與漫反射和高光反射都有聯系。
2.1 讨論反射方程
(我不确定這裡能不能這樣取标題,但我覺得本身AO就是在間接光層面給直接光照一個補充的,是以這樣取問題應該不大吧。)
拿漫反射來說,以一個Lambert表面為例,計算表面接受來自一整個半球
各個方向的入射光線,即輻亮度。在不考慮AO的情況下,出射光的輻亮度
與入射到表面的輻照度(Irradiance)
成正比,輻照度隻與着色點
位置和着色點法線方向
有關。再假設各個方向入射的輻亮度(Radiance)是一個常量
,則計算整個半球面上的輻照度
:
和出射光的輻亮度
的計算公式為
其中,BRDF中的漫反射項
,與傳統模型簡單的diffuse不同,
是儲存物體albedo材質的顔色,RGB三個通道,為一個Vector3f量。
計算完輻亮度後,物體表面某點的輻射(光照)強度為:
由于
是個恒值,是以會呈現出一個光滑的物體表面。于是,當一個場景(僅漫反射)不加入AO渲染,由于漫反射Radiance是常量,這意味着場景中隻要有光源,所有物體表面着色效果都一樣,下圖(圖截取自參考文章)是漫反射+陰影後的效果:
計算時認為光照不到的物體直接全部處在陰影下,跟陰影融為一體了,并沒有考慮到可見性的影響,先放上加入AO後的效果(圖源仍然是參考文章):
2.2 讨論可見性
這裡的可見性我沒有找到明确的解釋,我的了解分為3個層面:
- 物體處于陰影下的軟陰影
- 由于光彈射(間接光)帶來的可見性
- 豐富物體凹凸感效果
處于陰影下的軟陰影
在真實世界中,特别是一個場景中有多光源的影響,即使是處在其他物體陰影下的物體,還是會向周圍投射一定的軟陰影,如上圖的這個小細節:
本應該處于太陽光照射下陰影中的桌面,還是會向地面投射淡淡的軟陰影。這樣做是可以豐富人物、物體的立體感的,不至于帶來懸浮、失真的非真實感。
光彈射帶來的可見性
寫到這裡才發現,這兩條實際上都是屬于間接光範疇,我分得有失偏頗,但确實更好的幫助我了解,就先這麼着吧:)
上圖中除了陰影部分,會發現處于太陽光陰影下的場景仍舊可見,上圖應該是沒有加漫反射顔色,如果上色了就感覺像是“在自身顔色基礎上疊上了一層陰影的灰”的效果,這就是AO模拟全局光照的另一個展現層面。
物體凹凸感
這裡在1.2小節已經提過了,就是下面這種感覺:
同樣,也是增加立體感。
2.3 公式中加入AO
那我們如何考慮這個可見性?我們假設遮擋處的光線為0(并不考慮光線彈射),直接手動修正可見性:
其中,
——是一個随射線相交距離變化的量,如果沿入射方向很快收到了遮擋(有交點),則
的值就越小,了解它可以結合下圖(圖源參考文章),
它表示了目前着色點
在入射方向
上的可見性,[0,1]上由不可見(完全遮蔽)到可見(無遮蔽),以此為畫面增加更多的細節。單獨拉出來一個積分項,那這一項就是正經的計算環境光遮蔽項了:
表示了半球面非遮蔽率,于是輻照度表示為
3 AO的優化
3.1 Bent Normal
還記得上一篇烘焙AO貼圖時的過程嗎?AO貼圖一般會跟法線貼圖一起烘焙出來,在渲染時會使用物體自身的法線去采樣AO貼圖。那如果想展現不同環境光照下的陰影漸變,就換個法線貼圖采樣——Bent Normal去采。
關于Bent Normal可以參考UE5官方的介紹:Bent Normal Maps
問題1 單一環境光照
上述AO都是假設單一環境光照,即Lambert模型中的Radiance相同。這就導緻:模拟自遮擋的陰影效果不會随着物體凹凸的程度改變陰影的深淺。
用Bent Normal替代Normal做shading,可以優化上述的問題,獲得更好的陰影效果。對比如下:
圖源 遊戲中的全局光照(三) 環境光遮蔽/AO
問題2 漏光問題
漏光問題大概是下面這種情況:
截圖自 Unity3d | 常見的模型漏光問題及解決
UE文檔截圖
解決方案就是用Bent Normal去采樣環境貼圖,從更優化的方向計算采樣的光線。
3.2 更好的AO系數
問題 多次彈射 MutiBounce
其次,由于推導AO時不考慮光線彈射,假設遮擋處光線為0,這将導緻加上AO的效果與光追AO的效果相比會暗一點。那麼如何彌補丢失的光線?
MultiBounceAO
用更好的AO系數,目前用的較多的是MultiBounceAO函數,如下:
截圖自 遊戲中的全局光照(三) 環境光遮蔽/AO
4 AO的實作方式
實作AO,要麼離線預計算要麼實時Render。
4.1 AO預計算
AO貼圖
- AO貼圖如何烘焙
AO貼圖就是預計算AO,【技術美術美術部分】AO貼圖的烘焙及應用介紹了AO貼圖如何烘焙及應用(3D軟體中應用)。
- AO貼圖如何參與到渲染中
這裡結合Unity的代碼來談談AO貼圖如何參與到渲染中的,Unity Standard shader提供的放置AO貼圖的參數項:
_OcclusionStrength("Strength", Range(0.0, 1.0)) = 1.0
_OcclusionMap("Occlusion", 2D) = "white" {}
Unity的Standard shader将GI計算分為兩部分:
- 直接光照:BRDF
- 間接光照:UnityGI
也就是整個計算為:color = Direct.diffuse + Direct.specular + Indirect.diffuse + Indirect.specular
UnityGlobalIllumination.cginc中的函數UnityGI_Base函數,計算間接光diffuse部分:
inline UnityGI UnityGI_Base(UnityGIInput data, half occlusion, half3 normalWorld)
{
...
o_gi.indirect.diffuse *= occlusion;
return o_gi;
}
以及UnityGI_IndirectSpecular函數,計算間接光specular部分:
inline half3 UnityGI_IndirectSpecular(UnityGIInput data, half occlusion, Unity_GlossyEnvironmentData glossIn)
{
...
return specular * occlusion;
}
最後都有一個*occlusion, 這個參數就是通過采樣AO貼圖得到的結果。
結合上述代碼,更能看出,AO貼圖就是直接簡單地将采樣出的值直接與GI間接光計算結果相乘,這樣AO貼圖中的黑色部分就可以抑制環境光強度了,以達到環境光遮蔽的效果。
AO Volume
嚴格來講這也是AO預計算技術的一種,因為是離線對需要産生AO Volume的物體做local space下的遮擋資訊計算,效果對比的部分會在後面某個小節涉及。
4.2 實時Render*
離線烘焙AO,在光照計算時直接采樣,這是預計算的方法。随着硬體的提升,足以支撐實時計算AO,這就是下一篇文章會講的,基于AO衍生出的SSAO等算法。