Raytracing DirectX - pop-up



En 2018, Microsoft a annoncé l'API de raytracing (DXR) dans le cadre de DirectX 12. L'approche de raytracing oblige à repenser complètement la façon dont les scènes 3D sont rendues, déplaçant l'approche classique de rastérisation en arrière-plan. Les API sont modernisées, des GPU plus efficaces sont en cours de développement et les développeurs de packages de visualisation essaient de nouvelles possibilités. Cependant, même sur les cartes graphiques les plus puissantes, la puissance est suffisante pour ne générer que quelques faisceaux par pixel afin d'assurer une fréquence d'images stable. De plus, les performances dépendent fortement de la complexité des matériaux et de la scène. Mais même aujourd'hui, des algorithmes avancés de réduction du bruit et d'accumulation du résultat d'éclairage permettent d'atteindre un haut degré de réalisme. Tout cela motive à expérimenter dans ce domaine.



Le traçage de rayons GPU est relativement nouveau. En 2009, DirectX 11 est sorti avec des shaders de calcul - cela a donné une impulsion au développement de l'informatique non graphique. Cependant, la conception des structures d'accélération est tombée entièrement sur les épaules du programmeur, ce qui a ralenti le développement. Les bibliothèques d'intersection spécialisées se sont généralisées, telles que les Radeon Rays d'AMD. Dans DXR, les structures accélératrices sont représentées par un principe de boîte noire et l'intersection est réalisée à l'aide de blocs matériels spéciaux. Le lancer de rayons a également été ajouté à Vulkan en tant qu'extension VK_NV_ray_tracing pour les cartes Nvidia. En mars 2020, avec des modifications mineures, les extensions VK_KHR_ray_tracing ont été publiées, le fournisseur spécifique a cessé de l'être, peut-être sera-t-il inclus dans la spécification Vulkan 1.3.Un traçage de rayons complet est prévu pour AMD d'ici la fin de 2020. Un support omniprésent rend la technologie plus prometteuse.



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);
//...






Dans cet article, nous avons examiné les objets de base nécessaires pour démarrer avec DXR et avons également appliqué ces connaissances dans la pratique. Les questions d'initialisation DirectX, de chargement de modèles, de compilation de shaders, etc., qui ne sont pas pertinentes, ont été volontairement omises. Dans les prochains articles, il est prévu de mettre l'accent sur, en fait, les graphiques, plutôt que de travailler avec l'API.



Liens:



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

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

https: // développeur. nvidia.com/rtx/raytracing/dxr/DX12-Raytracing-tutorial-Part-1




All Articles