前言
其實在主機遊戲一直以來的發展中,一開始留給體積渲染的性能空間是不大的。即使設備的性能逐漸提升,解放了更多高級渲染特性,體積雲的性價比肯定是排在體積光、複雜水體、精細化頭髮等之後(這幾個方面我之前都有文章介紹過了)。
但是在畫面高清化的偏寫實遊戲中,雲也像體積光和水體一樣,必須要跟上整體畫質進化,因此人們也很難想象3A大作中的雲是一點動態沒有的“紙片雲”——屬於氛圍都烘托到這了,不做體積雲肯定也是不行的。
概念原畫中的雲
我個人選擇這篇2015年的SIGGRAPH分享作為和大家共同研習體積雲渲染的起點,大概有兩方面原因:
- 一方面,近10年以前的技術其實現在差不多能剛好或即將下沉到低性能主機設備和移動端,因此是今後10年仍不過時的技術。
- 另一方面,體積雲渲染基本也是從這個階段開始實現了比較好的動態、光照著色以及陰影,後面的發展可以理解為以此為基礎做的迭代。
文章還是以翻譯原文的講稿為主,重點部分會摘一些原文。由於篇幅原因會分為上下兩篇,打星號的部分則是我個人的補充說明。
1 早期探索方向
雲的實現目標(遊戲內渲染)
- 藝術家可定製的
- 真實感——多種不同樣式的雲
- 與天氣系統集成
- 隨時間流動和變化
- 具有史詩感
早期雲的探索
真實感的CG雲不是一個簡單的課題。因此,在我們嘗試解決創建完整天空系統的全部課題前,我們考慮先探索對獨立的雲資源進行製作和光照的不同方式。
我們最早成功的建模方法是使用定製化的流體生成器來產生雲。生成的結果效果很好,但對藝術家來說很難控制——如果他們沒有任何流體模擬的經驗。Guerrilla畢竟還是一個遊戲公司(不能要求藝術人員懂複雜物理)。
最終我們選擇了從簡單形體中為雲建模的方案:
- 將它們體素化
- 將這些體素輸入到我們的流體生成器中
- 直到我們得到一個像雲的形體
*到這裡還是說的建模軟件Houdini裡的事。
然後我們開發了一個基於預計算的光照模型,包含了直接和次級散射光照。圖中的結果是在Houdini中基於CPU計算10秒後得出的。
我們探索了3種把這類雲資源放入遊戲的方式。
最初我們嘗試把雲作為我們場景景觀的一部分,這意味著把它們從流體生成器種導出為多邊形結果,使用球諧光照(spherical harmonics)方式烘焙光照數據。這隻對有一定厚度的雲有效,對於蓬鬆的雲則不行。
因此,我們考慮嘗試強化billboard(廣告牌模式,指始終朝向攝像機的一種渲染方式)方案以支持更多雲的朝向,以及一天中不同時間的樣式。雖然成功了,但我們發現無法快速的重新生成雲的內陰影。
我們嘗試把所有(預生成的)雲作為一個集合,來製造能基於深度與大氣系統混合的天穹。某種程度上這是可行的。
在這一點上我們退回了一步來評估哪些部分是不可行的。這一方案生成的雲無法隨時間變化;這也不是一個使雲在物體上方穿過時的好方案;並且這些方案的內存佔用和overdraw都太高了。
所以傳統的基於(加載很多)資源的方法可能不可行。
*這部分主要在說預生成雲的常見問題:比較固定不動態(陰影、流動等);無法很好處理穿插(穿插會是“圖片和模型穿插”);上規模後性能開銷較大。
2 體積雲分析與嘗試
*在這個項目當時的情況,全體積方式渲染的雲還是比較難接受的,因為性能開銷較大。後面他們探索之後大概就是取了一個折衷的方案。
- 通常開銷很大:需要讀取很多紋理;需要光線步進(著色、陰影等方面);會有很多嵌套的循環。
- 可以使用很多經過驗證的實時體積光照方案。
- 有已經很成熟的通過噪聲圖來建模雲的方案。
- 我們能否通過取捨在性能開銷和好效果之間取一個平衡?
我們最初的嘗試是:在攝像機前堆疊很多多邊形,並通過它們作為3D Perlin噪聲的容器。雖然運行極度慢,但效果是可以的——不過我們想要更多不同類型的雲而不僅僅是這一種帶狀雲。
因此我們在Houdini中通過生成平鋪3D紋理的方式來模擬雲的形體。使用Houdini的GL擴展,我們構建了一個原型的GL shader來開發雲的系統和著色模型。
最終,通過很多hack的方式,我們得到了和參考很接近的模仿效果。
However, it all fell apart when we put the clouds in motion. It also took 1 second per frame to compute. For me coming from animated vfx, this was pretty impressive, but my colleagues were still not impressed.
然而,這一切在我們為雲加入動態時都崩塌了——它需要消耗每幀1秒來運算。對於我這個從事動畫和VFX(動效)領域的人來說,這個結果已經很讓人印象深刻了,不過我的同事似乎並沒有那麼振奮(1秒離實時還差很多,只渲染雲的話“實時”至少要是0.01秒內)。
So I thought, Instead of explicitly defining clouds with pre determined shapes, what if we could develop some good noises at lower resolutions that have the characteristics we like and then find a way to blend between them based on a set of rules. There has been previous work like this but none of it came close to our look goals.
所以我考慮,與其明確地通過預計算的形體來定義雲,如果我們可以開發一些在低分辨率下也能有好的效果、幷包含一些我們期望特性的噪聲,我們就可以找到基於一定規則來混合兩者的方式。這裡有一些前置工作,不過都和我們最終的視覺目標關係較遠(因此略去不介紹了)。
3 建模
*這裡是廣義上的建模概念,更類似“數學建模”中的建模——具體就是設計圖形算法、數據方案、渲染方案等。
這些最終把我們導向了在《地平線》中採用的方案。為了更好的解釋,我把整個方案拆解成4個章節:建模、光照、渲染和優化。
在開始解釋我們如何為雲的形體建模前,鋪墊一下對雲的基礎理解是很有幫助的——到底什麼是雲以及它如何變化成不同形體。
為雲分類能幫助我們更好的交流,以及明確定義我們繪製它們的場合。基礎的雲有如下類型:
- 層雲群體(strato clouds)包含層雲(stratus)、積雲(cumulus)、層積雲(stratocumulus)
- 高雲(alto clouds),指層雲之上的帶狀(bandy)或團狀(puffy)的雲
- 捲雲(cirro clouds)指在上層大氣的有著大電弧帶的雲和小型團狀的雲
- 最終還有所有這些雲的大綜合,積雨雲(cumulonimbus)
作為對比,珠穆朗瑪峰海拔是8000米以上(對應圖中從1500米開始的覆蓋範圍)。
在研究了雲的類型後,我們又學習了影響雲形狀的外力要素。
The best source we had was a book from 1961 by two meteorologists, called “The Clouds” as creatively as research books from the 60’s were titled. What it lacked in charm it made up for with useful empirical results and concepts that help with modeling a cloud system.
最好的素材是一本1961年的兩位氣象學家寫的書,書名叫《The Clouds》——它和其它60年代的名聲響亮的科研讀本一樣富有創造性。書中有著儘管缺乏閱讀魅力但富含經驗性結果的內容和概念,它們幫助我們建模了雲系統:
- 在低溫下密度增加
- 隨著海拔提高溫度降低
- 密度增加會加速雨雪的形成
- 風向會隨著海拔高度變化
- 雲層會隨著地熱緩慢上升
- 緊密的區域會隨著自身上升形成較圓的形狀
- 受光照的區域像霧一樣漫反射
- 大氣渦流持續地使雲扭曲
我們的建模方法使用光線步進(ray marching 這個詞後文都保持英文)來產生雲。
我們從攝像機發出射線(開始步進)以採樣噪聲圖和一組漸變,以在採樣器中確定雲的形體。
在ray march的過程中,我們使用採樣器來構建一個Alpha通道,並計算基礎光照(如圖)。
There are many examples of real-time volume clouds on the internet. The usual approach involves drawing them in a height zone above the camera using something called fBm, Fractal Brownian Motion. This is done by layering Perlin noises of different frequencies until you get something detailed.
網上有很多實時體積雲的例子。通常的一種繪製方式是在攝像機上方的一個高度區域使用fBm繪製(Fractal Brownian Motion 分形布朗運動)——是通過層疊不同頻率的Perlin噪聲的方式得到一些細節的結果。
This noise is then usually combined somehow with a gradient to define a change in cloud density over height.
這一噪聲結果通常會與一個漸變參數進行組合,以定義雲在不同高度的密度。
*fBm這裡可以簡單理解成一種噪聲組合採樣方案,組合採樣策略如文中所述。
這樣產生了看著不錯但非常“程序性外觀”的雲。哪裡出錯了?它們沒有更大範圍的外輪廓,以及缺乏視覺提示——我們無法基於雲的形體明確感受到它的流動變化。
作為對比,在這個照片中我們能對雲有較好的整體感受。這些雲像工廠中升起的泡泡團一樣上升——注意雲形體頂部的圓形結構和底部的蓬鬆結構。
fBm方法能得到較好的蓬鬆形體,但缺乏能帶來一些動態感的凸出和鼓起的部分。我們需要改進以超過網上那些隨處可見的shader中的效果。
這些被我稱為billow(鼓起、鼓包)的部分,它們是聚攏的,有時有著接近花椰菜(cauliflower)的形狀。
由於Perlin噪聲並不提供切割出它們的方案,因此我們需要開發自己的噪聲算法。
Worley噪聲在1996年被Steven Worley發明,通常被用來模擬焦散(caustics 這個詞的翻譯之前講水渲染提到過)或水下效果。圖中可以看到它顏色反轉時的效果。
- 它可以產生緊密擠壓的鼓包形體
- 我們將它以標準Perlin fBm的方式來分層
- 我們把它作為Perlin噪聲的一種補充,這使我們能在保持前者的聯通性的基礎上增加一些鼓包的形體。
- 我們把這個方案稱為"Perlin-Worley"噪聲
在遊戲中,為了性能考慮最好把噪聲存儲成平鋪3D紋理(而不是實時生成)——同時我們也希望儘量減少紋理讀取,並儘量降低其分辨率。
我們把噪聲組合壓縮到了2張3D紋理和1張2D紋理。
- 第一個3D紋理有4個通道,它有著128^3的分辨率
- 第一個通道是前面提到的Perlin - Worley噪聲,其它3個通道是頻率遞增的Worley噪聲
- 這個3D紋理被用來定義雲的基本形體
- 第二個3D紋理有3個通道,它有著32^3的分辨率
- 3個通道都是頻率遞增的Worley噪聲
- 這個紋理被用來給基礎的雲形體增加一些細節
- 我們的2D紋理有3個通道,它有著128^2的分辨率
- 它們都存儲非發散的捲曲噪聲(curl noise),被用來模擬雲的流動
- 我們使用這個噪聲來扭曲雲的形體,以添加一些渦流的感覺
回到標準方案中被稱為高度漸變(基於海拔改變噪聲信號)的部分:
- 我們使用了3個預運算結果用來表示低海拔的雲類型(用前面提到的基於採樣位置參數化的方式)
- 我們也使用了一張值在0到1之間的漸變圖來表示對應採樣位置希望的雲覆蓋率
圖中右側區域是《地平線》中攝像機旋轉30度向上的視圖,我們將展示基於這一攝像機上方區域繪製雲層的過程(文稿中沒有,是結合後面的圖一起看。完整過程有興趣可以去看PPT中的視頻):
- 首先,我們通過採樣第一張3D紋理並乘以高度漸變參數值,構建了雲的基礎形體
- 下一步是乘以覆蓋率參數並減少雲層底部的密度
這保證了雲層底部蓬鬆的同時,在整體的觀感上更接近自然界的樣子;同時也記住密度需要基於海拔變化。在這一步得到的雲的形體基礎上,我們再來添加細節。
下一個步驟是:
- 通過採樣第2個3D紋理並相減來在邊緣處削弱雲的形體(一點小提示,通過反轉Worley噪音圖的顏色可以得到很好的蓬鬆形體效果)
- 我們也通過2D捲曲噪音來扭曲第2個3D紋理,以模擬漩渦狀扭曲類似大氣擾動的感覺
這是遊戲中最終呈現的效果。我通過調整覆蓋率參數來使它們變厚,然後調整高度漸變參數使積雲變成層雲(文稿中也沒有,需要看視頻)。
現在我們已經有了得體的靜態雲層效果,接下來我們要添加動態和天氣系統。
雲覆蓋率和雲類型是我們天氣系統中開放出的2個功能模塊。
對於積雨雲和降雨我們有額外的控制模塊。
圖中左下角的圖片展示了渲染出圖中效果雲層對應的天氣設定。
其中淺粉色和白色的圖案是天氣系統的輸出。紅色是覆蓋率,綠色是降水量,藍色是雲類型。天氣系統在遊戲運行時通過模擬系統來控制住幾個通道。圖中展示的是頭頂有積雨雲、遠距離有層雲的情況。我們也能控制偏移量來使模擬基於藝術家的感覺進行調整。
默認設置狀態是積雲和層雲的組合。區域中有更多紅色部分和少量藍色部分,使它們更像層雲。這部分組合可以從圖中左下角的分佈圖看到。
圖中調整降水量參數使雲層變為了80%覆蓋率的積雨雲。
降水量控制不僅使雲的外觀變化,還帶來降雨效果(空間VFX粒子的方式)。圖中是降水量調整到100%的情況。
如果我們增加風速,並增加降雨概率,就能模擬出類似暴風雨雲層的效果。
我們的天氣系統也能確保雲層始終呈現出豐富的外觀,並能越過山峰。
雲的繪製範圍在15,000到35,000米之間。通常雲的外觀是50%覆蓋率的積雲效果。
在E3的預告片裡,我們用定製化的參數紋理覆蓋了天氣系統的輸入。你可以在圖中左下角看到對應的紋理,通過這種方式我們可以繪製定製化的天空。
總結一下我們的建模方案:
- 我們遵照標準的ray-march與採樣器的方案框架
- 但我們基於兩層細節紋理來構建雲層:一個低頻率的基礎外形,與一個高頻率的細節擾動
- 我們的定製化噪聲基於Perlin、Worley和捲曲(Curl )噪聲
- 我們使用一組預設紋理來對應不同雲類型的高度密度變化,以及覆蓋率
- 固定的轉場天氣系統則由定製化的紋理來驅動
- 所有效果都是能受風向影響動畫化的
結語
其實以後人的視角來看,可能會覺得他們當時的探索(作為索尼第一方來說)甚至就是“從零開始”了,但這其實也正是圖形技術在遊戲工業化中的顯著特點:
- 一方面發展非常快,機器性能只要能達到,就有很多在離線渲染領域已經做過的方案慢慢可以改到實時渲染中。熟悉兩者關係的可能知道,離線領域對各種課題的工業化(包括光線追蹤)都領先十幾年甚至幾十年,包含數據結構和圖形算法等很多方面。
- 另一方面就是需要針對特定的使用情景做定製化開發,具體到某款主機某個遊戲,真就得他們自己試才能找到當時最好的方案。
由於分享人是VFX方面的leader,因此文中可以兼具視覺模型的探索與物理模型的探索這兩種不同的視角。但是無論如何,實時渲染中的體積雲都還是一項相對昂貴的技術。在2015年,遊戲中任何形式的體積雲都還是比較超前的,大多數還是在使用“天空盒子”這種保守的方案。
篇幅原因這次僅包含了他們正式方案中最長的建模(Modeling)部分,下一篇會覆蓋後續的光照、渲染、優化幾個部分。
最後是資料鏈接:
The Real-time Volumetric Cloudscapes of Horizon: Zero Dawn這篇分享的PDF地址
這篇分享的PPT地址(含視頻版)