提示和技巧:光线跟踪最佳实践
提示和技巧:光線跟蹤最佳實踐
Tips and Tricks: Ray Tracing Best Practices
本文介紹了在游戲和其他實時圖形應用程序中實現光線跟蹤的最佳實踐。我們盡可能簡短地介紹這些,以幫助您快速找到關鍵的想法。這是基于英偉達工程師在2019年GDC上所做的陳述。
通過修剪和選擇性更新,優化加速結構(BLAS/TLAS)構建/更新最多需要2ms。
去噪RT效果至關重要。我們已經用NVIDIA RTX Deniser SDK打包了同類產品中最好的Deniser)。
使用異步計算隊列將加速結構(BLAS/TLAS)的構建/更新和去噪,與其他機制(G緩沖區、陰影緩沖區、物理模擬)重疊。
盡可能利用硬件加速進行遍歷。
最少的光線投射應該被稱為“RT開啟”,并且應該提供比光柵化明顯更好的圖像質量。提高質量水平應能以公平的速度提高圖像質量和性能。見下表:
Performance Best Practices
1.0 Acceleration Structure Management
1.1 General Practices
作為管理(生成/更新)移動到異步計算隊列。在圖形工作負載中很好地使用異步計算隊列對,并且在許多情況下幾乎完全隱藏了成本。類似地,任何AS依賴項(例如蒙皮)也可以移動到異步計算并很好地隱藏。
構建頂級加速結構(TLAS),而不是更新。在大多數情況下,它更容易管理,而且改裝的成本節約可能不值得犧牲TLA的質量。
確保GetRaytracingAccelerationStructurePrebuildInfo和BuildRaytracingAccelerationStructure的描述符匹配。否則,分配的緩沖區可能太小,無法容納AS或scratch內存,可能會產生一個微妙的錯誤!
不要在TLA中包含skybox/skysphere。在場景中使用天空幾何體只會增加光線跟蹤時間。改為在Miss著色器中實現天空明暗處理。
在BLAS和TLAS構建之間實現單個屏障。一般來說,正確性不需要更多的要求。BLAS構建之間的重疊可以在硬件上自然發生,但是添加不必要的屏障可以序列化該工作的執行。
1.2 Bottom-Level Acceleration Structures (BLAS)
在AABBs上使用三角形。RTX圖形處理器在加速由三角形幾何創建的AS的遍歷方面表現突出。
盡可能將幾何體標記為不透明。如果幾何體不需要執行任何命中著色器代碼(例如,對于alpha測試),則始終確保將其標記為不透明,以便盡可能有效地使用HW。不透明標志是來自幾何體描述符(D3D12_RAYTRACING_geometry_flag_OPAQUE/VK_geometry_OPAQUE_BIT)、實例描述符
(D3D12_RAYTRACING_instance_flag_FORCE_OPAQUE/VK_geometry_instance_FORCE_OPAQUE_BIT)還是通過光線(ray_flag_FORCE_OPAQUE/gl_RayFlagsOpaqueNV)并不重要。
批處理/合并生成/更新調用和幾何圖形非常重要。最終,在對小批量原語執行AS操作的情況下,GPU將被占用。利用一個構建可以接受多個幾何描述符的事實,并在構建時轉換幾何體。這通常會導致最有效的數據結構,特別是當對象的aabb相互重疊時。將事物分組到BLAS/實例應該遵循空間局部性。不要“把所有有相同材料的東西扔進同一個BLAS中,不管它們最終在太空中的什么地方”。
知道何時更新,而不是(重新)構建。持續更新BLAS會降低其作為空間數據結構的效率,使遍歷/交叉查詢相對于新構建的查詢要慢得多。作為一般規則,應該只考慮動態對象進行更新。如果部分網格相對于其局部鄰域的位置發生劇烈變化,則更新后的遍歷質量將迅速下降。如果事情只是“彎曲而不是斷裂”,那么更新將非常有效。示例:樹在風中搖擺:update=good;mesh exploding:update=bad。決定更新或重建蒙皮角色:這取決于。假設最初的構建是以t-pose的形式完成的,那么每次更新都會假設腳很近。在行走/跑步動畫中,這可能會影響跟蹤效率。這里的一個解決方案是建立幾個關鍵姿勢的加速度結構,然后使用最接近的匹配作為重新裝配的來源。建議采用實驗指導的流程/工藝。
對所有靜態幾何圖形使用壓縮。壓縮速度很快,通常可以回收大量內存。當對壓縮加速度結構跟蹤光線時,性能沒有下降。
Use the right build flags.
從下表中選擇一個組合開始…
然后考慮添加這些標志:
ALLOW_COMPACTION。對所有靜態幾何體執行此操作通常是一個好主意,以回收(潛在的)大量內存。
對于可更新的幾何體,壓縮那些具有較長生存期的blas是有意義的,因此額外的步驟是值得的(壓縮和更新不是互斥的!)。
對于每幀都重建(而不是更新)的完全動態幾何體,使用壓縮通常沒有好處。
不使用壓縮的一個潛在原因是利用BLAS存儲需求隨原始計數單調增加的保證—這在壓縮上下文中不成立。
MINIMIZE_MEMORY (DXR)/ LOW_MEMORY_BIT (VK)。僅當應用程序在如此大的內存壓力下,如果不盡可能優化內存消耗,光線跟蹤路徑將不可行時才使用。此標志通常會犧牲構建和跟蹤性能。并非所有情況下都是這樣,但要注意,未來的驅動程序版本可能會有不同的行為,因此不要依賴實驗數據“確認”標志不會降低性能。
2.0 – Ray-Tracing
2.1 – Pipeline Management
避免在關鍵路徑上創建狀態對象。集合和管道編譯可能需要幾十到幾百毫秒。因此,應用程序應該預先創建所有pso(例如,在level load),或者在后臺線程上異步創建狀態對象,并在準備就緒時進行熱交換。
考慮使用多個光線跟蹤管道(狀態對象)。當跟蹤幾種類型的光線(例如陰影和反射),其中一種類型(陰影)具有幾個簡單的著色器、小的有效載荷和/或較低的寄存器壓力,而另一種類型(反射)涉及許多復雜的著色器和/或較大的有效載荷時,這尤其適用。將這些情況分為不同的管道有助于驅動程序更高效地調度著色器執行,并在更高的占用率下運行工作負載。
將負載和屬性大小設置為可能的最小值。為MaxPayloadSizeInBytes和MaxAttributeSizeInBytes配置的值直接影響寄存器壓力,因此不要將它們設置得高于應用程序/管道絕對需要的值。
將最大跟蹤遞歸深度設置為可能的最小值。跟蹤遞歸深度影響為DispatchRays啟動分配的堆棧內存量。這會對內存消耗和總體性能產生很大影響。
2.2 –Shaders
2.2.1 – General
保持射線有效載荷小。有效負載大小轉換為寄存器計數,因此直接影響占用率。像打包gbuffer那樣打包有效負載通常需要一些數學知識。大量的有效載荷會溢出到記憶中。
保持低屬性計數。與有效負載數據類似,自定義交集著色器的屬性轉換為寄存器計數,因此應保持最小值。固定函數三角形相交使用兩個屬性,這是一個很好的準則。
盡可能使用RAY_FLAG_ACCEPT_FIRST_HIT_和_END_SEARCH/gl_RayFlagsTerminateOnFirstHitNV。例如,這通常適用于陰影光線和環境光遮擋光線。請注意,使用此標志比顯式調用AcceptHitAndEndSearch()/terminateRayNV()的any hit著色器更有效。
避免跨跟蹤調用的實時狀態。通常,在TraceRay調用之前計算并在TraceRay之后使用的變量必須溢出到堆棧中。編譯器可以在某些情況下避免這種情況,例如使用重新物質化,但通常溢出是必要的。因此,材質球一開始越能避開它們,效果越好。在某些情況下,當陰影復雜度非常低并且沒有遞歸TraceRay調用時,將一些活動狀態放入有效負載中以避免溢出是有意義的。然而,這與保持有效載荷小的愿望相沖突,所以要非常明智地使用這個技巧。
避免著色器中的跟蹤調用過多。著色器中的許多TraceRay調用可能會導致次優性能和著色器編譯時間。嘗試構造代碼,使多個跟蹤調用合并為一個。
明智地使用循環展開。如果所述循環包含跟蹤調用(前一點的必然結果),則尤其如此。復雜的材質球可能會受到展開循環的影響,而不是從中受益。嘗試HLSL中的[loop]屬性或GLSL中的顯式展開。
嘗試無條件執行TraceRay調用。保持TraceRay調用不使用“if”語句可以幫助編譯器簡化生成的代碼并提高性能。不要使用條件,嘗試將光線的tmin和tmax值設置為0以觸發未命中,并且(如果需要正確的行為)使用無操作未命中著色器以避免意外的副作用。
Use
RAY_FLAG_CULL_BACK_FACING_TRIANGLES / gl_RayFlagsCullBackFacingTrianglesNVjudiciously。與光柵化不同,光線跟蹤中的背面消隱通常不是性能優化,它可以導致執行更多而不是更少的工作。
2.2.2 – Ray-Generation Shaders
確保每個光線生成線程生成一個光線。在最終不會產生任何光線的光線生成著色器中調度/分配線程可能會損害調度。這里可能需要人工壓實。
2.2.3 – Any Hit Shaders
保持任何擊中陰影極簡。任何命中著色器在每一個TraceRay中執行多次(與最近的命中或未命中著色器相比,例如,后者只執行一次),這使得它們非常昂貴。此外,任何命中都在調用圖中寄存器壓力最高的點執行。所以為了獲得最佳性能,盡可能讓它們變得微不足道。
2.2.4 – Shading Execution Divergence
從一個簡單的著色實現開始。當實現需要大量材質著色(例如反射或GI)的技術時,性能可能會受到著色散度的限制。這通常有許多原因,但不限于:指令緩存抖動和/或發散內存訪問。采用以下策略來解決這些問題:
使用簡化的著色器優化指令發散:
使用較低質量或簡化的材質球(相對于光柵化)進行光線跟蹤。
在某些極端情況下(例如:漫反射GI或粗糙鏡面反射),可以從視覺上接受完全回落到頂點級別的著色(這也有減少噪聲的附加好處)。
通過以下方法優化發散內存訪問:
降低紋理訪問的分辨率-或偏移mip貼圖級別
將光線跟蹤著色器中的照明計算推遲到幀中的稍后點
在極端情況下,可能需要手動安排(分類/裝箱)陰影。當上述優化策略不足時,應用程序可以手動安排著色。但是,這會阻止基于driver/HW的調度生效。英偉達不斷改進我們的日程安排。
2.3 – Resources
對場景全局資源使用全局根簽名(DXR)或全局資源綁定(VK)。這將避免在本地每幾何體根表中進行復制,并應導致更好的緩存行為。
避免資源臨時性。這通常會導致非原語代碼重復。例如,將一個紋理保留在一個臨時的位置,并根據某些條件對其進行指定,將導致每個可能的紋理指定的所有采樣操作重復。可能的解決方法:使用資源數組并動態索引到其中。
同時訪問64位或128位對齊的本地根表數據可以實現矢量化加載。
對于對齊的原始數據,首選StructuredBuffer而不ByteAddressBuffer。
3.0 – Denoisers
使用RTX去噪SDK實現高質量、快速的光線跟蹤效果去噪。您可以在GameWorks光線跟蹤頁面找到更多詳細信息。
4.0 -Memory Management
對于DXR,將QueryVideoMemory API報告的預算視為軟提示。實際節段大小大約大20%。
將命令分配器隔離到不同類型的命令列表。如果可以避免,不要將非DXR-CAs與DXR-CAs混合和匹配。
命令分配器重置將不會釋放關聯的內存。可以使用destroy/create釋放這些分配,但必須在關鍵路徑之外執行此操作,以避免長時間暫停
注意管道的堆棧大小。堆棧大小隨著TraceRay調用中保持的活動狀態的數量和TraceRay調用周圍的控制流復雜性而增加。最大跟蹤深度實際上是堆棧大小的一個直接乘法器——盡可能保持低的深度。
手動管理堆棧(如果適用)。使用API的查詢函數來確定每個著色器所需的堆棧大小,并應用關于調用圖的應用程序端知識來減少內存消耗和提高性能。一個很好的例子是在trace depth 1上使用昂貴的反射著色器來拍攝陰影光線(trace depth 2),應用程序知道這些陰影光線只會命中堆棧要求較低的小命中著色器。驅動程序無法預先知道此調用圖,因此默認的保守堆棧大小計算將過度分配內存。
重用臨時資源。例如,為BVH構建重用scratch內存資源以用于其他目的(可能是非光線跟蹤)。在DXR上,使用放置的資源和第2層資源堆。
5.0 – Profiling and Debugging
請注意以下工具,其中包括對DirectX光線跟蹤和NVIDIA的VKRay的支持。它們發展很快,所以請確保使用最新版本。
NVIDIA Nsight圖形。為光線跟蹤開發人員提供了優秀的調試和分析工具(著色器表和資源檢查器、加速結構查看器、范圍分析、扭曲占用和GPU度量、通過NVIEW后的崩潰調試、C++幀捕獲)。
NVIDIA Nsight系統。提供系統范圍的分析功能和口吃分析功能。
微軟PIX
FAQ
Q、 基本體的數量和加速結構構建/更新的成本(時間)之間的關系是什么?
A、 基本上是線性關系。好吧,它開始變得線性超過某個原始計數,在此之前,它被常數開銷所限制。這里的確切數字在不斷變化,不可靠。
Q、 假設最大占用率,加速結構構建/更新的GPU吞吐量SOL是多少?
A、 一個數量級準則是:對于完整構建,O(1億)原語/秒;對于更新,O(10億)原語/秒。
Q、 RT-PSOs的唯一著色器數量與編譯成本(時間)之間的關系是什么?
A、 它大致是線性的。
Q、 現在游戲中RT-PSO編譯的典型成本是多少?
A、 任何地方,20 ms→300 ms,每條管道。
Q、 有沒有關于應該使用多少alpha/透明度的指導?任何命中和最近命中的代價是什么?
A、 任何打擊都是昂貴的,應該使用最少。最好將幾何體(或實例)標記為不透明,這將允許在固定功能硬件中進行光線遍歷。當需要AH時(如評估透明度等),盡可能簡單。不要僅僅為了執行alpha-tex查找和if語句而計算巨大的著色網絡。
Q、 開發人員應該如何管理陰影差異?
A、 首先在最近的命中著色器中著色,在一個簡單的實現中。然后分析perf并決定問題分歧的程度以及如何解決。解決方案可能包括也可能不包括“手動調度”。
Q、 開發人員如何查詢堆棧內存分配?
A、 API具有在管道/著色器上查詢每個線程堆棧需求的功能。這對于跟蹤和分析非常有用,應用程序應該盡可能少地使用著色器堆棧(一個建議是在開發期間轉儲堆棧大小直方圖和標記異常值)。堆棧需求最直接地受到跟蹤調用的實時狀態的影響,這應該最小化(請參閱最佳實踐)。。
Q、 一個典型的光線跟蹤實現需要額外消耗多少VRAM?
A、 今天,實現光線跟蹤的游戲通常使用1到2 GB的額外內存。主要影響因素是加速結構資源、光線跟蹤特定屏幕大小的緩沖區(擴展g緩沖區數據)和驅動程序內部分配(主要是著色器堆棧)。
總結
以上是生活随笔為你收集整理的提示和技巧:光线跟踪最佳实践的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于OpenSeq2Seq的NLP与语音
- 下一篇: 视频系列:RTX实时射线追踪(上)