DirectX光线追踪-弹出



在2018年,Microsoft宣布将光线跟踪API(DXR)作为DirectX 12的一部分。光线跟踪方法迫使人们彻底重新考虑渲染3D场景的方式,从而将经典的栅格化方法转换为背景。 API正在现代化,正在开发更高效的GPU,可视化程序包开发人员正在尝试新的可能性。但是,即使在功能最强大的图形卡上,功率也足以在每个像素上产生几束光,以确保稳定的帧频。另外,性能在很大程度上取决于材质和场景的复杂性。但是即使在今天,用于降噪和照明结果累积的高级算法也可以实现高度逼真的效果。所有这些激发了在这一领域进行实验的动力。



GPU光线跟踪相对较新。 2009年,DirectX 11推出了计算着色器-这推动了非图形计算的发展。但是,加速结构的设计完全落在程序员的肩膀上,这减慢了开发速度。专门的交叉库已经普及,例如AMD的Radeon Rays。在DXR中,加速结构以黑匣子原理表示,并且交点使用特殊的硬件块发生。光线跟踪也已添加到Vulkan中,作为Nvidia卡VK_NV_ray_tracing的扩展。 2020年3月,通过一些较小的更改,发布了VK_KHR_ray_tracing扩展,它不再是特定于供应商的,可能会包含在Vulkan 1.3规范中。计划在2020年底之前为AMD进行全面的光线追踪。无处不在的支持使这项技术更具前景。



DXR . — . , . , , , . , (, ). , (hit, miss, procedural hit, closest hit), , , , . pipeline .





DXR- GPU Nvidia RTX 2060 . Windows SDK 19041 ( , Miscrosoft ), IDE Visual Studio 2019, C++.





DXR , raygen-. ID3D12GraphicsCommandList4::DispatchRays() c , TraceRay(). top level acceleration structure. , . , , , (closest hit). , .





miss hit-. payload — . DirectX, global root signature. per-shader , local root signature Shader binding table. , .





:



  • bottom-level, top-level acceleration structures
  • raytracing pipeline
  • shading binding table (SBT) — per-shader


.



Bottom-level acceleration structure (BLAS)



, — . BLAS . BLAS . . BLAS GPU, command list . , BLAS (scratch-). DirectX 12, API, ID3D12Device5::GetRaytracingAccelerationStructurePrebuildInfo. D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE — .



D3D12_RAYTRACING_GEOMETRY_DESC — BLAS. ( index-buffer ):



D3D12_RAYTRACING_GEOMETRY_DESC geometryDesc = {};
geometryDesc.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES;
geometryDesc.Triangles.IndexBuffer = 0;// GPU-address index- (  )
geometryDesc.Triangles.IndexCount = 0;
geometryDesc.Triangles.IndexFormat = 0;//  DXGI_FORMAT_R16_UINT;
geometryDesc.Triangles.VertexFormat = DXGI_FORMAT_R32G32B32_FLOAT;
geometryDesc.Triangles.VertexCount = < >;
geometryDesc.Triangles.VertexBuffer.StartAddress = <GPU-address  >;
geometryDesc.Triangles.VertexBuffer.StrideInBytes = sizeof(Vertex);


BLAS:



D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS bottomLevelInputs;
bottomLevelInputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY;
bottomLevelInputs.Flags = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_TRACE;
bottomLevelInputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL;
bottomLevelInputs.pGeometryDescs = &geometryDesc;
bottomLevelInputs.NumDescs = 1;

D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC bottomLevelBuildDesc = {};
bottomLevelBuildDesc.Inputs = bottomLevelInputs;
bottomLevelBuildDesc.ScratchAccelerationStructureData = scratchResource->GetGPUVirtualAddress();
bottomLevelBuildDesc.DestAccelerationStructureData = bottomLevelAccelerationStructure->GetGPUVirtualAddress(); // ID3D12Resource* bottomLevelAccelerationStructure -    


BLAS:



dxrCommandList->BuildRaytracingAccelerationStructure(&bottomLevelBuildDesc, 0, nullptr);


Top-level acceleration structure (TLAS)



TLAS BLAS . BLAS , . TLAS BLAS — scratch-. , scratch-, TLAS BLAS. TLAS :



    D3D12_RAYTRACING_INSTANCE_DESC instanceDesc[2] = {};

    for (int i = 0; i < 2; ++i)
    {
        instanceDesc[i].Transform = YourEngineTransformToDXR(transforms[i]);
        instanceDesc[i].InstanceMask = 1;
        instanceDesc[i].InstanceID = 0; //  
        instanceDesc[i].InstanceContributionToHitGroupIndex = i; //     hit SBT
        instanceDesc[i].AccelerationStructure = bottomLevelAccelerationStructure->GetGPUVirtualAddress();
    }


TLAS (D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC) BLAS.



Raytracing pipeline



graphic compute raytracing pipeline state object — . RT pipeline -, . CD3DX12_STATE_OBJECT_DESC CreateSubobject(< >).



  1. . BytecodeLength pShaderBytecode D3D12_SHADER_BYTECODE, SetDXILLibrary() DefineExport(). 3- : raygen, hit, miss.
  2. Hit group (CD3DX12_HIT_GROUP_SUBOBJECT). hit group-, . SetHitGroupExport, SetHitGroupType(D3D12_HIT_GROUP_TYPE_TRIANGLES). hit-group, .
  3. (CD3DX12_RAYTRACING_SHADER_CONFIG_SUBOBJECT). payload — , TraceRay , closest hit — 2 float.
  4. (CD3DX12_RAYTRACING_PIPELINE_CONFIG_SUBOBJECT). 1.
  5. root signature (CD3DX12_LOCAL_ROOT_SIGNATURE_SUBOBJECT). , hit-. SBT ( ).
  6. local root signatore c hit group (CD3DX12_SUBOBJECT_TO_EXPORTS_ASSOCIATION_SUBOBJECT). root signature SetSubobjectToAssociate() AddExport().
  7. root signature (CD3DX12_GLOBAL_ROOT_SIGNATURE_SUBOBJECT). , . SetComputeRootDescriptorTable, SetComputeRootShaderResourceView SetComputeRoot32BitConstants.


Shader binding table (SBT)



SBT — . , , . , GPU-, . .



shader record. TLAS , — . . TLAS BLAS, TraceRay(), .



3 : ray generation, hit miss, , , . , . GPU- , DispatchRays(). shader record-.



shader record-a . raygen miss , shader record-a . , , , root signature, SBT. shader record D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT ( 32 ).



void*, GetShaderIdentifier() ID3D12StateObjectProperties, COM- raytracing pipeline. raygen- (miss ) :



ComPtr<ID3D12StateObjectProperties> stateObjectProperties;
dxrStateObject.As(&stateObjectProperties);
void* rayGenShaderIdentifier = stateObjectProperties->GetShaderIdentifier(L"RayGen");


. SBT raygen miss .



hit float4 . SBT root signature: virtual GPU-address/GPU-handle. constant buffer, hit SBT shader record-. 32- 4x4- , 48, - 64 . :







vertex-fragment shader 3: raygen, hit, miss.



raygen:



#include "Common.hlsl"
#include "Global.hlsl"

struct CameraData
{
    float4 forward;
    float4 right;
    float4 up;
    float4 origin;
};

ConstantBuffer<CameraData> gCamera : register(b0);

[shader("raygeneration")] 
void RayGen() 
{
    HitInfo payload;
    payload.colorAndDistance = float4(0, 0, 0, 0);

    uint2 launchIndex = DispatchRaysIndex().xy;
    float2 dims = float2(DispatchRaysDimensions().xy);

    float2 ndc = float2(
        float(launchIndex.x + 0.5f) / dims.x * 2 - 1,
        float(dims.y - launchIndex.y - 1 + 0.5) / dims.y * 2 - 1);

    RayDesc ray;
    ray.Origin = gCamera.origin.xyz;
    ray.Direction = GetWorldRay(ndc, gCamera.forward.xyz, gCamera.right.xyz, gCamera.up.xyz);
    ray.TMin = 0;
    ray.TMax = 100000;

    TraceRay(
        SceneBVH,
        RAY_FLAG_NONE,
        0xFF, 
        0, // RayContributionToHitGroupIndex
        0, // MultiplierForGeometryContributionToHitGroupIndex
        0, // MissShaderIndex
        ray,
        payload);

    gOutput[launchIndex] = float4(payload.colorAndDistance.rgb, 1.f);
}


. TLAS, , SBT. TraceRay() payload . [shader("raygeneration")] , , , "RayGen" , .



closesthit



#include "Common.hlsl"
#include "Global.hlsl"

struct InstanceData
{
    float4 color;
};
ConstantBuffer<InstanceData> instanceData : register(b1);

[shader("closesthit")] 
void ClosestHit(inout HitInfo payload, Attributes attrib)
{
    float3 barycentrics = float3(1.f - attrib.bary.x - attrib.bary.y, attrib.bary.x, attrib.bary.y);

    float3 vertexNormals[3] = {
        Vertices[PrimitiveIndex() * 3].normal,
        Vertices[PrimitiveIndex() * 3 + 1].normal,
        Vertices[PrimitiveIndex() * 3 + 2].normal
    };

    float3 N = vertexNormals[0] * barycentrics.x +
        vertexNormals[1] * barycentrics.y +
        vertexNormals[2] * barycentrics.z;

    const float3 L = normalize(float3(0, -0.4, 1));

    payload.colorAndDistance = float4(instanceData.color.rgb * max(0, dot(N, L)), RayTCurrent());
}


. - payload. . . , .



miss.



#include "Common.hlsl"

[shader("miss")] 
void Miss(inout HitInfo payload : SV_RayPayload)
{
    payload.colorAndDistance = float4(0.0f, 0.2f, 0.7f, -1.0f);
}


— .



Main loop



main loop :



//...
//   root signature
dxrCommandList->SetComputeRootSignature(raytracingGlobalRootSignature.Get());

//   descriptor heap
dxrCommandList->SetDescriptorHeaps(1, descriptorHeap.GetAddressOf());

//   
dxrCommandList->SetComputeRootDescriptorTable(0, raytracingOutputResourceUAVGpuDescriptor);
dxrCommandList->SetComputeRootDescriptorTable(1, buffersGpuDescriptor);
dxrCommandList->SetComputeRootShaderResourceView(2, topLevelAccelerationStructure->GetGPUVirtualAddress());

//   
//...

D3D12_DISPATCH_RAYS_DESC dispatchDesc = {};
dispatchDesc.HitGroupTable.StartAddress = hitGroupShaderTable->GetGPUVirtualAddress();
dispatchDesc.HitGroupTable.SizeInBytes = hitGroupShaderTable->GetDesc().Width;
dispatchDesc.HitGroupTable.StrideInBytes = 64; //  hit shader record 
dispatchDesc.MissShaderTable.StartAddress = missShaderTable->GetGPUVirtualAddress();
dispatchDesc.MissShaderTable.SizeInBytes = missShaderTable->GetDesc().Width;
dispatchDesc.MissShaderTable.StrideInBytes = dispatchDesc.MissShaderTable.SizeInBytes;
dispatchDesc.RayGenerationShaderRecord.StartAddress = rayGenShaderTable->GetGPUVirtualAddress();
dispatchDesc.RayGenerationShaderRecord.SizeInBytes = rayGenShaderTable->GetDesc().Width;
dispatchDesc.Width = width;
dispatchDesc.Height = height;
dispatchDesc.Depth = 1;

dxrCommandList->SetPipelineState1(dxrStateObject.Get());

dxrCommandList->DispatchRays(&dispatchDesc);
//...






在本文中,我们研究了DXR入门所需的基本对象,并在实践中应用了此知识。故意省略了DirectX初始化,加载模型,编译着色器等不相关的问题。在下一篇文章中,实际上计划将重点转移到图形上,而不是使用API​​。



链接:



https://github.com/k-payl/X12Lib/blob/master/src/examples/raytracing.cpp

https://microsoft.github.io/DirectX-Specs/d3d/Raytracing.html

https://开发人员。 nvidia.com/rtx/raytracing/dxr/DX12-Raytracing-tutorial-Part-1




All Articles