遊戲中的Volumetric Rendering

總結下游戲中常見的Volumetric Rendering的實現方法
1. 一些理論知識
快速簡要地介紹一些理論知識.
光打到粒子上之後的效果:

光在介質上的散射,入射光分為吸收,透射,外散射三個部分,根據能量守恆,入射光等於三項的和
當不考慮中間介質時候,攝影機中得到的顏色就是最近的點上出射光的顏色

不考慮散射
考慮散射時,情況就比較複雜了:

光的散射
內散射會使路徑上的光增多,外散射會使路徑上的光變少.通常情況下,為了計算方便,不考慮多次散射的光.
模擬真實光穿透介質的比例的函式:

不同的散射型別:

Mie散射和Rayleigh散射
Rayleigh散射模型用來描述較小的粒子的散射,比如空氣粒子的散射使天空變藍. Mie散射模型是用來描述較大粒子的散射,比如灰塵.
Phase Function 是用來描述光在不同方向的散射分佈的函式,根據能量守恆,光在所有方向散射的和總是1

Henyey–Greenstein Phase Function 是一個經常用來描述Mie散射的Phase Function

2. DepthFog
在每個畫素計算的正常顏色基礎上,根據距離混合一個霧的顏色.
最常用的三種計算霧強度的公式:
Linear : factor = (end-z)/(end-start)
Exp: factor = exp(-density*z)
Exp2: factor = exp(-(density*z)^2)
unity中的全域性霧設定和巨集APPLY_FOG就是使用這種方式

unity中的全域性霧設定
早期的Opengl和DirectX甚至提供的類似的API介面(glFog 等),在硬體級別實現霧效.
3. PostProcessing Fog
和Depth Fog基本上是一樣的,區別在於PostProcessing 的Fog通過在PostProcessing時根據depth texture反推計算出攝影機到目標畫素點的距離.
除了用距離做引數,還可以根據高度作為引數,或者高度*距離這樣的形式來作為引數.
4. 粒子/BillBoard
在需要霧效的位置使用大量的粒子或者BillBoard來模擬光散射效果或者霧效.很顯然,這種方式很可能造成一些OverDraw效能問題,以及需要特定的觀察角度,而且不能隨光照變化.

5. Sun Shaft
也叫God Ray,通過PostProcessing來實現.GPU Gems 3 13.3中詳細描述了這種方法的實現.
原理是在PostProcessing時,將遊戲介面中的太陽以太陽為中心向外做一個Vector Blur + Bloom,再進行疊加,產生太陽光向外發散的感覺.當然了,這種方式只有太陽出現在畫面中的時候才有效果.

UE4中的Light Shafts包含兩種模式Light Shaft Occlusion和Light Shaft Bloom,後者就是上面所說的方式,前者則是將太陽周圍的暗部拉伸,產生遮擋的效果,原理是類似的.

UE4中的Light Shaft設定
Unity早期的Image Effects中,也有Sun Shaft效果元件.
6. RayMarching
使用PostProcessing和RayMarching來實現,GPU PRO5裡有一篇文章Volumetric Light Effects in Killzone Shadow Fall by Nathan Vos詳細介紹了這種方法.
基本原理是在pre-z得到場景Depth Buffer以及光照的Shadow Map後,確定一個要進行Volume Light的區域(點光源球形,錐形光錐形,直線光是全屏的),RayMarching計算出一個Volume Light的Buffer,計算光照效果時應用效果.
生成Volume Rendering Buffer的過程其實就是在Volume Redering區域中進行RayMarching,為了降低Artfict,通常會使用一個Dither Texture進行抖動,並且在最後對結果進行Blur,得到平滑的結果.

有一個Unity的Volume Lighting的Demo是這種方式來實現的, https://github.com/SlightlyMad/VolumetricLights.
7. Volume Texture
使用Volume Texture來儲存空間中的散射資訊,是真正意義上的Volume Rendering.
一個詳細描述了實現方法的文章: https://www.ea.com/frostbite/new ... ering-in-frostbite.
一個簡單的Volume Texture實現的Volume Rendering的過程:
1.劃分VolumeTexture的區域,這裡將攝影機視錐內的部分作為Volume Texture區域,沿著垂直於攝影機方向的平面切分.為了較好的效能,將3DTexture的大小弄的小一點,比如180x60x64.

沿著攝影機方向垂直切分
2.渲染光源的Depth Map,為了減少大量PCF陰影的效能消耗,這裡用ESM陰影,並進行DownSample.
3.使用Computer Shader,向Volume Texture中寫入空間中點的光照資訊,光照包含空間環境光,光源光照,求和後寫入到Texture RGB通道中.空間點的散射強度值,寫入到Texture A通道中.
4.使用Computer Shader,從攝影機方向向外進行RayMarching,使用前面提到的模擬散射穿透計算的公式,累加光照.

5.渲染某個點時,在VolumeTexture中查詢相應點的散射光照值,進行計算.
UE4中的VolumeRendeing就是這種方法.而且UE4還進行了升級,支援將Volume Lighting烘培到LightMass中.新版的UE4還有Volume Material和3DTexture匯入,可以方便地實現各種效果.
Unity的HDRP同樣是這種方式渲染.Unity官方以前的宣傳片Adam,同樣是這種方法,可以參考:https://github.com/Unity-Technologies/VolumetricLighting
作者:TC130
專欄地址:https://zhuanlan.zhihu.com/p/102114679
相關文章
- AvaloniaUI 中的 WPF CompositionTarget.Rendering 替代品UI
- Physically Based Rendering
- 遊戲中的夥伴遊戲
- “遊戲中的遊戲世界”——遊戲副本的起源與發展史遊戲
- 遊戲中的“瘟疫史”遊戲
- 遊戲中<loading>的思考遊戲
- 遊戲開發中遊戲效能的最佳化遊戲開發
- [Vue] useDefer to improve the rendering performacneVueORMMac
- 回合制遊戲中的10種遊戲平衡手段遊戲
- 日本遊戲中的中國武術遊戲
- 元遊戲(Metagame)中的“沉默”遊戲GAM
- 遊戲中的Decal(貼花)遊戲
- 喵的Unity遊戲開發之路 - 推球:遊戲中的物理Unity遊戲開發
- Games101-9 advanced renderingGAM
- 深入理解 iOS Rendering ProcessiOS
- 遊戲與烏托邦:《蚱蜢》中的遊戲哲學(四)遊戲
- 遊戲基礎知識——遊戲中“屍體”的設計遊戲
- 中國遊戲的得與失,中國遊戲的工業化還缺什麼?遊戲
- 遊戲中的陰影實現遊戲
- 遊戲中的活動設計遊戲
- 日本遊戲中的武士情結遊戲
- 遊戲中的時空與探索遊戲
- 誰是中國的遊戲之都?遊戲
- 遊戲開發中的道具管理遊戲開發
- 雜談:遊戲中的“聲音”遊戲
- 遊戲中的牛頓力學,簡析遊戲物理機制遊戲
- 遊戲中的意識流(下)——以Supercell系列遊戲為例遊戲
- 遊戲中的意識流(上)——以Supercell系列遊戲為例遊戲
- “反遊戲“的遊戲——放置遊戲研究遊戲
- 淺談遊戲中槍械:什麼因素影響射擊遊戲中的槍?遊戲
- 中國遊戲出海如何破局 Yalla :中東遊戲市場的新機會遊戲
- 3D遊戲的照明設計理論(四):如何在遊戲引擎中照亮遊戲世界3D遊戲引擎
- 中國遊戲商為什麼做不出好的三國遊戲?遊戲
- 「找找看」遊戲:埋沒在歷史中的遊戲文化功臣遊戲
- 走進遊戲中的美術:遊戲美術風格介紹遊戲
- 中國遊戲玩家為何偏好“種田遊戲”?遊戲
- 遊戲開發中的資料表示遊戲開發
- 遊戲場景中的光影設計遊戲