04. The-Forge 入門教程 - Raytracing
要說nVidia 20系顯卡最大的特征,那自然是加了硬件光線追蹤。NVIDIA 20系顯卡其實加入了非常多的新特性,但是在媒體宣傳上,一直以光追和DLSS為主,可能也是因為其他特性AI兩家加入并不難吧。如果看nVidia的白皮書,其實能發(fā)現(xiàn),圖靈是進(jìn)步極大的一代,安培在架構(gòu)上反而是繼續(xù)吃老本,進(jìn)步不大。
如果是入門DXR,最好的參考就行微軟的官方demo
https://github.com/microsoft/DirectX-Graphics-Samples/blob/master/Samples/Desktop/D3D12Raytracing/readme.md
本節(jié),就嘗試將微軟DXR官方demo的D3D12RaytracingHelloWorld,移植到The-Forge中。光追的代碼非常冗長,我可能就跳過代碼的講解,在文末會給我自己的代碼repo。
硬件實時光追簡介
對于光柵算法,就是把場景轉(zhuǎn)換到視錐在投影到相機(jī)的過程。光線追蹤則可以算作是該算法的逆算法,就是從相機(jī)出發(fā),反向?qū)⑸渚€從每個像素射向場景,并看最終能找到什么物體。在不透明物體上,可以直接用BRDF,通過光源的信息計算該點顏色。如果碰到鏡面,就沿發(fā)現(xiàn)對稱再射出一條光線。如果射到透明物體,折射角度發(fā)射光線。如果沒有擊中任何物體,假設(shè)擊中的天空。

簡化后的狀態(tài)機(jī)如上圖所示。
該狀態(tài)機(jī)中,硬件負(fù)責(zé)幫忙實現(xiàn)光線求交的相關(guān)部分,而用戶要自己負(fù)責(zé)Raygen,Miss,Hit的部分。
在Raygen shader中,自己可以定義一個數(shù)據(jù)結(jié)構(gòu)RayPayload。在Raygen shader中,每個像素射出一條光線,每個光線傳入一個RayPayload。之后硬件負(fù)責(zé)與整個場景求交。在最后,如果找到了交點,就會執(zhí)行closesthit shader,在closesthit shader修改RayPayload的值;反之,就會執(zhí)行miss shader,在miss shader中修改RayPayload的值。

TraceRay的實際結(jié)構(gòu)如上圖
光線求交如果光源直接遍歷所有物體所有三角形,運(yùn)算量將是天文數(shù)字。因為需要一些特殊的加速結(jié)構(gòu),現(xiàn)代主流加速結(jié)構(gòu)是BVH

D3D12RaytracingHelloWorld功能解析

場景中存在一個三角形,三角形的三個點坐標(biāo)分別為(0, 0.75,0)(-0.75,-0.75,0)(0.75,-0.75,0)
在場景中,每個像素的位置,沿著(0,0,1)發(fā)射一條射線。因此,在(0, 0.75,0)(-0.75,-0.75,0)(0.75,-0.75,0)范圍內(nèi)的射線會擊中三角形,執(zhí)行chit shader,進(jìn)行顏色插值。三角外部的點執(zhí)行miss shader,直接返回顏色float4(0.1f,?0.1f,?0.1f,?1.0f)
shader代碼
miss shader

首先是最簡單的miss shader,直接返回一個固定顏色
closesthit shader

closesthit shader的參數(shù),除了RayPayload之外,還有一個IntersectionAttributes
IntersectionAttributes有一個float2類型的參數(shù),
通過(1 - IntersectionAttributes.baryCrd.x -?IntersectionAttributes.baryCrd.y,?IntersectionAttributes.baryCrd.x,?IntersectionAttributes.baryCrd.y)可以得到光線擊中的點,在被擊中的三角形的重心坐標(biāo),依靠重心坐標(biāo)和其他三個頂點數(shù)據(jù),就可以進(jìn)行插值了。在光柵中該步驟是硬件完成的,如果寫過軟光柵或者軟光線追蹤的同學(xué)應(yīng)該對重心坐標(biāo)不會陌生,而光線追蹤中插值就要自己來了。
如果重心坐標(biāo)為(bx,by,bz)(bx + by + bz = 1)
那么該點的數(shù)據(jù)為V = bx * V0 + by * V1 + bz * V2
position,uv,color等數(shù)據(jù)都要通過重心插值得到
在本shader中,直接將重心坐標(biāo)作為顏色返回。重心坐標(biāo)顏色直接顯示也是光線追蹤渲染調(diào)試的重要依據(jù)。
raygeneration shader

在Raygen shader中,運(yùn)行TraceRay函數(shù),執(zhí)行結(jié)果會寫回payload中,然后再作為結(jié)果寫到Tex0(UAV)中即可。
c++

在03-compute的基礎(chǔ)上繼續(xù)開發(fā),c++部分的主要工作,就是生成AccelerationStructure和RaytracingShaderTable

完整代碼不再解釋,就提幾嘴我個人覺得需要很注意的點。

在pRenderer初始化時,需要把target設(shè)置到sm6.3.
shader model 6.3是dxr1.0要求的版本,dxr1.1則需要shader model 6.5

AccelerationStructure也要加到descriptorSet中
全部的源碼可以參考我的repo https://github.com/THISISAGOODNAME/leanring-The-Forge
接下來該干什么
在這個教程之后,如果還對硬件光線追蹤本身感興趣,推薦嘗試將raytracing in one weekend中實現(xiàn)的demo移植到The-Forge中。
這一系列教程可能到此就要暫停了。接下來的部分要等我搶到RTX3080或者RX6800XT以后了。可以提前預(yù)告一下,我后面想寫一些關(guān)于dx12u,sm6.5相關(guān)的內(nèi)容。
最后再一次給The-Forge 交流群打個廣告,950656923,歡迎對 The-Forge/bgfx/panda3D/horde 之類圖形中間件感興趣,或者對現(xiàn)代renderer pipeline感興趣,對mesh shader/real time raytracing/VRS/VRR等新特性感興趣的朋友加入
參考
https://github.com/microsoft/DirectX-Graphics-Samples/tree/master/Samples/Desktop/D3D12Raytracing/src/D3D12RaytracingHelloWorld
https://microsoft.github.io/DirectX-Specs/d3d/Raytracing.html
https://developer.nvidia.com/rtx/raytracing/dxr/DX12-Raytracing-tutorial-Part-2
https://www.nvidia.com/content/dam/en-zz/Solutions/design-visualization/technologies/turing-architecture/NVIDIA-Turing-Architecture-Whitepaper.pdf
https://www.nvidia.com/content/dam/en-zz/Solutions/geforce/ampere/pdf/NVIDIA-ampere-GA102-GPU-Architecture-Whitepaper-V1.pdf