基於RTX的NVIDIA OptiX光線追蹤

基於RTX的NVIDIA OptiX光線追蹤

光線追蹤與光柵化

自20世紀90年代以來,傳統的3D渲染通常會採用一種被稱為光柵化的流程。光柵化使用基於三角形或多邊形網格創建的對象來構建物體的3D模型。然後渲染管線將3D模型的每個三角形轉換成2D圖像平面上的像素。這些像素最終在屏幕上顯示之前,還可能會被進一步處理或「著色」。雖然光柵化對於實時生成圖像非常有效,但為光柵化管線添加逼真的光照效果會使複雜性提升,因此就需要基於給定場景手動進行許多參數調整。要想維持良好的性能,通常需要通過剪切或處理掉不可見的一些物體面,或進行估計,這可能會影響整體的逼真感。而光線追蹤是實現更高逼真度的重要一步。

光線追蹤通過模擬光線的物理行為來生成高度逼真的圖像。光線追蹤通過追蹤光線從觀者的眼睛穿過虛擬3D場景的路徑來計算像素的顏色。光線在穿過場景時可能會從一個物體反射到另一個物體(引起反射)、被物體阻擋(引起陰影)、或穿過了透明或半透明物體(模擬半透明或電介質,如玻璃或水)。所有這些交互結合起來就產生了屏幕上所顯示像素的最終顏色。如圖1所示,保真度不會受影響,且演算法可完美地實施,但需要大量複雜的計算工作量。

圖1. 這是一張計算機生成圖像,由Enrico Cerica使用OctaneRender生成,其顯示了複雜地板表面上的光線追蹤陰影和反射

光線追蹤原理

光線追蹤可直接模擬穿過虛擬環境的光線。圖2顯示了由相機、一組光線、3D幾何模型及其材質描述所構成的環境。然後對代表光路或光子的光線進行追蹤,以確定相機感測器在給定方向上所感知的光線值。光線追蹤通常會遵循如下順序:

  1. 創建代表從環境到相機的光路的反向路徑。
  2. 光線與場景相交,確定光線射中哪個物體(如果有的話)。
  3. 材質著色器或環境著色器計算光路中的光照值。
  4. 最後,得出的光照值被寫入Framebuffer。

圖2.簡化的光線追蹤圖解

第3步通常是通過生成額外的光線來確定入射光會投射到物體的某一位置點,因此可以說光線追蹤屬於遞歸演算法。

基於GPU的光線追蹤

為什麼光線追蹤會被視為計算機渲染的未來?原因就在於其創建照片級寫實圖像的能力。如今的光線追蹤渲染器主宰著虛擬效果製作和動畫特效領域。大規模並行GPU的出現擴展了光線追蹤的應用空間。從前採用主流CPU時需要幾小時才能完成的離線渲染現在使用GPU只需要幾分鐘的時間。如今NVIDIA GPU與NVIDIA最先進的光線追蹤技術堆棧配合使用,提供了相應的計算能力和軟體框架,可在消費者級工作站執行實時光線追蹤工作負載。

NVIDIA在3月的GTC上宣布新款Quadro? GV100支持RTX技術。開發者可通過多種API訪問NVIDIA RTX技術,具體取決於其需求和開發環境,如圖3所示。

圖3. NVIDIA RTX技術

  • 微軟的DirectX Raytracing(DXR)API。將光線追蹤功能完全集成到遊戲開發者所採用的行業標準API DirectX中,使光線追蹤成為光柵化與計算的補充,而非其替代品。DXR專註於通過光柵化和光線追蹤技術的混合型技術,來處理用戶案例。
  • NVIDIA的Vulkan光線追蹤擴展程序。是Vulkan圖形標準的光線追蹤擴展程序,也是在跨平台API中實現光線追蹤和光柵化技術緊密耦合的另一種途徑。
  • NVIDIA的OptiX API。是基於GPU實現高性能光線追蹤的應用程序框架。它為加速光線追蹤演算法提供了一個簡單、遞歸且靈活的管線。OptiX SDK包含兩個可相互獨立使用的主要組件:用於渲染器開發的光線追蹤引擎和post process管線來處理最終顯示的像素。
  • 所有這三種API共享同一種描述光線追蹤操作的方法,使開發者能夠便利地通過多個平台訪問RTX。十年來在渲染軟體和硬體方面的投入鑄就了高度優化的光線追蹤解決方案,實現了前所未有的性能和交互性水平。NVIDIA還大舉投資工具鏈的開發,使得GPU編程、調試和分析比以往更加容易。

有關DXR的更多信息,可查看

如何評價 NVIDIA RTX Technology??

www.zhihu.com圖標

今年GTC大會也演示了Vulkan擴展程序,現在讓我們來看看OptiX API。

圖4. 光線追蹤在概念層面簡單,但計算層面卻複雜

NVIDIA設計了OptiX API來填補基於NVIDIA GPU的簡單概念模型和相對高級的執行模型之間的差距,使開發者能夠專註於其核心光線追蹤演算法,如圖5所示。OptiX基於一個主要洞察而構建,即大多數光線追蹤演算法可通過一小套可編程操作來實施。OptiX提供了一個描述虛擬環境的API和一組用戶可編程著色器來實施光線追蹤周期的每個階段。

圖5. OptiX中的用戶可編程著色器顯示為綠色。遍歷是通過OptiX進行內部控制。

OptiX的核心是一個特定領域的實時編譯。編譯器通過結合用戶提供的光線生成、材質著色、對象相交和場景遍歷的程序來生成自定義光線追蹤內核。高性能是通過使用緊湊型對象模型和光線追蹤編譯器優化實現的,可有效地映射到全新RTX技術和Volta GPU。

OptiX支持各類用例,包括互動式渲染、離線或批量渲染、碰撞檢測系統、人工智慧查詢、以及聲音傳播或中子傳輸等科學模擬。OptiX已集成到各種當前可用的商業軟體產品中,且近十年來一直是重要的光線追蹤SDK。

使用OptiX的主要優勢包括:

  • 可編程GPU加速光線追蹤管線,可根據應用需求輕鬆定製
  • 提供完全支持遞歸的單光線編程模型和類似於虛擬函數調用的動態調度機制
  • 最先進的數據結構可極快地實現光線與對象相交
  • 支持渲染大型場景,可通過跨多個GPU的透明縮放、以及通過NVLink自動組合多個GPU顯存來實現
  • OptiX利用最新的GPU架構特性,無需在應用方面進行更改
  • 一種基於AI的降噪器,可改善用戶在實時探索中的體驗
  • 其靈活性支持任意著色模型,包括基於物理的MDL材料規範的實施示例
  • 全面的編程指南、參考文檔和示例,可幫助您快速將OptiX集成到應用程序中
  • NVIDIA RTX技術和Volta GPU強大性能的直觀界面

光線生成程序

光線路徑中的第一個光線段通常稱為主光線,它使用光線生成程序。它追蹤場景中的光線,將追蹤結果寫入輸出緩衝區。以下是一個非常簡單的光線生成程序示例。

// The user can define an arbitrary struct to carry data associated with a ray// and to return values from the trace.struct PerRayData{ float4 result; // Output variable for results. We could track other // information here as needed.};rtDeclareVariable(CameraParams, camera_params, , ); // Input parameters describing // the camera model.rtDeclareVariable(rtObject, scene_root_group, , ); // The top level group // containing scene description.rtBuffer<float4, 2> output_buffer; // Output buffer to store rendered // image.rtDeclareVariable(uint2, launch_index, rtLaunchIndex, ); // OptiX built-in variable containing // the current index into launch grid. // Usually this corresponds to pixel // index in the output image.rtDeclareVariable(uint2, launch_dim, rtLaunchDim, ); // OptiX built-in variable containing // the size of the launch grid. Usually // this corresponds to the dimensions // of the output image.RT_PROGRAM void pinhole_camera(){ // Create a primary ray by modeling a pinhole camera. Alternatively we could read // pre-generated rays from an input buffer or use some other method. const float3 ray_origin = pinholeCameraGetOrigin(camera_params); Const float3 ray_direction = pinholeCameraComputeDirection(camera_params, launch_index, launch_dim); optix::Ray ray = optix::make_Ray( ray_origin, // camera position ray_direction, // direction from origin to pixel position on screen plane 0u, // ray-type (see documentation) scene_epsilon, // minimum intersection distance RT_DEFAULT_MAX); // maximum intersection distance // Initialize our per-ray data structure and call the built-in function rtTrace PerRayData prd; Prd.result = make_float4(0.0f); rtTrace(top_object, ray, prd); // Write results into buffer. Once a launch is finished, this output buffer is typically // drawn to the screen or written to an image file. output_buffer[launch_index] = prd.result;

場景遍歷程序

OptiX利用最先進的空間分區層次數據結構,可非常快速地剔除虛擬場景中沒有與給定光線相交的部分。Optix核心編譯器控制著這些數據結構的創建和遍歷。這使得OptiX可隱藏高度優化的架構特定性實施的複雜性,並將NVIDIA多年的研究成果應用於遍歷加速結構。

Intersection和Bounding Box程序

可採用用戶定義Intersection和Bounding Box程序來實施自定義基元,如球體、曲線或細分補丁。Bounding Box程序必須計算自定義基元的對象空間軸對齊邊界框。根據輸入光線是否與基元相交,Intersection程序返回true或false。以下每種類型程序的簡單示例演示了如何實施球體基元。

rtDeclareVariable(float4, sphere, , ); // Input variable giving sphere center, radiusrtDeclareVariable(float3, normal, attribute normal, ); // Attribute variables allow data passing from intersection // program to hit programsrtDeclareVariable(optix::Ray, ray, rtCurrentRay, ); // Built-in variable provided by OptiXRT_PROGRAM void intersect_sphere(){ float3 center = make_float3(sphere); // Extract sphere』s center position float radius = sphere.w; // Extract sphere』s radius float3 n; // Output parameter for the surface normal float t; // Output parameter for the intersection distance if(intersect_sphere(ray, center, radius, n, t)) // Determine if the ray hits the sphere and, if so, // at what distance { if(rtPotentialIntersection(t)) // Tell OptiX that the ray intersects the sphere. OptiX // will check if the intersection distance lies within the // current valid ray interval and return true/false // accordingly. { normal = n; // Output attributes are always written to between // rtPotentialIntersection and rtReportIntersection const int material_id = 0; rtReportIntersection(material_id); // Report intersection with material ID } }}// Takes primitive index for use with multi-primitive Geometries (eg, triangle meshes)RT_PROGRAM void bounds (int /*primitive_index */, float result[6]) { const float3 center = make_float3( sphere ); const float radius = make_float3( sphere.w ); optix::Aabb* aabb = (optix::Aabb*)result; // Cast float array to helper data type for ease of use aabb->m_min = center - make_float3(radius); aabb->m_max = center + make_float3(radius); }

Closest-Hit與Any-Hit程序

Closest-hit和any-hit程序協同工作,以實現材質著色器的功能。OptiX允許開發者指定一種或多種類型的光線(例如輻射、環境光遮蔽或陰影光線)。材質可指定closest hit和any-hit程序來描述對象與每種光線類型相交時的著色行為。Hit程序通過屬性變數從intersection程序接收信息。它們通過寫入ray payload將信息傳遞迴光線生成程序。

當光線追蹤核心完全穿越場景並找到當前光線有效距離區間內的最近交點時,將調用closest-hit程序。最終著色通常發生於這一階段。功能齊備的著色系統可能會評估基於物理的反射函數,並生成二次光線來評估反射、折射和光線遮蔽。

在遍歷場景時發現新的可能的最近對象時,any-hit程序就會被調用。Any-hit程序都可對當前的潛在交點採取以下三種操作之一:

  • 通過調用rtIgnoreIntersection可忽略相交。這可在諸如透明alpha剪切的情況下否認交叉。
  • 光線遍歷可以通過調用rtTerminateRay來終止。這通常用於點對點可見性測試,因為在兩點之間能夠找到任何對象都足矣。
  • 交點可被接受,但遍歷繼續。如果既不調用rtIgnoreIntersection也不調用rtTerminateRay ,則默認如此。

對於任何給定的材質光線類型slot,any-hit和closest-hit程序都可能保持未綁定狀態。例如,一種不透明的材質可能只需要一個any-hit程序來遮蔽光線,因為找到光線和陰影點之間的任何交點就足以確定一個點在陰影中。另一方面,不透明材料通常只針對輻射光線採用closest-hit程序。

以下是針對一種不透明材料的一對非常簡單的hit程序示例,它僅通過對象表面法線的可視化來遮蔽物體。

// Often, any-hit and closest-hit programs use differing ray payload structs, depending on what data they want to// return to the ray-generation program. For simplicity we will use a single type. struct PerRayData{ float4 result; // Radiance value for closest hit, shadow opacity for any-hit};rtDeclareVariable(PerRayData, prd, rtPayload,); // Built-in providing access to this ray』s payload structrtDeclareVariable(float3, normal, attribute normal, ); // Attribute specified by our intersection programsRT_PROGRAM void normal_shader_closest_hit_radiance(){ // Transform the object normal into world space and convert to a color const float3 world_space_normal = optix::normalize(rtTransformNormal(RT_OBJECT_TO_WORLD, normal)); Const float3 color_normal = world_space_normal*0.5f + 0.5f; prd.result = make_float4(color_normal, 1.0f);}RT_PROGRAM void normal_shader_any_hit_shadow(){ // this material is opaque, so it fully attenuates all shadow rays prd_shadow.result = make_float3(0.0f); // We terminate this ray since we only want to know if any geometry is hit, not the closest rtTerminateRay();}

Miss程序

如果沒有幾何體被光線射中,則調用miss程序。Miss程序可根據光線類型指定,也可能保持未綁定狀態。Miss程序用於實施環境地圖或無限遠處的背景。以下是一個用戶可指定單色背景環境的程序。

struct PerRayData{ float4 result; // Radiance value for closest hit, shadow opacity for any-hit};rtDeclareVariable(float4, bg_color, , ); // Input variable for the background colorrtDeclareVariable(PerRayData, prd, rtPayload, ); // Built-in providing access to this ray』s payload struct RT_PROGRAM void miss(){ prd_radiance.result = bg_color;}

性能

OptiX可在一系列NVIDIA GPU上運行,但使用Volta GPU可實現最佳性能,如圖6所示。

圖6. NVIDIA GPU上的OptiX性能

使用NVIDIA OptiX增強創造力

使用NVIDIA OptiX的渲染軟體(例如Autodesk Arnold、Chaos Group V-Ray、Isotropix Clarisse、Optis、Pixar RenderMan和Solidworks Visualize)在NVIDIA Volta架構GPU上運行時會自動採用RTX技術。

OptiX AI降噪技術與Quadro GV100和Titan V中的全新NVIDIA Tensor Cores相結合,可提供相當於前代GPU 3倍的性能,並首次實現了無雜訊流體交互。

NVIDIA正改變著渲染、乃至整個設計過程。藉助NVIDIA Volta GPU和NVIDIA? RTX?光線追蹤技術,您可以通過電影畫質般的實時渲染來增強創造力,從而實現更佳的效果並迅速作出決策。您可以與客戶在房間中探索設計,對照明和材料進行實驗,從而互動式地準確模擬真實世界的光線條件。

了解更多有關OptiX的信息,請訪問NVIDIA OptiX開發者頁面,包括詳細文檔的鏈接以及獲取OptiX的方式。


推薦閱讀:

AB是一家?VAO與VBO
關於雜訊...
《一周學習光線追蹤》(三)紋理和柏林雜訊
計算機圖形學常用術語整理

TAG:NVIDIA英偉達 | 3D渲染 | 計算機圖形學 |