熱門
比肩原生4K畫質,《永劫無間》搭載DLSS流程公開
自 2021 年 8 月全球發布以來,大逃殺類新作《永劫無間》在全球掀起了一波又一波的游戲狂潮。游戲源自中國玄幻的美術風格給世界各地的玩家們留下了極為深刻的印象。
作為網易的獨立子公司,24 Entertainment 工作室在其首款桌面端游戲《永劫無間》就搏得了開門紅,迅速吸引了全球玩家的目光。游戲在發布第一周內便登上 Steam 排行榜前 10 名,活躍玩家數超過《彩虹六號:圍攻》、《Splitgate》等熱門游戲。
這場大逃殺式的動作冒險將場景設立在五光十色的山巔、郁郁蔥蔥的森林和斷壁殘垣的古城中,每一個都蘊含了驚人的細節。為了抓住環境的美感,以足夠的性能和幀率支撐多達 60 人的多人游戲,24 Entertainment 與知名技術企業 NVIDIA 和 Unity 展開了親密合作。
在與 NVIDIA 的合作中,24 Entertainment 提前用上了深度學習超采樣 (DLSS) 技術:一項以渲染高幀率、高分辨率實時圖形為目的的新渲染技術。DLSS 可借助人工智能舉重若輕地增強圖形性能和整體質量。
為了維持高性能,《永劫無間》以低分辨率渲染,避免了像素著色計算等流程。在運行期間,DLSS 將利用神經網絡生成高分辨率圖像,為玩家們保留美術細節。這樣一來,游戲不僅能生成高質量的圖像,還能借助人工智能填補圖像缺失,使得渲染速度提高幾乎一倍,這對于如此大體量的多人競技游戲非常關鍵。
在 DLSS 的幫助下,24 Entertainment 成功實現了高幀率、高分辨率和高清細節??梢哉f,DLSS 的 4K 幾乎可以比肩原生 4K。Unity 2021.2 版本將支持并維護 DLSS 技術。
經過訓練的 AI 能參考前幾幀畫面進行渲染,輔助抗鋸齒等功能。并且,同一游戲的神經網絡模型無須再度訓練即可處理各種畫面。
《永劫無間》中的DLSS
在幾年前《永劫無間》的開發初期,團隊在 Unity 可編程渲染管線(SRP,一種支持添加自定義C#渲染架構的管線)的基礎上建立了自己的渲染管線。
在 NVIDIA 的 Developer Relations 專家及 Unity Core Support 的支持下,24 Entertainment 還率先在 Unity 中應用了 DLSS 技術。
為了幫助其他開發者更深入地了解 DLSS 在實時環境下的運作機制,《永劫無間》的圖形開發團隊披露了部分技術應用細節、提示及開發時遇到的挑戰。
高采樣(Upsampling)
DLSS 應用的第一步是在低分辨率圖像中進行高采樣。
部分24 Entertainment需要解決的難題
為了降低采樣對最終畫面的影響,24 Entertainment 將這一步放在了泛光、色調映射、特效光等后處理效果之前,所有后處理效果都應用在了采樣后的高清圖像上。
整個管線的運行流程如下:
第 1 步:將畫面設為高質量模式,再使用 NVIDIA 的 getOptimalsettings 接口來計算輸入數據大小和最佳清晰度。不同的質量模式有著不同的圖像縮放比例。
第 2 步:使用 NVIDIA 的 CreateFeature 接口在各個攝像機中抓取特征,據此設置質量模式、輸出圖像大小及銳化程度。銳化后的輸出圖像可包含更多細節。
第 3 步:在后處理之前使用以下代碼執行 DLSS 推算:
commandBuffer.ApplyDLSS(m_DLSSArguments);
準備輸入數據
團隊稍微調整了渲染管線來保證輸入圖像可以兼容 DLSS。
由于低分辨率圖像需要按一定比例進行放大,游戲窗口需要緩存到 G-Buffer(Geometry Buffer,包含色彩、法線、坐標信息的緩存紋理)中,才能正確在管線中行進,而窗口必須以正確的比例重新創建。
pixelRect = new Rect(0.0f, 0.0f,
Mathf.CeilToInt(renderingData.cameraData.pixelWidth * viewportScale),
Mathf.CeilToInt(renderingData.cameraData.pixelHeight * viewportScale));
commandBuffer.SetViewport(pixelRect); // RenderScale Supported
渲染完成后,DLSS的源圖像大小、目標大小、目標色彩渲染和目標深度等參數將根據低分辨率原圖進行設定。
int scaledWidth =
UpSamplingTools.Instance.GetRTScaleInt(cameraData.pixelWidth); int scaledHeight =
UpSamplingTools.Instance.GetRTScaleInt(cameraData.pixelHeight);
// Set the argument m_DLSSArguments.SrcRect.width = scaledWidth; m_DLSSArguments.SrcRect.height = scaledHeight;
m_DLSSArguments.DestRect.width = cameraData.pixelWidth;
m_DLSSArguments.DestRect.height = cameraData.pixelHeight;
m_DLSSArguments.InputColor = sourceHandle.rt;
m_DLSSArguments.InputDepth = depthHandle.rt
信號抖動偏移(Jitter Offset)
接下來的問題是輸入圖像的 Jitter Offset,這一步與時域上的樣本積累有關。
在渲染時,著色器如果只渲染三角形所覆蓋的像素,會導致光柵化圖元變得分散,生成有鋸齒、不自然、邊緣不光滑的圖像。
如果渲染的分辨率更高,則圖像亦會變得精細、自然起來。然而,如果缺少分散的圖像樣本,要想生成連續的圖像信號會變得非常困難,更有可能產生鋸齒。
在 4K 分辨率下,鋸齒現象的確可以通過提高分辨率來緩解。但在 8K 分辨率下,此方法會導致渲染速度慢近四倍,并且很可能會產生紋理帶寬(內存使用)的問題。
另一種常見的抗鋸齒方法是由 GPU 硬件驅動的多重采樣抗鋸齒(Multisample Anti-aliasing,常稱為MSAA)。MSAA 除了檢測像素的中心點外,還會檢測亞像素位置的樣本。三角形片元的色彩將根據圖元覆蓋的樣本數量進行調整,來讓圖像邊緣更顯平滑。
時域抗鋸齒 (TAA) 是另一種跨幀累積樣本的方法。該方法將在每一幀上抖動采樣位置,接著利用運動矢量混合幀之間的渲染色彩。
如果每個幀像素過去的色彩都可被識別,我們就可以利用這些過去的像素進行抗鋸齒。
抖動(Jitter)通常是指像素采樣位置的輕微調整,以達到累積多幀樣本的目的,免去了一次性解決欠采樣的必要。
24 Entertainment 之所以轉而采用 DLSS,就是因為它不僅降低了渲染分辨率的要求,而且還生成邊緣平滑的高質量圖像。
我們推薦在 DLSS 中使用的采樣模式包括 Halton 序列,一種看似隨機、覆蓋更均勻的低離散度序列。
Halton序列:
https://en.wikipedia.org/wiki/Halton_sequence
在實踐中,Jitter Offset 的應用可以非常簡單。要想實現高效的應用,可以參考以下步驟:
第 1 步:在特定攝像機中根據 Halton 序列生成不同圖像設定下的樣本。輸出信號的抖動量應該在 -0.5 到 0.5 之間。
Vector2 temporalJitter = m_HalotonSampler.Get(m_TemporalJitterIndex, samplesCount);
第 2 步:將抖動量存儲到一個 Vector4 中,將其乘以 2、再除以縮放后的分辨率,來將其應用到屏幕空間的單位像素上。將結果存儲到 zw 組件中。
然后,使用這兩個值修改投影矩陣、改變總體的渲染結果:
m_TemporalJitter = new Vector4(temporalJitter.x, temporalJitter.y,
temporalJitter.x * 2.0f /
UpSamplingTools.GetRTScalePixels(cameraData.pixelWidth),
temporalJitter.y * 2.0f /
UpSamplingTools.GetRTScalePixels(cameraData.pixelHeight) );
第 3 步:將視圖投影矩陣設置為全局屬性 Unity_MATRIX_VP。頂點著色器會調用相同的函數來轉換屏幕上的世界位置,而將矩陣歸入該屬性可免去修改著色器的必要。
var projectionMatrix = cameraData.camera.nonJitteredProjectionMatrix;
projectionMatrix.m02 += m_TemporalJitter.z; projectionMatrix.m12 += m_TemporalJitter.w;
projectionMatrix = GL.GetGPUProjectionMatrix(projectionMatrix, true); var jitteredVP = projectionMatrix * cameraData.viewMatrix;
運動矢量
在解決 Jitter Offset 問題后,接下便是借助工具生成運動矢量。
運動著的攝像機和對象會改變屏幕圖像,而要根據多幀樣本來生成圖像,則我們還需要抓取對象的前一位置。
例如,當攝像機的位置從 q 變為 p 時(如圖所示),屏幕上的某個點很可能會被投射到另一個點上。將這兩個點相減便能得到此次運動的矢量,即前一幀相對于當前幀的位置。
運動矢量可采用如下步驟計算:
第 1 步:在管線的深度信息通道中計算對象的運動矢量。通道中的深度信息主要用于描繪對象距攝像機的距離,輔助系統檢測“景深”。
第 2 步:根據前一幀的攝像機 View Projection 矩陣移動窗口、抓取前一窗口位置,再填補新像素。
第 3 步:在 DLSS 中寫入矢量相關的屬性。
我們可以根據不同的清晰度(分辨率)來計算對應的運動矢量,通過按比例縮放矢量來實現想要的結果。這里,24 Entertainment 將矢量設為了負的寬高比。DLSS 要求運動矢量以像素為單位,而團隊在屏幕空間中生成運動矢量,
之所以使用負號,是為了在管線中互換減數(當前幀)和被減數(前一幀)的位置。
m_DLSSArguments.MotionVectorScale = new Vector2(-scaledWidth, -scaledHeight); m_DLSSArguments.InputMotionVectors = motionHandle.rt;
《永劫無間》渲染循環集成概述
24 Entertainment 的渲染管線結合了延遲渲染和前向渲染。為了節省內存,所有渲染對象都在放大之前作了分配。
DLSS 管理器會使用 RTHandle 系統在攝像機創建之際分為渲染對象分配一次內存,省去為每次攝像機循環都分配一次內存的必要。
RTHandle 系統:
https://docs.Unity3d.com/Packages/com.Unity.render-pipelines.core@12.0/manual/rthandle-system-using.html
再到深度通道中生成運動矢量(僅包括運動對象),來實現時域上的 Jitter Offset 等效果。接著,在屏幕通道中生成攝像機的運動矢量。
DLSS 管理器支持在后處理開始時使用 RTHandle 系統為放大后的渲染對象分配內存。
到這里,DLSS 推算已經能獲取除信號抖動以外所有參數信息了,再加上信號抖動就可以實現時域化采樣了。
《永劫無間》的渲染管線帶有一個可以緩存攝像機 Halton 采樣階段索引和矩陣抖動與否等信息的系統,并且所有光柵化步驟都采用了 View Projection 和 Jitter 矩陣,除了矢量通道。矢量通道采用的是無抖動的矩陣。
24 Entertainment
關于充分利用DLSS的提示和技巧
Mip Map Bias
Mip Map 是一種預先計算好的、分辨率逐級遞減(后者為前者的二分之一)的圖像序列。它們可以有效地逐級過濾紋理,然后在原紋理中對所有組成屏幕像素的紋素進行采樣。
在下例中,遠離攝像機的對象會在低分辨率的 Mip Map 中被采樣,從而生成更符合實際的結果。
在為 DLSS 采集紋理樣本時,一定要添加 Mip Map Bias。DLSS 與棋盤渲染等其他類似的上采樣方法一樣,需要在較高的分辨率下進行采樣才能渲染出低分辨率的窗口圖像。這時,在高分辨率下還原出的紋理不會顯得模糊。
Mip Map Bias可使用以下方法計算:
MipLevelBias = log2(RenderResolution.x / DisplayResolution.x)
如果輸出為負,你可以利用偏差值回滾為更高分辨率的圖像。只有設置了 Mip Map Bias,DLSS 才能在采集低分辨率紋理樣本時維持圖像質量不變。
緩存特征供攝像機使用
我們應該在攝像機上緩存抓取的 DLSS 特征。
為了反映攝像機尺寸和質量模式的變更,DLSS 必須抓取新的特征。有時,多個大小和質量模式相同的攝像機需要同時使用 DLSS 渲染。但每個特征都是根據前一幀的信息總結而來,某個特征只能適用于特定攝像機。
在《永劫無間》中,24 Entertainment 以每臺攝像機的哈希值作為鍵值將各個特征緩存到了一個字典中,藉此保證每個特征只能被對應的攝像機使用。
commandBuffer.ApplyDLSS(m_DLSSArguments, cameraDescriptor);
切忌將 DLSS 與其他抗鋸齒方法混合使用。最后,不要將 DLSS 與其他抗鋸齒方法組合使用。作為一種新技術,DLSS 與其它抗鋸齒方法一同使用可能會產生不可預測的瑕疵。
Unity 2021.2中的DLSS
Unity 與 NVIDIA 有著緊密的技術合作關系,Unity 引擎和 HDRP 都已經集成了 DLSS 及上述所有功能,進一步的集成開發也將展開!
Unity 將自 2021.2 版本起支持并維護所有 NVIDIA 技術。以下為 NVIDIA 技術集成至 Unity 的詳情:
?
引擎核心的 DLSS 集成
在引擎內核中,我們專門為 DLSS 模塊編寫了一層恰當的 C# API。這一層代碼還負責處理平臺兼容性、引擎內的 #define(用于在運行平臺上屏蔽特定的DLSS代碼)以及提供正確的說明文檔,它屬于在 SRP 中調取完整 DLSS 的官方 API,也是其它可編程渲染管線的整合基礎。
說明文檔:
https://docs.Unity3d.com/2021.2/Documentation/ScriptReference/NVIDIA.GraphicsDevice.html
HDRP 中的圖形集成
DLSS 以動態分辨率系統(DRS) 功能的形式應用在了 HDRP 中,功能也使用了上述的腳本 API。
動態分辨率系統(DRS) 功能:
https://docs.Unity3d.com/Packages/com.Unity.render-pipelines.high-definition@12.0/manual/Dynamic-Resolution.html
我們以《永劫無間》的 TAA 抖動算法為基礎,在后處理之前類似地應用了分辨率上采樣,再并以全分辨率渲染后處理效果。
并且 Unity 的 DLSS 還有了一點改進:應用以動態分辨率系統為基礎,允許實時切換分辨率。動態分辨率系統可完全兼容 RTHandle 系統,并支持硬件驅動的 DLSS(基于紋理鋸齒)及軟件驅動的分辨率修改(基于游戲窗口)。而前邊提到的 Mip Map Bias 功能可用于所有 DRS 過濾器和技術。
為了減少粒子重影現象,我們建立了一個特殊的渲染通道,來保證動態分辨率系統與其它 HDRP 功能的兼容。
此外,我們還建立了一個包含 DLSS 版本信息和幀狀態等信息的調試面板。最后,DLSS 現在支持 VR、實時光追、DX11、DX12 和 Vulkan。
在Unity 2021.2中使用DLSS
首先確認項目使用的是 Unity 2021.2 版本(Unity 2021.2 版本現已正式發布,可通過 Unity Hub 下載),以及確保項目中使用的渲染管線為 HDRP。
啟用 DLSS 的方法如下:
第 1 步:按照下圖中的步驟找到安裝 NVIDIA 軟件包的 Fix 按鈕。
打開 Project Settings 窗口
在 Quality 設置下找到 HDRP 配置界面
選擇當前項目使用的 HDRP 配置
找到 Rendering 渲染功能配置組
找到 Dynamic resolution(動態分辨率)組(DLSS 是通過 HDRP 的 Dynamic resolution 功能來提供的)
可以看到提示說 DLSS 功能還未被激活:NVIDIA Deep Learning Super Sampling (DLSS) is not active in this project. To activate it, install the NVIDIA package. 點擊 Fix(修復)按鈕激活 NVIDIA DLSS 功能
第 2 步:安裝完畢以后可以在 Dynamic resolution 參數組中啟用 DLSS,并選擇調整相關參數。
第 3 步:最后在場景主攝像機中啟用 DLSS。
電話:010-50951355 傳真:010-50951352 郵箱:sales@www.gentlemenlisten.com ;點擊查看區域負責人電話
手機:13811546370 / 13720091697 / 13720096040 / 13811548270 /
13811981522 / 18600440988 /13810279720 /13581546145