概要
はじめに
Direct3D 12 Raytracing,
DirectX-Graphics-Samplesより正しく詳しい情報は得られません.
処理の概観についてまとめます.
必要環境
ハードとソフトに強く依存します.
Windows 10 | Version 1809 |
Windows SDK | October 2018 (17763) |
Nvidia Driver | Version 415 |
GPU | RTXシリーズ |
従来のCompute Shaderでエミュレートする環境が用意されていますが今回は無視します.
SDK
d3d12_1.h がWindows SDK (17763)にはないため, DirectX-Graphics-Samples
からコピーします.
初期化
サポートチェック
デバイスは, D3D12_FEATURE_D3D12_OPTIONS5::RaytracingTierをチェックするだけです. HLSL Shader Model 6.3が必要ですが, 包含していると考えていいのでしょう.
デバイスチェック
D3D12_FEATURE_DATA_D3D12_OPTIONS5 featureSupportData = {};
return SUCCEEDED(device_->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS5, &featureSupportData, sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS5)))
&& D3D12_RAYTRACING_TIER_NOT_SUPPORTED != featureSupportData.RaytracingTier;
DXRインターフェイス
ID3D12Device5と, ID3D12GraphicsCommandList4が追加されました.
インテーフェイス取得
ID3D12Device5* device5 = nullptr;
ID3D12Device* device->QueryInterface(IID_PPV_ARGS(&device5));
ID3D12GraphicsCommandList4* commandList4 = nullptr;
ID3D12GraphicsCommandList* commandList->QueryInterface(IID_PPV_ARGS(&commandList4));
パイプライン
シェーダ関数をコンピュートユニットに発行することで処理が進みます.
CPUからは, ID3D12GraphicsCommandList4::DispatchRays
ID3D12GraphicsCommandList4::DispatchRays(D3D12_DISPATCH_RAYS_DESC* dispatchDesc)
シェーダ内の各関数に *[shader("attribute name")]*の形式で属性を付けておきます.
raygeneration関数がシステムから呼ばれ, TraceRayでレイを生成します.
"レイが何かにヒットした"等のイベントごとに, それぞれ対応する関数が呼ばれます.
下図のようにTraceRayでレイを生成して, シーンをトラバースします. Intersection はBVHの境界ボリュームに交差したときのイベントです.
HLSL
シェーダモデル6.3が必要です. 従来のfxcではなく, dxcにlib_6_3を指定してコンパイルします.
サンプルから引用(Raytracing.hlsl)
struct Viewport
{
float left;
float top;
float right;
float bottom;
};
struct RayGenConstantBuffer
{
Viewport viewport;
Viewport stencil;
};
RaytracingAccelerationStructure Scene : register(t0, space0);
RWTexture2D<float4> RenderTarget : register(u0);
ConstantBuffer<RayGenConstantBuffer> g_rayGenCB : register(b0);
struct RayPayload
{
float4 color;
};
[shader("raygeneration")]
void MyRaygenShader()
{
float2 lerpValues = (float2)DispatchRaysIndex() / (float2)DispatchRaysDimensions();
// +Z方向に垂直投影
float3 rayDir = float3(0, 0, 1);
float3 origin = float3(
lerp(g_rayGenCB.viewport.left, g_rayGenCB.viewport.right, lerpValues.x),
lerp(g_rayGenCB.viewport.top, g_rayGenCB.viewport.bottom, lerpValues.y),
0.0f);
RayDesc ray;
ray.Origin = origin;
ray.Direction = rayDir;
ray.TMin = 0.001;
ray.TMax = 10000.0;
RayPayload payload = {float4(0, 0, 0, 0)};
TraceRay(Scene, RAY_FLAG_CULL_BACK_FACING_TRIANGLES, ~0, 0, 1, 0, ray, payload);
RenderTarget[DispatchRaysIndex().xy] = payload.color;
}
[shader("closesthit")]
void MyClosestHitShader(inout RayPayload payload, in BuiltInTriangleIntersectionAttributes attr)
{
float3 barycentrics = float3(1 - attr.barycentrics.x - attr.barycentrics.y, attr.barycentrics.x, attr.barycentrics.y);
payload.color = float4(barycentrics, 1);
}
[shader("miss")]
void MyMissShader(inout RayPayload payload)
{
payload.color = float4(0, 0, 0, 1);
}
BVH生成
Acceleration Structureが必須です. データ構造が公開されていないため自作できません.
ID3D12GraphicsCommandList4::BuildRaytracingAccelerationStructureで作成します.
トップレベルとボトムレベルのふたつを作成する必要があります.
ID3D12GraphicsCommandList4::CopyRaytracingAccelerationStructureを使えば, 事前生成ができそうです.
ただし, D3D12_SERIALIZED_RAYTRACING_ACCELERATION_STRUCTURE_HEADERの
D3D12_SERIALIZED_DATA_DRIVER_MATCHING_IDENTIFIERをチェックする必要があります.
まとめ
処理の概観についてまとめました. 詳細はサンプルコードを読むしかないのですが,
シェーダを中心に必要なものを生成していくコードを読むとわかりやすいと思います.
従来のラスタライザパイプラインとは完全に分離しているため, 結果を合成するなりしないといけません.