米哈遊弋振中:從手機走向主機,《原神》主機版渲染技術分享
大家好!歡迎參加這次分享!今天我演講的主題是從手機走向主機,《原神》主機版渲染技術分享。首先我簡單介紹一下《原神》的遊戲,《原神》是開放世界的RPG遊戲,有獨特的二次元畫風,是跨平臺的,而且長期運營,長期更新。
稍微介紹一下自己,我叫弋振中,大概有十多年的主機遊戲開發經驗,畢業之後加入了Ubisoft Shanghai,2012年去了加州的Zindagi Games,為當時還沒有上市的PS4做一款獨佔的遊戲。然後去了紐約的Avalanche Studios,參與制作了《正當防衛》的3和4。回國之前的最後一站是在西雅圖的微軟Xbox。2019年初回到上海,加入了米哈遊,組建了研發團隊,目前負責《原神》的主機平臺開發。這是我做過的一些專案。
今天的內容安排大致是這個樣子,首先我會介紹一下《原神》主機平臺的基本情況,然後按照我們開發的時候改造渲染管線的思路,選擇部分的技術點進行更深入的分享。希望從渲染的角度,讓大家對於我們如何將《原神》帶到主機平臺有大致的瞭解。最後是一點我個人的開發體會。
首先,Unity是我們遊戲裡面使用的引擎。Unity是一個靈活度很高的引擎,程式碼風格很簡潔,所以我們能夠更方便地定製化開發《原神》的渲染管線。Unity中國的技術支援很配合我們,在此對他們表示感謝!
PS4作為遊戲的主機,硬體架構可以說是為遊戲開發量身打造的,主機開發過程當中大量的精力是花費在如何更好地利用硬體特性上,也積累了不少我們認為還可以的技術實現。不過因為索尼NDA的原因,今天的分享就不涉及相關的內容,也不涉及底層的優化。前面也提到今天的分享,主要是針對渲染管線的,所以也不涉及CPU和其他的模板。
下面是主機渲染管線的簡介,首先我們有非常強大的引擎團隊,在Unity上面為《原神》進行了深度的開發。主機平臺和手機平臺採用了不同的渲染管線,但是遊戲的基調是一致的,都是基於PBR的風格化渲染。《原神》的主機平臺開發起步時間稍晚於手機平臺,在平臺管線搭建好以後就進入了同步開發的節奏。資源的製作、功能的開發多方面都需要兼顧到多個平臺的情況。
基於PBR,是為了讓整個大世界的光影效果保持統一,因為我們的光影都是實時計算的,有24小時的迴圈,有動態的天氣系統。PBR能夠確保不會在不同的光照條件下出現脫離預期的渲染效果。作為風格化的遊戲,也需要根據美術的需求修改不同的材質。
《原神》在PS4上的解析度是這樣設定的,PS4 pro上面是原生的4K解析度,在PS4的base,我們是把1440P作為我們的渲染解析度,最後是輸出到1080P上面,這樣我們得到的最終後面會更加清晰,也會更加銳利。作為《原神》為主機開發的功能,大量使用了compute shader,compute shader有很多很好的特性,而且在支援Async compute管線的平臺上,我們還能夠進一步隱藏開銷。
《原神》的風格化渲染是非常獨特的,因此美術對於圖形功能的要求也和寫實類遊戲不一樣,尤其是光影效果,大家可以看到髒、黑、死、焦、噪這些詞都頻繁地出現了美術和程式的溝通當中。
下面我們提到的所有的技術,都經歷了很長的磨合期,有一些甚至還在磨合當中。在經歷了反覆的打磨和修改,直到美術對最終效果滿意,程式對最終實現方案的效能也滿意的情況下,我們才會大規模鋪開製作。
接下來再介紹具體的功能之前,我跟大家講一下在PS4平臺剛開始開發的時候,我們面臨的一個狀況。首先是我們有一個已經針對手機做大量開發的Unity引擎,這就意味著簡單的切換平臺就想讓遊戲能夠在PS4上跑起來,這是不可能的了。很多專案之前做的改動,在實現的時候也沒有考慮到主機平臺的特性。再加上各種計劃為PS4開發的圖形和遊戲的功能,這都意味著大量的工作量。
另外還有TRC、索尼賬號等等一系列PS4獨有的問題需要解決,工作量和工作難度都非常大,然而我們能夠給主機開發的資源又很有限。一開始的主機團隊就我一個人,光桿司令。為了全球同步上市,留給我們的開發時間大概只有一年半,一年半的時間要讓一個平臺從無到有,還要達到一定的品質,這期間還要準備ChinaJoy、TGS等展會,能夠順利地完成這一切,真的是非常感謝《原神》的整個開發團隊的努力,非常的不容易。
下面講一下我們在渲染管線做改動的時候一些思路,因為開發的時間很緊,所以在選擇技術改造點的時候,遵循下面幾個原則。
第一個是關於功能的選擇,我們首先排除掉開發週期長的,需要過多地前期研究工作的功能,因為我們沒有時間。
然後根據遊戲的美術風格,我們選擇一些對於畫質的幫助更大的地方去做提升。另外因為時間不多,所以我們希望新加的功能能夠更多地發揮作用,所以最好是能夠在相互之間產生互動,這樣會顯得畫面更加系統化,得到的畫質提升也會有1+1>2的效果。
下面就是我們做一些技術點的解析。首先我們從場景的光影方面選擇了幾個技術點,主要是側重一些方法,會稍微涉及到一點點的優化思路。第一個是關於方向光的陰影,《原神》的大量遊戲時間是在室外,室外方向光的陰影質量非常重要。一方面近處的陰影細節需要更加細膩,才顯得畫面更乾淨。另外一方面是陰影覆蓋範圍需要足夠大,因為遊戲的可視距離非常遠。《原神》的陰影範圍是800米。大家可以看一下這張貼圖,即使在遠處牆壁上一小片的綠植產生的陰影,在放大之後都能夠看到樹葉的輪廓。這個地方放大之後,能夠看到樹葉輪廓,而且非常穩定。整體上來說,我們對於《原神》的方向光陰影的質量是比較滿意的。
我們陰影的技術還算是比較常規,使用了Cascaded shadow map 加上基於Poisson disc的soft shadow,我們遊戲沒有使用通常的4級cascades,而是用了8級,這屬於大力出奇跡的方式。大力出奇跡帶來了更好的陰影效果,當然也帶來了更多的效能開銷。更多的drawcall會帶來CPU開銷,更多的cascades也會帶來GPU的開銷。我們把質量提升上去之後,會想辦法來解決效能問題,那我們怎麼去做的呢?
首先在CPU端,我們做了一個shadow cache,8級cascades前4級我們每幀都更新,後面4級是採用輪流更新的方式,確保每8幀所有的cascades都能至少更新一次。每一幀的話,我們只更新5級cascades。
主要的工作量其實在GPU端,用了8級cascades以後,我們的screen space shadow map的開銷長期是大於2毫秒的,在某些情況之下能夠超過2.5毫秒。GPU比4級cascades的情況下,爆漲了0.5到0.8毫秒。
我們的軟陰影採用的是泊松分佈的取樣,而且每個畫素會去做一個旋轉,來消除重複的pattern,這一整套的操作都是很重量級的。但是我們仔細想一想,真的需要對每個畫素都要做這麼多操作嗎?所以我們的優化思路是儘量只在必要的地方做軟陰影計算,我們會生成一張Mask貼圖,在貼圖裡面標出陰影、半影和非影片區。陰影區和非陰影區只需要直接返回0和1就好了,只有在半影區才會去計算軟陰影,通過這種方式,我們的GPU開銷大致減少了30%左右。甚至比採用4級cascades還要再快一些。
大家可以看一下這張圖,圖裡面被紅色標註的區域,就是我們的半影區,這個是需要我們去做軟陰影處理的區域。其他的區域,就是在陰影區域或者是非陰影區域,我們直接返回0和1就好了。大家可以看出來,絕大部分的畫素都可以去掉軟陰影計算這個繁瑣的步驟。
這張神奇的Mask貼圖是怎麼生成的呢?這張Mask貼圖的解析度是螢幕解析度的1/4×1/4,也就是說一個Mask值對應的是一個4×4的block。然後我們對4×4的block裡面的每一個畫素,來判斷它是不是在陰影中,最後彙總成一個陰影、半影和非陰影的三個狀態,儲存到Mask貼圖裡。這樣我們能夠得到一個準確的半影資訊,但是它不夠快,所以我們做了進一步的優化,只選擇4×4這個block裡面很少的幾個畫素,來判斷是不是在陰影當中。
這幾個畫素的判斷結果,就代表了整個block的資訊,顯然這樣會出現一些誤差,因為我們是拿幾個少數幾個畫素的結果來代表整個block,所以我們把這樣計算得到了Mask貼圖做了模糊處理,讓半影的區域稍微擴散出去。整個Mask貼圖的生成,包括模糊處理大概的開銷是在0.3毫秒左右。大家可以看一下對比圖。
優化出來的效果非常好,肉眼可以說是看不出任何的區別。這樣優化完之後,我們的GPU開銷時間大概穩定在1.3到1.7毫秒。
把陰影搞好以後,下面我們來看看AO(Ambient Occlusion環境光遮蔽)。大家可以考慮一種情況,就是人物和場景的物體都已經處在山或建築物的陰影當中,這個時候人物和物體的投影跟山和建築的投影是融為一體的。這種情況之下,畫面缺乏對比,人和物體就會顯得浮空。為了解決這個問題,我們在遊戲裡面採用了多種的AO技術,針對不同的情景生成不同的AO。
首先我們使用了HBAO,這是一個比較常規的實現,能夠提供一些比較細節的AO效果。同時我們對靜態物體和動態物體分別採用了AO Volume和Capsule AO這兩種技術。大家可以看一下這是HBAO開關的對比圖,效果還是很明顯的。
下面這個是AO Volume的開關情況,大家可以重點看一下我們在紅圈裡面的區域。椅子對地面產生了柔和的投影,在我們開啟AO volume的情況下。
和HBAO相比,AO Volume能夠產生更大範圍的AO。它可以針對類似桌子或者椅子產生大面積AO。因為技術原理和效能的限制,HBAO是沒辦法產生這種效果的。AO Volume這個時候就體現很好的補充,要實現AO volume,首先我們是在離線的時候對需要產生AO volume的物體做一個遮擋資訊的計算。這個計算是在物體的本地空間(Local space)去做的,生成的遮擋資訊我們儲存下來,在執行的時候注入到volume texture中去使用。這個技術在2012年GDC關於《InFamous 2》的講座上有提到過,大家有興趣可以去看一下。
下面是關於Capsule AO的對比圖,大家可以重點看一下屏風和地面,被我們紅色的圈給圈出來的區域。大家可以看到相鄰在屏風和地面,能夠產生出能夠反映體形和人影的投影。而且如果在遊戲中大家去觀察的話,隨之相鄰動作的改變,陰影的形狀也會隨之產生變化。
我們前面提到AO Volume主要是針對靜態物體的,因為遮擋資訊是通過離線計算的方式儲存下來。像角色這種帶骨骼動畫的,是不能採用這種方式的,因為形狀是不停地在發生變化。Capsule AO的做法就是用一些膠囊體包裹住人物的四肢和軀幹,這些膠囊體和角色的骨骼動畫繫結進行同步更新。然後這些膠囊體會被用來做遮擋計算,計算的時候我們把它分為無方向的環境遮擋計算,以及帶方向的遮擋資訊計算。帶方向的遮擋資訊計算採用的方向是主光源方向和法線進行混合之後的得到的虛擬遮擋方向。通過這種方式,角色可以同時在周圍的牆和地面等投出多個陰影。
下面是一個關於AO的優化技巧,《原神》的AO都是在1/2×1/2解析度的RT(Render Texture)上去做計算。為了保證畫面的乾淨,我們對AO還做了一個模糊處理(blur)。然後再Upsample一個全解析度的貼圖上面去。所有的模糊處理和Upsample pass,我們都用了一個Bilateral filter,確保不會有無效的AO滲透到周圍的區域。
從前面的描述可以看出來,模糊處理和Upsample加起來一共有三個pass,這就意味著AO需要被讀取和寫入多次。而且你如果你瞭解Bilateral Upsample的話,大家可以知道相鄰的畫素之間有很多的計算其實都是重複的,所以我們採用的優化方式是將所有的計算都放到一個compute pass裡面去做。然後通過LDS來儲存blur的中間值,通過同時輸出四個畫素的方式,來重用相鄰畫素的計算。最終我們還可以通過async compute pipe把效能開銷進一步降低。
關於我們的Local Light,我們在遊戲裡面採用了Clustered deferred lighting。我們支援是視野內同時出現最多1024盞燈。大概的做法是我們將螢幕分成64×64畫素的tile,然後每一個tile在深度的方向上面繼續分為16級的clusters。通過這兩個圖,可以大概看出我們能夠支援多少燈。
這張圖是一個遊戲裡面的截圖,是一個典型的通過Local Light的陰影提升畫面的情況,多個不同的Local Light,它們的照明範圍是交錯存在的,然後角色也投下多個不同的陰影朝不同的方向,畫面就顯得細節很豐富。
我們怎麼做的呢?我們的Local Light 陰影系統支援接近100盞燈的實時陰影,理論上我們可以支援更多的,不過這已經很夠用了。陰影的解析度是根據優先順序和距離進行動態調整,最終的陰影是通過烘焙的靜態場景陰影和實時生成的動態場景陰影結合得到的。
遊戲裡面有很多的Local Light,如果每一個Local Light都去烘焙它的shadow texture的話,會佔用的硬碟空間非常大。而且因為是深度貼圖,所以不能夠隨便使用BCn的壓縮,那樣瑕疵會非常風險,所以需要一個好的演算法來對於烘焙的shadow texture做一個壓縮。這個壓縮需要在精度損失足夠低的同時,還要保持壓縮率足夠高,同時我們的解壓開銷要非常小才行。
我們開發的這個系統是在離線製作的時候,對於shadow texture做一個壓縮,儘量地去保持精度,執行的時候解壓的速度也非常快,用compute shader去解壓的情況,1K×1K的shadow texture,我們解壓只需要0.05毫秒,可以說非常非常快。
那壓縮率和壓縮質量呢?我們先介紹一下壓縮的演算法思路。首先我們對於shadow texture按照一個2×2的block來進行編碼,每4個深度值,我們用32bit來儲存。如果想要降低精度損失,可以選擇高精度壓縮,這種情況之下每個block的大小變成64bit。編碼的方式有兩種,一種是基於深度平面方程的方式,或者是通過壓縮的浮點數方式。編碼完成之後,還要進一步通過一個quad tree來合併編碼以後的資料,進一步提高壓縮率。quad tree是每個tile要儲存一個,而每個tile又包含了16×16個block,大家可以看到下面的三個圖,從左到右分別是沒有壓縮的深度貼圖,中間是我們的平面方程編碼的檢視,最右邊是我們quad tree 0到4級的深度檢視,黑的地方是深度為0的區域。我們參考了Li Bo在2019年Siggraph上面的講座,大家有興趣可以去看一下。
壓縮比:在一個典型的室內場景預設精度壓縮比是在20:1到30:1左右。如果開啟高精度模式壓縮的話,大概預設精度壓縮到40%到70%。陰影貼圖的壓縮是非常必要的,可以幫我們容量下降一個數量級。
大家可以看一個對比,這是預設精度壓縮,能夠看到紅圈裡面有一些瑕疵。這個實際上是我們找到的可以說是最差的一個情況。這是高精度壓縮,基本上看不出任何瑕疵來。這個是預設精度壓縮。如果把高精度壓縮的圖和不壓縮的情況做對比的話,其實肉眼是看不出什麼差別,所以沒有放這個圖。
剛才的圖是一個2K×2K的shadow texture,大小如果不壓縮的話是在8MB,預設精度壓縮大小變成了274.4KB,壓縮率是29.85。如果替換成高精度壓縮,就是肉眼看不出差距的壓縮,貼圖大小變成了583.5KB,這種情況的壓縮率還是有14左右,所以還是相當不錯的。
在搞好了Local Light以後,我們接下來為遊戲新增了體積霧,體積霧是可以接受Local Light的照明影響,在燈的影響範圍內形成一圈光暈,可以極大地提升畫面的體積感。大家可以看到圖裡面近處的燈籠周圍會有一圈泛光。包括畫面遠處的建築物,因為籠罩在燈光下會使得周圍的體積霧也被照亮,而顯得有一絲的朦朧。
這個圖是一個更有意思的情況。如果我們給Local Light加一個projection texture,也就是我們通過這個貼圖來控制Local Light光照的形狀,就像右邊這樣,體積霧也會產生相應的變化。
我們的體積霧的計算是基於物理的。我們也支援通過不同的引數讓體積霧在大世界裡面的不同區域有不同的表現。體積霧支援Local Light,這個在前面已經展示過了。為了讓體積霧更加穩定,畫面更加細膩,我們給體積霧新增了Temporal filter,進行了多幀的混合。整體的GPU開銷,也控制的不錯,在PS4 Pro下面大致在1毫秒甚至更少。
大致的實現是這樣的:首先是基於相機空間,我們把view frustum分成很多的voxel,這些voxel跟我們前面提到的clustered deferred lighting的clusters是對齊的,這樣方便我們在後面對Local Light做scattering計算的時候進行一個加速。
前面提到的體積霧引數和Local Light的資訊,都會被注入到這些voxel裡面去,然後我們通過Ray marching的方式去計算體積霧。在這個時候,Local Light的資訊就自然而然被考慮進去了。
有了體積霧,我們不得不提到God Ray效果,首先大家可以先看看遊戲裡面God Ray的表現。對於方向光進行遮擋就可以產生God Ray的效果,我們的做法是有一個單獨的pass來生成God Ray,然後是在1/2×1/2解析度下面。God Ray也是通過Ray marching的方式去生成的,我們會去取樣shadow map,但是最多會取樣5級的cascades。
God Ray生成完之後,我們會提供美術一些可以調整的引數,然後將God Ray的結果疊加到體積霧上面去。它在使用上面,並不是一個物理上正確的東西,但是它的效果是能夠讓美術滿意的。
瞭解體積霧的人可能會有一個問題,為什麼要單獨使用一個pass呢?體積霧本身就可以產生God Ray。這個就是一個很好的技術和美術磨合的例子,我們有體積霧直接生成的God Ray,在遊戲裡面實際效果其實不能夠讓美術滿意,原因有兩點。第一個是解析度不夠,因為體積霧的解析度是靠Voxel,而我們的Voxel是不會劃分的特別精細的。第二是因為體積霧生成的God Ray強度是完全依賴於體積霧的濃度。要想得到很明顯的God Ray,就需要霧的濃度提的非常高。霧的濃度一旦提高了,畫面就會顯得不通透,太髒,這就是回到前面提到的兩組詞裡面,這是美術不能夠接受的。所以我們是採用了單獨的pass去生成God Ray,這樣可以得到更銳利、更清晰的效果,美術調整也更靈活。美術想要什麼,我們就給他做什麼。
下面給大家看看對比圖,大家就能更好地體會到我說的是什麼意思。這個God Ray就是通過體積霧生成的,包括整個畫面的表現。這張是我們遊戲裡面現在使用的方式,就是單獨的pass去生成,做一個對比。
大家可以看到第一張God Ray不是很明顯,而且畫面霧的濃度非常高。而第二張圖,God Ray會更清晰一些,而且整個畫面是更加乾淨、更加通透,這就是美術想要的效果。
接下來是IBL(Image Based Lighting)系統,大家先看一下演示視訊。圖中左邊的是Reflection probe(反射探針),右邊是Ambient probe,隨著24小時的變化,我們的Reflection probe和Ambient probe的內容也會跟著變化。
我們先看一下左邊的Reflection probe,Reflection probe是用來給場景提供反射資訊的。因為遊戲的光影不斷變化,我們是不能夠簡單地為反射探針烘焙一張環境貼圖作為反射資訊之用。所以對於每一個Reflection probe,我們是烘焙了一個mini GBuffer。產生在遊戲當中,根據當時的光照條件去實時生成環境貼圖,美術可以在遊戲裡面擺很多個這樣的Reflection probe,只要他們需要。
然後在執行的時候,我們會去更新場景的Reflection probe的cubemap。整個過程我們大致分為三步,第一步是Relight,第二步是Convolve和Compress。我們使用Compute Shader去同時處理六個面,然後分幀進行,同時只處理一個probe,不停地做迴圈。
第一個步驟,就是Relight步驟,大家可以通過圖能看出來,就是一個簡單的把當前的光照環境用來照亮mini GBuffer,得到環境貼圖的過程。然後生成的環境貼圖,需要經過Convolve這一步,得到mipmap的正確資訊。最後這個貼圖需要再通過一個Compute Shader的做法,壓縮成BC6H的格式,然後送到渲染管線裡面去使用。大致是這麼三步的過程。
下面是我們的Ambient probe。Ambient probe也是實時生成的。我們在做完Relight以後,Reflection probe是包含了當前的整個光照資訊,我們可以從中提取出當前的Ambient的資訊,並且把它轉化成一個3階的SH(Spherical Harmonic)係數儲存下來。
這個提取的過程,在我們把Reflection probe處理完成以後會自動進行,也是同時使用Compute Shader來處理六個面。
這麼看下來,我們整個系統算是完成了,但實際上裡面有很多地方是可以改進的。第一個是Relight是沒有陰影的,因為單靠mini GBuffer我們是沒有辦法在Relight pass生成陰影,這樣會導致一個很大的問題。就是在Relight完成得到的環境貼圖是漏光的,本來應該處於陰影當中的地面也會變得非常明亮。
通過這樣的環境貼圖算出的環境光(ambient)也會出現有問題的情況,那怎麼解決呢?我們的做法是,我們把24小時的shadow都烘焙下來,就是隔一段時間我們烘焙一下,把shadow轉化成一個shadow SH儲存起來。在執行的時候簡單通過當前的時間對shadow SH進行插值,用來壓暗Relight以後的結果。
這樣得到的效果是出乎意料的好,而且我們需要儲存的資料非常的少。因為shadow SH很糊,所以我們做插值也沒有什麼大的問題。
同樣的方式,我們還可以把Local Light的資訊也儲存下來,作為Local Light的SH在Relight的時候也加上去,這樣可以得到非常好、非常廉價的一個Local Light 反彈的效果。
大家可以看一下對比,這張圖是沒有新增shadow SH,這張是新增的,大家可以看到沒新增的情況之下,屋簷和地面都莫名其妙的亮,新增之後就能夠看出來是在陰影當中了,所以效果是很明顯的。
下面是我們把Local Light SH加進去的情況對比。這是沒有新增的,大家注意看一下畫面右上角那片屋簷下面暗的區域,這是沒有新增Local Light SH的情況。這是新增了的。那塊區域被照亮了。
我們現在已經解決了漏光的問題,並且新增了Local Light SH。接下來是一個室內室外光照環境不一致帶來的問題,因為室內和室外的光照環境往往是很不一樣的。如果不加區分的話,室內外的環境光(ambient)混在一起,得到的效果就很容易讓人家覺得不對勁。
我們是把Reflection probe分成室內、室外兩種,然後美術通過擺放一個室內環境用的網格(interior mesh)來標記受室內光影響的畫素。Ambient probe也會相應地為室內、室外生成不同的環境光。
下面看一下對比,這是沒有開的情況,如果不區分的話,室內跟室外一樣都會受天光的影響而變得很藍,然後做了室內(interior)標記,室內的畫素就能夠正確地反應出室內的光照條件,會顯得更黃一些。
而且我們還做了一個過度的處理,就是在門口這個區域當室內光照和室外光照環境切換的時候,不會出現一個因為明顯的光照差異不一樣而產生的硬邊的效果。
下面這個就是室內環境用的網格(interior mesh)生成的Mask標記圖,紅色區域就是室內的區域,大家可以看一下對照關係。
除了通過Reflection probe得到的反射,我們還有Screen space reflection來提供實時的反射資訊。SSR在PS4 Pro上面的GPU開銷大概是在1.5毫秒左右,我們對SSR也加了一個Temporal filter,通過當前幀的SSR資訊和歷史資訊混合起來,來提高SSR計算結果的穩定性,讓畫面也更平滑一些。
為了得到更多的反射資訊,我們為SSR生成了Hi-Z的buffer,我們可以讓每條射線通過Hi-Z最多能夠跟蹤的距離達到整個螢幕。
下面是一個SSR(Screen space reflection)效果開關的對比圖,在比較光滑的地板上效果尤其明顯。
從前面的截圖大家也能夠看到,在沒有SSR的情況之下,我們還有Reflection probe,它也是可以提供場景的反射資訊。我們是使用了一個Deferred reflection pass來計算Reflection和Ambient資訊。在計算Reflection的同時,我們把AO資訊也考慮進去,這樣可以有效地降低漏光。
接下來是我們的最後一個技術點,HDR Display。這裡面的HDR Display包含了兩個方面,一個方面是指亮度,需要使用PQ ST2084的EOTF,最高是能夠讓畫面亮度達到10000 nits。另外一方面就是在色彩空間這邊,我們需要支援Rec.2020色彩空間,Rec.2020色彩空間和現在普遍的電視機使用的Rec.709相比,它可以顯示的色彩範圍要大得多。大家可以看看在CIE 1931色度圖裡面的覆蓋範圍對比。Rec.2020色彩空間覆蓋範圍大概能達到75.8%,相比之下Rec.709只能在35.9%的樣子。
在這裡我們稱使用了ST2084和Rec.2020色彩空間的渲染管線為HDR管線,而使用的Rec.709色彩空間的非HDR管線,我們把他們叫做SDR管線。關於HDR Display很多基礎的資訊,有很多人都已經講過在這裡面就不細講了。下面主要講一下,為了讓這個技術放到《原神》裡面去,我們做了哪些調整。
這張圖是《原神》的SDR和HDR的管線對比圖,和SDR管線相比,HDR管線沒有了tone mapping,color grading變成了HDR的color grading。而代替tone mapping的是RRT+ODT(reference rendering transform + output display transform)的組合,這就是很多人熟悉的ACES調色。
另外,UI在HDR下面,也是單獨畫到一張RT的。然後再跟場景做一個合併,這是因為UI的亮度處理方式跟場景是不太一樣的。在圖上大家看到RRT+ODT是灰掉的,我們待會會再來細講這個事情。
《原神》從1.2開始,會在PS4上面支援HDR10的模式,然後替換SDR的Color grading是我們的HDR Color grading,美術會在Davinci這種軟體上面去做HDR校色。然後通過我們的指令碼輸出HDR的Look-Up-Table(LUT)。
在執行的時候,白平衡HDR的Color grading,還有我們的Color expansion這些操作,都會在一個compute pass裡面,輸出到一張Color的Look-Up-Table裡面去。因為這個Look-Up-Table很小,所以儘管前面提到的這些都是需要大量的計算操作,但實際上開銷是很小的,大概不到0.05毫秒。
前面管線圖的RRT+ODT部分是灰掉的,雖然這個是一個主流的調色方式,但是我們並沒有採用它,因為和我們的遊戲風格不太搭。所以儘管主流,我們還是放棄了。
為了保證在低亮度範圍內的畫面和SDR版本的遊戲一致,我們將HDR的渲染畫面和tone mapping處理之後的畫面做了一個基於亮度的混合,然後在亮度不高的地方,就儘量保證了filmic tonemapping的關於toe部分的處理。
在低亮度範圍內一致性的問題,這裡面涉及到OOTF的事情。前面我們提到在HDR上面是用了BT1886作為一個EOTF曲線,然後在裝置處理遊戲輸出的時候會用到,相應的遊戲在輸出訊號給電視機的時候也會增加一條曲線,這個就是OETF。然後在HDR的管線裡面,實際上就是一條gamma曲線。
但是這裡面存在一個問題,就是1886的gamma是2.4,但是SDR的OETF是一個分段函式,大致上可以看作是gamma 2.2,這就出現了一個問題,也就是在PPT上寫的問題。OETF處理完的顏色,經過EOTF,它得到的並不是它本身,就產生了一個誤差。
但是在HDR下面,因為我們OETF和EOTF是被很好的定義了的情況,所以他們是互逆的,於是這個顏色在經過這兩個處理之後能夠得到原來的顏色,所以在HDR下面沒有這麼一個問題。
但是大家已經習慣了在HDR下面有這麼一個誤差的畫面,所以為了模擬這個誤差,我們是在HDR管線裡面新增了OOTF,把差異給補上去了。
做完這些,是不是HDR就徹底沒問題了呢?並不是。這還有一個大坑,叫做Hue Shift。什麼解釋一下什麼是Hue Shift?舉個例子,大家可以看一下游戲裡面火焰製作的示意圖,我們通過一個灰度圖,就是下面像饅頭一樣的東西,加一個噪聲貼圖,然後進行擾動,得到了火焰擾動的紋理,然後我們用橘色去染色。最後我們把火焰的整體亮度往上提,這個時候就得到大家可以看到的見證奇蹟的時刻,在SDR下面因為有tone mapping的原因,tone mapping在亮部是有一條曲線的,會讓亮度增加逐漸變慢,於是橘色的R通道跟G通道的差異本來是很大,但是隨著亮度的增加,tone mapping曲線介入了,R通道的增長就變慢,G通道就逐漸趕了上來,於是就產生了Hue Shift,畫面漸漸開始發黃,於是就得到了後面看到的SDR下面火焰的效果。
但是這個是美術想要的一個效果,只不過他是通過這種神奇的方式得到的。但是問題來了:因為在HDR下面,我們是沒有tone mapping的,Hue Shift是不會發生的。它叫做Hue Preserving。R通道跟G通道的比例關係是得到一個保持的,所以能夠得到亮度非常高的橘色。但是在視覺上,不會讓人家覺得很明亮,因為沒有黃色。
那怎麼去修改呢?一種常用的方法,也是很多大作都用的方法,叫做黑體輻射。這是一個基於物理的演算法,美術去指定溫度,根據溫度計算出應該是什麼顏色。通過這種方式,我們是需要修改美術的資源。不過我們沒有采用這種方式,為什麼?一方面是因為HDR 這個功能是在很後期才加入的,我們不能夠讓美術去大量修改已有的資源。
另外遊戲並不是寫實類的遊戲,我們的火可以是各種顏色,而且還有很多其他的特效是隨著元素反應去轉換顏色的。所以我們自己搞了一個方法,我們在shader裡面去模擬了Hue Shift,並且把模擬放到了color grading pass裡面去,合併到Look-Up-Table的計算中。
這樣的好處是,首先我們是不需要修改任何的效果,得到的效果非常滿意,我們不僅僅是讓火焰特效在HDR下面的效果跟SDR幾乎一致。而且因為通過引入tone mapping的方式模擬了Hue Shift,所以我們前面提到的在非HDR的亮度部分的畫面一致性的問題,也被順手解決掉了,不需要跟tone mapping處理之後的畫面做混合。而且這個操作,也是在生成Look-Up-Table的時候去做的,所以它的效能增加是可以忽略不計的。
技術介紹我們就到這裡介紹了,下面是我一些個人的總結和感想。
首先是全球玩家對《原神》主機版的接受程度之高是出乎我們的預料,非常誠惶誠恐,也非常的感慨。從零開始,我把PS4版做起來,看著它逐漸地變化,就像看著自己的孩子逐漸長大一樣。隨著PS版越做越完善,很多的小夥伴就逐漸加入了開發隊伍中,於是PS4版變成了大家的孩子,大家努力讓它變得更好,最後就懷著忐忑的心情送出來跟全球玩家見面。沒想到現在這麼受歡迎,所以是一件非常有成就感的事情。而且很開心,能夠和這麼好的團隊一起做這個專案,後面我們也會繼續努,不斷地改進,也不斷地去優化,不斷地出更好的內容給大家。
就像前面提到的,《原神》的主機版開發是第一次嘗試,時間、資源和人才都很缺乏。通過一年多的開發,我們積累了很多的經驗,尤其是如何把寫實的渲染技術跟風格化遊戲結合的經驗,非常的寶貴!隨著新的主機平臺的到來,我們又面臨了一大波的技術升級。不過和在美國的時候相比,國內主機開發的從業人員太少了,希望大家能夠多多交流,和我們探討一下技術,交流一下開發經驗。
下面是我們HR拜託的一個硬廣的時間,希望大家踴躍掃描二維碼。就我個人而言,在米哈遊做遊戲、做技術是一個非常不錯的選擇,我們也很熱忱地邀請大家加入,尤其是加入主機團隊,我們需要所有崗位的大佬,一起來做次世代的遊戲。
最後是感謝!首先要感謝原神引擎團隊的所有成員,也感謝所有為《原神》主機開發出了力的大佬們!其次還要感謝主機團隊特別成員,每天被大家擼來擼去的lulu。最後是特別感謝陳文禮、Terry liu,以及各位Sony全球的技術支援專家,感謝你們在《原神》開發期間對專案的大力支援!
我這次的分享就結束了,感謝大家!
相關文章
- 我們和米哈遊技術總監弋振中聊了聊《原神》在PS5上的技術追求
- .NET Core技術研究-主機
- 《原神》技術總監弋振中:怎樣製作一款暢銷全球的跨平臺遊戲?遊戲
- 技術分享 |《原神》部分渲染效果分析(非官方)
- redis主從同步機制Redis主從同步
- mysql主從同步機制MySql主從同步
- 從動物森友會聊主機遊戲聯機機制遊戲
- 技術分享主幹
- 什麼是工控主機?工控主機安卓主機板有哪些配置?安卓
- Linux修改主機名(靜態主機名、臨時主機名)Linux
- 麥田-魅族手機主題
- 開發者中心混合雲主機接入技術探祕
- 中: 阿里映象 - 主機寶阿里
- iOS 手機振動棒iOS
- 技術與藝術的結合,HMS Core讓手機主題趣味叢生
- USB主機
- 讓手機執行主線核心
- BlueHost主機和GoDaddy主機哪個好Go
- solaris 主機修改主機名 ip地址 步驟
- HP主機訪問動態IP主機配置
- 國行版任天堂Switch來了,它能讓主機遊戲走向大眾嗎?遊戲
- Linux中主機名的作用是什麼?如何配置主機名?Linux
- 虛擬機器與主機互傳檔案方法分享虛擬機
- Linux 有問必答:如何從VirtualBox中從主機訪問NAT客戶機Linux
- 災備建設中,跨主機叢集恢復技術應用
- Linux7修改主機IP及主機名Linux
- docker 1 主機和docker2主機通訊Docker
- oracle 主機部署Oracle
- kvm主機快照
- MySQL 主從複製,雙機熱備MySql
- 部落格從 CloudBase 遷移至雲主機Cloud
- Window 10 單機配置MYSQL主從同步MySql主從同步
- 主從庫與切片叢集機制
- MySQL-技術專題-MySQL主從架構以及[半同步機制]模式大全MySql架構模式
- 錘子的理想主義手機:軟體從未如此重要
- Python獲取網路中的存活主機以及哪些主機是LinuxPythonLinux
- 手機號機主姓名核驗,簡單操作輕鬆完成!
- mongodb將備機提升為主機MongoDB