
Em 2018, a Microsoft anunciou a API de raytracing (DXR) como parte do DirectX 12. A abordagem de raytracing força um repensar completo da maneira como as cenas 3D são renderizadas, mudando a abordagem de rasterização clássica para o fundo. APIs estão sendo modernizadas, GPUs mais eficientes estão sendo desenvolvidas e os desenvolvedores de pacotes de visualização estão experimentando novas possibilidades. No entanto, mesmo nas placas gráficas mais poderosas, a potência é suficiente para gerar apenas alguns feixes por pixel para garantir uma taxa de quadros estável. Além disso, o desempenho depende muito da complexidade dos materiais e da cena. Mas já hoje, algoritmos avançados para redução de ruído e acúmulo do resultado de iluminação permitem atingir um alto grau de realismo. Tudo isso motiva a experimentar nesta área.
O rastreamento de raio da GPU é relativamente novo. Em 2009, o DirectX 11 foi lançado com sombreadores de computação - isso deu ímpeto ao desenvolvimento da computação não gráfica. No entanto, o design das estruturas de aceleração caiu inteiramente sobre os ombros do programador, o que desacelerou o desenvolvimento. Bibliotecas especializadas de interseção se espalharam, como o Radeon Rays da AMD. No DXR, as estruturas de aceleração são representadas no princípio da caixa preta e a interseção ocorre usando blocos de hardware especiais. Ray tracing também foi adicionado ao Vulkan como uma extensão de VK_NV_ray_tracing para placas Nvidia. Em março de 2020, com pequenas alterações, as extensões VK_KHR_ray_tracing foram lançadas, não é mais específico do fornecedor, ele pode ser incluído na especificação Vulkan 1.3.O rastreamento de raio completo está planejado para a AMD até o final de 2020. O suporte onipresente torna a tecnologia mais promissora.
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(< >).
- . BytecodeLength pShaderBytecode D3D12_SHADER_BYTECODE, SetDXILLibrary() DefineExport(). 3- : raygen, hit, miss.
- Hit group (CD3DX12_HIT_GROUP_SUBOBJECT). hit group-, . SetHitGroupExport, SetHitGroupType(D3D12_HIT_GROUP_TYPE_TRIANGLES). hit-group, .
- (CD3DX12_RAYTRACING_SHADER_CONFIG_SUBOBJECT). payload — , TraceRay , closest hit — 2 float.
- (CD3DX12_RAYTRACING_PIPELINE_CONFIG_SUBOBJECT). 1.
- root signature (CD3DX12_LOCAL_ROOT_SIGNATURE_SUBOBJECT). , hit-. SBT ( ).
- local root signatore c hit group (CD3DX12_SUBOBJECT_TO_EXPORTS_ASSOCIATION_SUBOBJECT). root signature SetSubobjectToAssociate() AddExport().
- 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);
//...

Neste artigo, examinamos os objetos básicos necessários para começar a usar DXR e também aplicamos esse conhecimento na prática. As questões de inicialização do DirectX, carregamento de modelos, compilação de shaders, etc., que não são relevantes, foram deliberadamente omitidas. Nos próximos artigos, planejamos mudar a ênfase, de fato, nos gráficos, em vez de trabalhar com a API.
Links:
https://github.com/k-payl/X12Lib/blob/master/src/examples/raytracing.cpp
https://microsoft.github.io/DirectX-Specs/d3d/Raytracing.html
https: // developer. nvidia.com/rtx/raytracing/dxr/DX12-Raytracing-tutorial-Part-1