1. 程式人生 > >WebGPU+光線追蹤Ray Tracing 開發三個月總結

WebGPU+光線追蹤Ray Tracing 開發三個月總結

大家好~這三個月以來,我一直在學習和實現“基於WebGPU的混合光線追蹤實時渲染”的技術,使用了Ray Tracing管線(如.rgen、.rmiss等著色器)。 現在與大家分享和介紹我目前的學習成果,希望對大家有所幫助!謝謝! # 通過國外的開源專案,可在WebGPU中使用Ray Tracing管線 這三個月我對Ray Tracing的研究有了質的突破,主要歸功於我發現的[WebGPU Node](https://github.com/maierfelix/webgpu)開源專案! 該作者首先在[dawn-ray-tracing](https://github.com/maierfelix/dawn-ray-tracing)開源專案中對“dawn專案:Chrome對WebGPU的實現"進行了擴充套件,加入了光追的API; 然後在[WebGPU Node](https://github.com/maierfelix/webgpu)開源專案中,底層封裝了Vulkan SDK,上層使用了dawn-ray-tracing專案,提供了WebGPU API,實現了在Nodejs環境中使用WebGPU API和Ray Tracing管線來實現硬體加速的光線追蹤(電腦需要使用nvdia的RTX顯示卡)! 相關介紹參見: [Real-Time Ray-Tracing in WebGPU](http://maierfelix.github.io/2020-01-13-webgpu-ray-tracing/) ## 搭建執行環境 有兩種方法來搭建執行環境: 1、給Chrome瀏覽器打補丁,使其與下載DXR驅動(DirectX Raytracing)關聯,從而在該瀏覽器中執行 詳見該作者最近寫的開源專案:[chromium-ray-tracing](https://github.com/maierfelix/chromium-ray-tracing) (我沒有測試過,不知道是否能使用) 2、編譯[dawn-ray-tracing](https://github.com/maierfelix/dawn-ray-tracing)和[WebGPU Node](https://github.com/maierfelix/webgpu)專案,從而在Nodejs環境中執行 我使用的是這個方法(不過我使用的[WebGPU Node](https://github.com/maierfelix/webgpu)專案是今年3月份時的程式碼,最新的程式碼我還沒有測試過)。 我的作業系統是win7,顯示卡是RTX 2060s,vulkan sdk是1.1.126.0版本 編譯的步驟為(需要使用VPNFQ): ``` # 編譯dawn-ray-tracing專案 ## Clone the repo as "dawn-ray-tracing" git clone https://github.com/maierfelix/dawn-ray-tracing cd dawn-ray-tracing ## Bootstrap the gclient configuration cp scripts/standalone.gclient .gclient ## Fetch external dependencies and toolchains with gclient gclient sync set DEPOT_TOOLS_WIN_TOOLCHAIN=0 npm install --global --production windows-build-tools gn gen out/Shared --ide=vs --target_cpu="x64" --args="is_component_build=true is_debug=false is_clang=false" ninja -C out/Shared # 編譯webgpu node專案 npm install webgpu 在webgpu node的根目錄中建立名為“PATH_TO_DAWN”的檔案,在其中指定dawn-ray-tracing專案的絕對路徑,如: D:/Github/dawn-ray-tracing 在webgpu node的根目錄中執行: npm run all --dawnversion=0.0.1 ( 這裡要注意的是,需要先安裝Vulkan SDK和python; 可以通過“npm config set python C:\depot_tools\python.bat”來設定python路徑,或者指定python路徑: npm run all --dawnversion=0.0.1 --python="C:\Users\Administrator\Downloads\depot_tools\bootstrap-3_8_0_chromium_8_bin\python\bin\python.exe" ) # 在nodejs中執行ray tracing示例,驗證是否成功 進入webgpu node的根目錄 cd examples & cd .. node --experimental-modules examples/ray-tracing/index.mjs ``` # 應用場景 考慮到WebGPU還沒有正式釋出,並且可能在三年內瀏覽器都不會支援Ray Tracing管線,所以我把渲染放到雲端,這樣就可以在雲端自行搭建環境(如使用WebGPU Node開源專案),然後通過網路傳輸將渲染結果傳輸到客戶端,從而在客戶端瀏覽器不支援的情況下仍能顯示光追渲染的畫面。 因此,我的應用場景為: 1、雲渲染 2、雲遊戲 這兩個應用場景有不同的需求: “雲渲染”屬於離線渲染,我們關心的是: - 畫質要好 - 渲染時間可以長點 因此: - 每幀可採樣多次,即n spp(n >= 30) - 支援多種渲染效果,如“焦射”(causicts)等 - 全域性光照可使用n次bounce(n >= 2) “雲遊戲”屬於實時渲染,我們關心的是: - 畫質可以差點 - 渲染時間要短(每幀30ms以內) 因此: - 每幀只採樣一次,即1 spp - 全域性光照只使用一次或兩次bounce - 對“焦射”(causicts)等場景用效能好的方案達到接近的渲染效果,通過犧牲畫質來減少渲染時間 # 介紹我目前的實現方案 主要技術框架是“實時混合光線追蹤”,主要包含下面的pass: 1、gbuffer pass 建立gbuffer 2、ray tracing pass 直接從gbuffer中獲取world position、diffuse等資料,用來計算直接光照,從而減少了每個像素髮射的光線數量; 每個像素髮射1個shadow ray,用來計算直接光照的陰影; 如果只用1個bounce來計算全域性光照的話,每個像素髮射1個indirect ray+1個shadow ray,用來計算間接光照。 3、denoise pass 基於[BMFR演算法](http://www.tut.fi/vga/publications/Blockwise_Multi-Order_Feature_Regression_for_Real-Time_Path_Tracing_Reconstruction.html)來實現降噪,具體可參考本文後面的“實現降噪Denoise”部分。 4、taa pass 使用taa來抗鋸齒 相關程式碼可見我的開源專案: [WebGPU-RTX](https://github.com/yyc-git/WebGPU-RTX) # 介紹我學習的整個流程,分享相關資料 ## 瞭解光線追蹤的相關領域 我通過下面的文章進行了初步的瞭解: [一篇光線追蹤的入門](https://zhuanlan.zhihu.com/p/41269520) [光線追蹤與實時渲染的未來](https://zhuanlan.zhihu.com/p/34851503) [實時光線追蹤技術:業界發展近況與未來挑戰](https://zhuanlan.zhihu.com/p/102397700) [Introduction to NVIDIA RTX and DirectX Ray Tracing](https://devblogs.nvidia.com/introduction-nvidia-rtx-directx-ray-tracing/) [如何評價微軟的 DXR(DirectX Raytracing)?](https://www.zhihu.com/question/269149582) ## 實現第一個光追的Demo 通過學習下面的資料: [Ray Tracing in One Weekend](http://www.realtimerendering.com/raytracing/Ray%20Tracing%20in%20a%20Weekend.pdf) [Ray Tracing: The Next Week](http://www.realtimerendering.com/raytracing/Ray%20Tracing_%20The%20Next%20Week.pdf) [Ray Tracing in One Weekend和Ray Tracing: The Next Week的詳解](https://www.cnblogs.com/lv-anchoret/category/1368696.html) [基於OpenGL的GPU光線追蹤](https://zhuanlan.zhihu.com/p/51387524) 我參考資料中的程式碼,用WebGL 2實現一個Demo: ![](https://img2020.cnblogs.com/blog/419321/202006/419321-20200627175159769-555922735.png) 該場景的紅圈中是一個球,附近有一個球形光源和一個矩形光源 因為沒有進行降噪,所以噪點太多了哈哈! 相關程式碼可見我的開源專案: [Wonder-RayTrace](https://github.com/Wonder-Technology/Wonder-RayTrace) ## 學習和實現Ray Tracing管線 通過學習[NVIDIA Vulkan Ray Tracing Tutorial](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR/)教程,我用 js語言+[WebGPU Node](https://github.com/maierfelix/webgpu)開源專案 基於Ray Tracing管線依次實現了陰影、反射等基礎渲染效果。 該教程使用了VK_KHR_ray_tracing擴充套件,而[WebGPU Node](https://github.com/maierfelix/webgpu)開源專案也使用了該擴充套件(Vulkan SDK),因此該教程的shader程式碼幾乎可以直接用到該開源專案中。 [教程程式碼](https://github.com/nvpro-samples/vk_raytracing_tutorial_KHR) ## 用Reason重寫 我用[Reason語言](https://reasonml.github.io/)重寫了示例程式碼,提煉了一個基礎架構。 ## 學習GBuffer+Ray Tracing混合管線 因為我希望優先減少渲染時間,所以我要通過混合管線來進行實時渲染。 我通過[A Gentle Introduction To DirectX Raytracing](http://cwyman.org/code/dxrTutors/dxr_tutors.md.html)教程來學習和實現。 [教程程式碼下載](http://cwyman.org/code/dxrTutors.Code.zip) 我學習了該教程的第一篇到第11篇,分別實現了建立GBuffer、使用Lambertian材質渲染、多光源的陰影等內容。 ## 實現降噪Denoise 教程的[第9篇](http://cwyman.org/code/dxrTutors/tutors/Tutor9/tutorial09.md.html)通過每個畫素對每個光源發射一個shadow ray,最後累加並計算平均值,實現了多光源的陰影。 教程的[第11篇](http://cwyman.org/code/dxrTutors/tutors/Tutor11/tutorial11.md.html)對第9篇進行了改進:為了減少每個像素髮射的shadow ray的數量,每個畫素只隨機向一個光源發射一個shadow ray。 這樣會導致噪點,如下圖所示: ![](https://img2020.cnblogs.com/blog/419321/202006/419321-20200627180211593-1135305863.png) 我們可以通過累計取樣數來不斷逼近無噪點的圖片(如該教程的[第6篇](http://cwyman.org/code/dxrTutors/tutors/Tutor6/tutorial06.md.html)一樣),但這樣需要經過長時間後才會收斂,所以只適合“雲渲染”這種離線渲染的應用場景。 累加一定幀數後,結果如下圖所示: ![](https://img2020.cnblogs.com/blog/419321/202006/419321-20200627180852746-1953908106.png) ### 實現taa 降噪演算法通常需要先實現“幀間的資料複用”,而TAA抗鋸齒也需要實現“幀間資料複用”的技術;而且降噪演算法會使用TAA作為最後一個pass來抗鋸齒。所以我決定先實現taa,將其作為實現降噪演算法的鋪墊。 我參考了下面的資料來實現taa: [DX12渲染管線(2) - 時間性抗鋸齒(TAA)](https://zhuanlan.zhihu.com/p/64993622)、 [相關程式碼](https://github.com/MrySwk/GravityEngine/blob/master/GEngine/GDxRenderer/Shaders/TaaPassPS.hlsl) [Unity Temporal AA的改進與提高](https://zhuanlan.zhihu.com/p/46841906)、 [相關程式碼](https://github.com/Hengle/Unity-GPU-Driven-Pipeline/blob/master/Assets/PostProcessing/Shaders/Builtins/TemporalAntialiasing.shader) [unit Temporal Anti-Aliasing](https://liangz0707.github.io/whoimi/blogs/RTR/TAA.html) ### 實現BMFR降噪演算法 為了能應用於“雲遊戲”這種實時渲染的應用場景,我們需要快速降噪。因此我實現了BMFR演算法來降噪。 降噪前場景: ![](https://img2020.cnblogs.com/blog/419321/202006/419321-20200627181019015-1268635518.png) 降噪後場景: ![](https://img2020.cnblogs.com/blog/419321/202006/419321-20200627181026025-937868782.png) 我參考了下面的資料: [BLOCKWISE MULTI-ORDER FEATURE REGRESSION FOR REAL-TIME PATH TRACING RECONSTRUCTION](http://www.tut.fi/vga/publications/Blockwise_Multi-Order_Feature_Regression_for_Real-Time_Path_Tracing_Reconstruction.html) [參考程式碼](https://github.com/gztong/BMFR-DXR-Denoiser) ## 學習蒙特卡羅積分(monte carlo)的理論 教程的[第11篇](http://cwyman.org/code/dxrTutors/tutors/Tutor11/tutorial11.md.html)隨機向一個光源發射一個shadow ray,這其實已經使用了蒙特卡羅積分的理論。 我們可以通過下面的資料深入學習該理論,瞭解概率密度函式(pdf)、重要性取樣等相關概念,為我們後面實現全域性光照打下理論基礎: [【RAY TRACING THE REST OF YOUR LIFE 超詳解】 光線追蹤 3-1 蒙特卡羅 (一)](https://www.cnblogs.com/lv-anchoret/p/10327692.html) 到 [【RAY TRACING THE REST OF YOUR LIFE 超詳解】 光線追蹤 3-7 混合概率密](https://www.cnblogs.com/lv-anchoret/p/10604712.html) [光線追蹤器Ray Tracer:進階篇](https://yangwc.com/2019/05/23/RayTracer-Advance/) ## 實現全域性光照 通過學習教程的[第12篇](http://cwyman.org/code/dxrTutors/tutors/Tutor12/tutorial12.md.html),我實現了one bounce的全域性光照。 更多參考資料: [Global Illumination and Path Tracing](https://www.scratchapixel.com/lessons/3d-basic-rendering/global-illumination-path-tracing) [Global Illumination and Monte Carlo](https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-837-computer-graphics-fall-2012/lecture-notes/MIT6_837F12_Lec18.pdf) 這裡我遇到的問題主要是處理indirect specular noise:噪點不穩定,導致降噪後不穩定(高光周圍有明顯波動)。 我首先以為是pdf寫錯了,結果修改了pdf後還是沒有改進; 然後希望通過clamp等方法移除這些高光的fireflies噪點,結果影響到了畫質; 最後採用了“取樣indirect specular/diffuse多次”來穩定噪點。這適用於“雲渲染”的離線渲染,但不適用於“雲遊戲”的實時渲染。 ## 基於GGX模型,實現disney BRDF 通過學習教程的[第14篇](http://cwyman.org/code/dxrTutors/tutors/Tutor14/tutorial14.md.html),我引入了pbr材質,實現了GGX模型,加入了多bounce的全域性光照。 我對教程程式碼進行了改進: 在.rgen著色器中使用for迴圈而不是遞迴來實現的多bounce; 實現了disney BRDF,在pbr材質中有diffuse、roughness、metallic、specular這幾個引數。 更多參考資料: [基於物理著色(二)- Microfacet材質和多層材質](https://zhuanlan.zhihu.com/p/20119162) [基於物理著色(三)- Disney和UE4的實現](https://zhuanlan.zhihu.com/p/20122884) [基於物理的渲染(PBR)白皮書 | 迪士尼原則的BRDF與BSDF相關總結](https://zhuanlan.51cto.com/art/201904/594881.htm) [WebGPU-Path-Tracer](https://github.com/maierfelix/WebGPU-Path-Tracer) 實現了disney BRDF ## 目前的渲染效果 ![](https://img2020.cnblogs.com/blog/419321/202006/419321-20200627181756867-1335598038.png) # 我目前的實現需要改進的地方 ## 在Ray Tracing pass中支援紋理 使用bindless texture或者virtual texture來實現 ## 擴充套件disney BRDF,實現BSDF,支援透明、折射效果 ## 增加後處理 如gamma矯正等 ## 在雲端環境下多執行緒渲染 雲端天然具有並行的優勢,因此可將渲染任務分配到多個顯示卡/伺服器中執行。 ## 改進降噪效果 BMFR對高光specular處理得不好。 為了應用在“雲渲染”中,需要提高畫質。因此可考慮: - 改進BMFR對specular的處理 BMFR論文中已有相關的討論 - 使用專門對多個spp取樣進行降噪的降噪器來替代BMFR 因為BMFR主要是針對1 spp取樣,所以需要使用針對蒙託卡羅積分路徑追蹤的降噪器來替代 ## 改進indirect specular/diffuse noise 現在我通過增加spp來增加噪點的穩定性,這在“雲遊戲”中行不通,因為只能有1 spp。因此可考慮: - 使用blue noise 可參考: http://psgraphics.blogspot.com/2018/10/flavors-of-sampling-in-ray-tracing.html https://hal.archives-ouvertes.fr/hal-02158423/file/blueNoiseTemporal2019_slides.pdf https://belcour.github.io/blog/research/2019/06/18/animation-bluenoise.html https://zhuanlan.zhihu.com/p/90017623 - 對GGX模型使用VNDF來代替NDF取樣 - 對多bounce的indirect specular noise進行優化 可能的解決方案: 使用reflection denoise filter; adaptive multiple bounce; - 使用photon mapping來降