天天看點

提示和技巧:光線跟蹤最佳實踐

提示和技巧:光線跟蹤最佳實踐

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_RayFlagsCullBackFacingTrianglesNV judiciously。與光栅化不同,光線跟蹤中的背面消隐通常不是性能優化,它可以導緻執行更多而不是更少的工作。

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緩沖區資料)和驅動程式内部配置設定(主要是着色器堆棧)。