前回は DXR におけるスキニングの実装の流れ(コンピュートシェーダー版) を軽く紹介しました。今回はその実装について踏み込んでいきます。
バッファの準備
コンピュートシェーダーによるスキニングによる頂点変形では、変形処理前の頂点列と変形後の頂点列の2つのバッファが必要になります。従来のレンダリングパイプラインの場合では変形前のバッファのみで済みましたが、今回はそのようにはなりません。
またコンピュートシェーダーから書き込むために、結果格納先のバッファは UAV としてアクセスできるようにしておきます。そのため VRAM 側にリソースが確保されるようにしておきます。
コンピュートシェーダーへ2つのバッファを設定しますが、必要に応じてシェーダーリソースビューのディスクリプタも用意します。ただ、ルートパラメータに直接各バッファを設定するような場合にはこれは不要です。
AccelerationStructure の更新
スキニングモデルの形状更新後は、まず BLAS を更新します。
たとえば BLAS の生成のためのコードの一部は以下の通りです。ここでは頂点バッファを結合している都合もあり、各メッシュ(サブメッシュ)ごとにバイト単位でのオフセットを考慮した設定をしています。
D3D12_RAYTRACING_GEOMETRY_DESC desc{};
desc.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES;
desc.Triangles.VertexBuffer.StartAddress = vertexBuffer->GetGPUVirtualAddress();
desc.Triangles.VertexBuffer.StrideInBytes = sizeof(Vertex);
desc.Triangles.VertexBuffer.StartAddress += mesh.vertexStart * sizeof(Vertex);
desc.Triangles.VertexFormat = DXGI_FORMAT_R32G32B32_FLOAT;
desc.Triangles.VertexCount = mesh.vertexCount;
desc.Triangles.IndexBuffer = indexBuffer->GetGPUVirtualAddress();
desc.Triangles.IndexBuffer += mesh.indexStart * sizeof(UINT);
desc.Triangles.IndexCount = mesh.indexCount;
desc.Triangles.IndexFormat = DXGI_FORMAT_R32_UINT;
desc.Flags = D3D12_RAYTRACING_GEOMETRY_FLAG_OPAQUE;
あとはこれを元にして、Scratch バッファと BLAS の作成・更新を行います。
続いて TLAS の更新ですが、BLAS の構築が終わった後で処理します。
TLAS には各インスタンスの配置場所であるワールド行列も一緒に設定されるため、動的に対応するためにはこちらの更新も必要になります。
TLAS の生成には以下のコードのように更新可能フラグをつけて行います。
D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS inputs = {};
inputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY;
inputs.Flags = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_ALLOW_UPDATE;
inputs.NumDescs = UINT(rtInstanceDescs.size());
inputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL;
スクラッチバッファは更新時には再利用する形で使用しております。
処理ステップの同期について
ここまでのステップが進んで行くにあたり、重要な点があります。それは各ステップが完了してから次の処理を始めなければならない、という点です。使用しているバッファに適切なリソースバリア(遷移バリア・UAVバリア)を設定するのを忘れないようにしましょう。
この実装が不十分であると、例えば以下のように動かした際に不正な描画結果が出てくることがあります。バリアを消去してみると、このような結果を見ることが出来るかもしれません(保証はしません)。
バリアの漏れは少なくとも現状、警告が出るようなことがなかったので割と長時間、見落とししていました。また自分の環境では上記のようにわかりやすい不正な結果でしたが、ある環境ではこのようにならないかもしれません。また RADEON 系列ではまた異なった結果が得られるかもしれません(自分は Geforce RTX使用)
コメント