當前位置: 華文星空 > 知識

UE5的nanite和DX12U的meshshader有什麽不同?

2021-05-29知識

不,mesh shader更加先進。nanite則是在不能對硬件動刀的前提下,采用軟件針對特定套用的一種特定的實作。

從概念的範疇來說,nanite是UE5當中,針對高面數模型在引擎當中的使用,給出的一種「純軟件」的實作。當然,它對硬件有一定的要求,但是並非對硬件提出了專用的客製化要求,而只是需要支持Compute Shader的GPU,以及滿足一定頻寬需求的硬件環境。

而mesh shader是硬件升級本身帶來的產物,其本身改變了硬件的設計,改變了GPU渲染管道的流程,可以看作是CS的一種特化,是一個軟硬結合的方案,用途也並非僅僅是針對高面數模型,且其自身也並不包括數據的組織方式和載入(串流)方式。

但是在解決高面數模型的渲染問題方面,nanite和mesh shader的確是有異曲同工之妙。這是因為,據我所知,這兩個技術其實應該都是來自一個共同的起源:用CS實作三角形的篩選(culling),然後再將結果交給通常的渲染管道渲染。這一過程通常被稱為dispatch draw。

dispatch draw的出現,是因為隨著畫面的提升,一幀畫面要處理的模型面數越來越多。在DX9級別的固定管線GPU當中,三角形首先以頂點+索引流的方式進入VS階段,完成一系列座標變換之後,才會被後續的PA模組組裝成為三角形送入後續的SC模組,也就是離散化模組進行離散。

這樣的處理在近代的高品質遊戲渲染當中,出現幾個顯著的問題。VS的過程是基於頂點的,而且近代的遊戲會在頂點上附著很多內容:比如兩套甚至兩套以上的uv、頂點色、法線、tangent、高度圖等等。這些內容值都需要在VS過程當中處理,並且結果需要儲存。

因此VS通常在執行之前,GPU的排程模組需要為其分配片上緩存區域,進行結果的儲存。這個分配過程本身開銷較大,而且片上緩存十分金貴,一般只能儲存十幾個頂點這樣,後續的SC則需要對附著在頂點上的所有內容完成插值,並且在後續的PS完成對這些值的參照之後,相應的緩存才能釋放。

也就是說,VS計算本身是相當占用片上資源的。然而,DX9的傳統管線缺乏在VS之前對頂點進行篩選的能力,所有的三角形,無論大小,都是一個三角形3個頂點,需要進行VS處理。很多微小三角形最終畫面面積可能只有幾個甚至不足一個像素,卻要完整地經歷3個頂點的VS處理。

也就是,如果從最終畫面角度來看,各個頂點的VS計算對於最終畫面的「面積貢獻度」不是恒定的。這是由於VS基於頂點,而不是基於三角形的處理方式導致的。

所以,在出現CS之後(CS本身為什麽會出現,又是另外一個故事了,篇幅原因這裏不贅述,和GPGPU的出現有關),一些渲染方面的老手,開始著手用CS解決VS的這個問題,也就是在執行VS之前,先用CS按照三角形的概念對頂點和索引進行一遍過濾,調整頂點的「畫面面積貢獻度」之後,再交給VS處理。

這個成果在實際的商業遊戲當中得到運用和檢驗(抱歉我忘記了是哪款遊戲了)(評論區補充:源起15年大革命的cluster rendering和17年ea的visibility buffer,可以補充上~[愛] @SaeruHikari ),並且在siggraph上面進行了發表。很可能N社和Nanite的作者都是看到了這個發表,然後分別用自己的屁股進行了思考。

N社的屁股是硬件,所以自然而然反思了VS本身的實作,將其輸入從頂點+index拓展到primitive+頂點+index,也就是在考慮頂點的同時考慮三角形本身,並且在這個基礎上進一步拓展(泛化)成為輸入數據格式可以任意自訂,在shader內透過一系列計算直接輸出最終需要渲染的頂點和index流給SC,這就是mesh shader。

而Nanite的作者的屁股是UE4,這麽一個跨平台引擎。所以自然以當時廣泛的技術條件為基礎,也就是CS為實作手段,考慮如何進一步提升效率的問題。其結果就是進一步統合dispatch draw的上下遊。首先是對於上遊,吸收Virtual Texture的經驗,將模型以層級方式進行組織,以流送的方式載入並且用CS進行基於三角形的culling,選擇出對於當前畫面必須的頂點送入後續處理。並且在此基礎上統合下遊,將VS負責的部份,甚至是部份PA+SC的部份也直接合並到CS當中,減少GPU在不同stage之間切換的開銷,將不同stage之間數據的傳遞轉化為同一個stage內的寄存器數據傳遞,提升效率。

nanite的這種做法的好處是其泛用性,對硬件要求相對較低。但是自然也無法完全享受硬件升級帶來的所有好處。可以預見在幾個版本叠代之後,nanite應該會切換到改用mesh shader實作的方式。(或者至少,加入對mesh shader的支持)