小白也能看懂的Ray March體積云

前言
今天要給大家分享的主題是現(xiàn)在游戲開發(fā)中必備的一項游戲效果:游戲中的云渲染
現(xiàn)在大部分的游戲,不管是主機、PC還是手機游戲都在往3A的方向發(fā)展,所以現(xiàn)在的游戲在云的渲染上很少會采用傳統(tǒng)的渲染方式
體積云是現(xiàn)在很多游戲大作中必備的體積云渲染方式,比如地平線系列、大表哥二,都采用了這樣的渲染技術(shù),可以說體積云是主機游戲標(biāo)配的一項渲染技術(shù)
下面先從最早年代的云渲染技術(shù)開始,看一下傳統(tǒng)的云渲染方式是什么樣的,現(xiàn)在的渲染方式又是什么樣的
版權(quán)聲明
本文為“優(yōu)夢創(chuàng)客”原創(chuàng)文章,您可以自由轉(zhuǎn)載,但必須加入完整的版權(quán)聲明
更多學(xué)習(xí)資源請加QQ:1517069595或WX:alice17173獲取(企業(yè)級性能優(yōu)化/熱更新/Shader特效/服務(wù)器/商業(yè)項目實戰(zhàn)/每周直播/一對一指導(dǎo))
點贊、關(guān)注、分享可免費獲得配套學(xué)習(xí)資源
詳細(xì)內(nèi)容可參考文末完整視頻
云的渲染方式
天空盒

天空盒方式:
把一個攝像機放在整個場景中間,然后往上、下、左、右、前、后六個方向拍六張圖片,來構(gòu)成一個盒子形狀,整個游戲的天空都是被包圍在這個盒子里的,這就叫天空盒技術(shù)
公告牌云

公告板云:
這種方式也比較簡單,就是在整個場景上做了一個穹頂(如右圖),它可能就是用幾個面片把天空罩起來,然后在穹頂上貼一張?zhí)炜盏脑茖訄D片
片面穿插云

片面穿插云
面片穿插云的特點也是簡單,但它比使用前面的這些方式做出來的效果看上去要真實一點
如右圖,面片穿插云不再是一個單一平面,而是由多個平面組合成云的形狀,在不同的面片上繪制不同的云貼圖,由于貼圖是半透明的,所以面片穿插云看上去會有一定的立體感
視差云

視差云:
云海效果是基于視差貼圖的技術(shù)來實現(xiàn)的,在視角移動時可以看到云的體積感,因為視差貼圖就是用一張圖片來表示視差,然后渲染出來,雖然是一個平面,但它能渲染出高低不同的感覺
模型云

模型云:
模型云相對要更真實一些,它是把真實的模型放在角色頭頂來表示云的形狀,它的實現(xiàn)方式有幾種:
模型沿著法線外擴,來形成多個云的云層
采用曲面細(xì)分技術(shù)
優(yōu)點:云的形狀比較簡單方便
缺點:由于它本質(zhì)上并不是真正的帶有體積的云,所以不能在云里穿梭
Ray March 體積云

Ray March體積云
這是今天課程的主題,也是大家平時不太會接觸到,或者比較難理解的一種TA進(jìn)階的技術(shù):**Ray March體積云技術(shù),**Ray March的意思是光線步進(jìn),它跟光線追蹤是比較像的
上圖的游戲畫面中的云就是使用Ray March體積云實現(xiàn)的,可以清晰地看到云的層次感
體積云的特點

體積云的特點:
體積云是有體積的,而不是平面的
議題

體積云的噪點圖生成
屏幕后處理
光線追蹤一個云盒
光線步進(jìn)云的形狀
大氣光線散射原理
云的形態(tài)控制
最終效果演示
體積云渲染時的七個步驟
云的噪點圖生成

要生成噪點圖需要先在圖片上隨機生成一些小紅點(如右圖),生成完以后,圖片上的每一個像素格子都要判斷靠它距離最近的那個小紅點是誰,并且通過它們的距離值來代表亮度,距離越近,就把它渲染的越黑
這種隨機生成若干個隨機點,靠隨機點之間的距離來代表這個格子的亮度的算法叫做Worley Noise算法
接下來再把中間是黑的,邊緣是白的圖做一下亮度值的反轉(zhuǎn),就會形成左邊的中間是白的,越靠近紅點越白,越遠(yuǎn)離紅點越黑的圖片

在平面上生成噪點圖的開銷其實是挺大的,它需要一分鐘甚至幾分鐘時間才能生成一張,那有沒有辦法讓它的速度更快一些呢?
可以只生成中間這一小塊噪點圖,然后再把它重復(fù)九次(如右圖)
但復(fù)制出的平面噪點圖是不連續(xù)的,縫隙非常明顯,可以把這張復(fù)制出的圖片進(jìn)行水平和垂直翻轉(zhuǎn),讓平面噪點圖變成連續(xù)的狀態(tài),并把渲染開銷降低到原來的1/9
接著再在高度上生成跟平面噪點圖分辨率一樣的若干個切片就形成了3D噪點圖

如何生成Worley Noise噪點圖?
隨機確定一些中心點
計算每個像素到中心點的距離
但由于隨便找一個像素點,然后把這個點與其他中心點的距離全部算一遍的效率太低了,并且中心點越多,它的效率就越低,所以要進(jìn)行優(yōu)化
算法層面的優(yōu)化方法可以參考一下我們的《Untiy小白的TA之路》

如何在Unity中生成這樣的噪點圖?如何用Worley Noise算法生成噪點圖呢?像素數(shù)量太多如何優(yōu)化呢?
優(yōu)化只要用九宮格算法就可以了,但用九宮格去生成其中一個格子也有不少的時間開銷的,
所以為了解決這些問題可以開啟Unity Shader的Compute Shader來進(jìn)行并行運算,Compute Shader可以利用CPU和GPU來高效的調(diào)動整個噪點圖的生成
具體怎樣做才能使效率達(dá)到更高,可以參考文末的《Unity小白的TA之路》


上圖是我們的噪點圖生成器
第一個步驟完成以后就已經(jīng)能生成云的形狀了,那應(yīng)該如何按照云的噪點來把云渲染出來呢?這里需要使用光線追蹤技術(shù)來把云渲染到一個盒子范圍里
屏幕后處理

屏幕后處理就是把整個屏幕看成是一個四邊形,然后整個屏幕的內(nèi)容都已經(jīng)渲染在一張紋理貼圖上面了(左圖代碼中的_MianTex),然后再傳入這張圖片的每一個像素點的uv坐標(biāo)(左圖代碼中的input.uv),就能夠?qū)ζ聊凰倪呅芜M(jìn)行采樣并渲染在場景里
至于為什么要在這里講解屏幕后處理呢?是因為接下來要做光線追蹤

如果想要對場景里的物件實現(xiàn)勾邊效果,可以在片元著色器中寫右邊用黃色圈起來的這段代碼,這段代碼是把像素點坐標(biāo)做一個偏移,然后進(jìn)行采樣
光線追蹤

這一階段的目標(biāo)是在執(zhí)行左邊的代碼時能渲染出一個盒子(如右上圖)這個盒子我們叫它AABB包圍盒
算法解析:

在渲染每一個像素點時從攝像機的位置發(fā)出一條射線,射線的目標(biāo)點就是這個像素點的位置,也就是說:
射線的起點是攝像機的原點,方向指向屏幕上的一個像素點,然后通過rayBoxDst(快速求交)算法,算得這個像素點是否與云盒中的云有相交
代碼解析:
獲取到碰撞信息后,通過返回的X坐標(biāo)來記錄射線到盒子的距離并用變量保存,叫做dstToBox,然后再通過返回的y值記錄盒子內(nèi)部的長度,同樣是用變量保存叫做dstInsideBox
下面的if語句是判斷如果沒有碰到,就把顏色設(shè)置為黑色,碰到了就會把顯示顏色,這樣就能把盒子畫出來了
這種技術(shù)叫做SDF算法,其實這種算法不僅可以在屏幕四邊形上畫盒子,還可以畫各種各樣的形狀,大家如果想要了解如何繪制各種SDF形狀,可以在文末掃一下愛麗絲老師的二維碼,來領(lǐng)取我們的課程資料

現(xiàn)在可以反過來把盒子外面繪制出來,將盒子里面繪制成黑色,方法很簡單,就是把上圖代碼中的if語句中的感嘆號去掉

現(xiàn)在假設(shè)盒子是隱藏在紅色盒子的后面(如右上角圖),但黑色盒子并沒有被紅色盒子遮擋,這又是什么原因呢?
因為在屏幕后處理階段寫的Shader代碼不能在平面上區(qū)分每一個像素點的前后關(guān)系
解決方法:
可以利用Unity URP渲染管線的深度采樣功能取得每一個像素點的深度值,然后再通過圖形學(xué)里的深度重建的技巧來得到每一個像素的深度值
關(guān)于深度重建的原理和推導(dǎo)會在系統(tǒng)課程里詳細(xì)介紹
光線步進(jìn)

并不是盒子范圍內(nèi)全部都要渲染成云,因為前面的噪點圖代表云是否生成,而噪點圖是一個灰度圖,當(dāng)它的灰度值小于一定的值時,我們就不會把它渲染成云
所以要寫一個算法來采樣當(dāng)前位置里的云的濃度
注意點:
由于云在立方體盒子里是立體的,所以這個3D噪點圖會有很多層,無法一次步進(jìn)完,需要進(jìn)行多次步進(jìn)(如下圖)

這也是為什么這個技術(shù)叫做光線步進(jìn)的原因,每次步進(jìn)都要進(jìn)行采樣、判斷

圈中代碼解析:

上圖是經(jīng)過上面一系列步驟之后實現(xiàn)的效果,雖然還不是最終效果,但已經(jīng)比較接近了
雖然是在屏幕后處理,但我們會使用一個立方體的盒子來承載這個效果,這樣可以傳入想要渲染的范圍,以做到動態(tài)控制
大氣光線散射

實現(xiàn)大氣光線散射需要采用LightMarch技術(shù)
LightMarch原理:
從攝像機的位置射出一條射線,這條射線會穿越云層,每當(dāng)它穿越一點,就判斷一下它到太陽光方向的濃度值,濃度值越大,說明它產(chǎn)生的散射就越多
云里的每一個點都要判斷一下,最后把LightMarch的結(jié)果加起來,就得到光線散射的系數(shù)值了,然后用這個系數(shù)值作為最終渲染云效果的系數(shù),這樣就能得到:
”云越靠近光線的地方,就越透明;越遠(yuǎn)離光線的地方,就能更多的展現(xiàn)它本身的顏色”
云的形態(tài)控制

體積云最大的好處就是可以控制云的形狀,所以我們通過Unity實現(xiàn)了編輯器擴展,可以編輯、調(diào)整云生成時的形狀,包括實時渲染出的形狀

最終效果演示

小結(jié)

體積云的噪點圖生成
屏幕后處理簡介
Ray Tracing光線追蹤一個云盒
Ray Marching光線步進(jìn)云的形狀
大氣光線散射的原理
云的形態(tài)控制
最終效果演示
思考

噪點圖生成算法如何進(jìn)行優(yōu)化?
Compute Shader的原理是什么?
如何有Compute Shader加速運算
Ray-Box快速求交算法
RayMarch性能是否還有優(yōu)化空間
手游上的RayMarch如何優(yōu)化
什么是深度重建
如何利用URP環(huán)境下的深度緩沖
大氣的光線散射如何深入理解并實現(xiàn)
體積霧怎么做
體積光怎么做
如何利用Unity的編輯拓展實現(xiàn)TA工具鏈
寫在最后
更多學(xué)習(xí)資源請加QQ:1517069595或WX:alice17173獲取(企業(yè)級性能優(yōu)化/熱更新/Shader特效/服務(wù)器/商業(yè)項目實戰(zhàn)/每周直播/一對一指導(dǎo))
點贊、關(guān)注、分享可免費獲得配套學(xué)習(xí)資源
詳細(xì)內(nèi)容可參考下方完整視頻
