前回はポリゴンを3Dで表示できましたが、実は1つ問題点がありました。気付いている方もいるかと思いますが、デプスバッファがないため、複数のポリゴンから構成されるデータを描画した場合にはうまく描画できません。下図の右側のような結果を期待しても、左側のような感じになります。今回はこのデプスバッファを作って右側のような結果となるように改良したいと思います。
注意事項
繰り返しの内容となりますが、以下の点をご了承ください。
現時点において DirectX12 の部分はプレビュー版となっています。正式版では大きく変更される可能性があります。よってここの情報は 2015/04 現在の限定された環境でのみ動作するという点をご理解ください。
また以下の内容は間違っている点もあるかと思います。その点にはご注意ください。
本内容は既に最新環境では正常にコンパイルできません。ご注意ください 2015/5
デプスバッファを使用した描画
キューブのデータ等はリポジトリのほうを参照してください。ここではデプスバッファを作るあたりと設定する部分を抜粋して説明していきます。
デプスバッファの作成
以下のような感じでデプスバッファ用のディスクリプタヒープやリソースを準備します。
ComPtrrenderTargetDepth; ComPtr descriptorHeapDSB; // デプスバッファの準備. D3D12_DESCRIPTOR_HEAP_DESC descDescriptorHeapDSB; ZeroMemory(&descDescriptorHeapDSB, sizeof(descDescriptorHeapDSB)); descDescriptorHeapDSB.NumDescriptors = 1; descDescriptorHeapDSB.Type = D3D12_DSV_DESCRIPTOR_HEAP; descDescriptorHeapDSB.Flags = D3D12_DESCRIPTOR_HEAP_NONE; hr = dxDevice->CreateDescriptorHeap( &descDescriptorHeapDSB, IID_PPV_ARGS(descriptorHeapDSB.GetAddressOf())); D3D12_RESOURCE_DESC descDepth = CD3D12_RESOURCE_DESC::Tex2D( DXGI_FORMAT_R32_TYPELESS, WINDOW_WIDTH, WINDOW_HEIGHT, 1, 1, 1, 0, D3D12_RESOURCE_MISC_ALLOW_DEPTH_STENCIL ); D3D12_CLEAR_VALUE dsvClearValue; dsvClearValue.Format = DXGI_FORMAT_D32_FLOAT; dsvClearValue.DepthStencil.Depth = 1.0f; dsvClearValue.DepthStencil.Stencil = 0; hr = dxDevice->CreateCommittedResource( &CD3D12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_MISC_NONE, &descDepth, D3D12_RESOURCE_USAGE_DEPTH, &dsvClearValue, IID_PPV_ARGS(renderTargetDepth.ReleaseAndGetAddressOf()) );
ここではデプスバッファ用のディスクリプタヒープを用意してしまい、そこから必要なサイズのバッファを作成しています。基本的には頂点データの確保の時とあまり変わらない感じです。続いてこのバッファをデプスバッファとして参照するためのビューを用意します。
D3D12_CPU_DESCRIPTOR_HANDLE descriptorDSV; // デプス用のビューを作成. D3D12_DEPTH_STENCIL_VIEW_DESC descDSV; ZeroMemory(&descDSV, sizeof(descDSV)); descDSV.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; descDSV.Format = DXGI_FORMAT_D32_FLOAT; descDSV.Texture2D.MipSlice = 0; dxDevice->CreateDepthStencilView( renderTargetDepth.Get(), &descDSV, descriptorHeapDSB->GetCPUDescriptorHandleForHeapStart() ); descriptorDSV = descriptorHeapDSB->GetCPUDescriptorHandleForHeapStart();
この流れは DirectX11 のときにもあったので、使っていた人には流れとしては自然だと思います。
インデックスバッファの準備
前回までは単に頂点バッファのみ使用していました。今回は形状も立方体ということもあってインデックスバッファを使用するようにしてみました。作成の方法はほぼ頂点バッファと同じなので割愛しますが、このバッファを参照するためのビューの設定は以下のようになります。
D3D12_INDEX_BUFFER_VIEW indexView; indexView.BufferLocation = indexBuffer->GetGPUVirtualAddress(); indexView.SizeInBytes = sizeof(cubeIndices); indexView.Format = DXGI_FORMAT_R16_UINT;
パイプラインステートを変更する
デプスバッファを使うようにパイプラインステートを変更します。基本的には以下のようにフォーマットを始め、いくつかのパラメータをセットするようにします。
descPipelineState.DepthStencilState = CD3D12_DEPTH_STENCIL_DESC(D3D12_DEFAULT); descPipelineState.DepthStencilState.DepthEnable = TRUE; descPipelineState.DepthStencilState.DepthFunc = D3D12_COMPARISON_LESS_EQUAL; descPipelineState.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; descPipelineState.DSVFormat = DXGI_FORMAT_D32_FLOAT;
描画する
描画する部分は以下のようになります。
まずはレンダーターゲットとしてカラーだけでなくデプスバッファをセットします(正確には各バッファを示すディスクリプタですが)。その後でインデックスバッファありで描画するために DrawIndexedInstanced でコマンドを発行しています。
commandList->SetRenderTargets( &descriptorRTV, FALSE, 1, &descriptorDSV); commandList->ClearDepthStencilView( descriptorDSV, D3D12_CLEAR_DEPTH, 1.0f, 0, nullptr, 0); commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); commandList->SetVertexBuffers(0, &vertexView, 1); commandList->SetIndexBuffer(&indexView); commandList->DrawIndexedInstanced(36, 1, 0, 0, 0);
これでデプスバッファが有効に効いて、正しい描画結果が得られるようになりました。余談ですが今回のキューブデータには法線情報も入れてあり、そのうちのライティング回で再利用しようと思っています。
ソースコードは今までと同様に GitHub のほうにあげてあります。
本内容は既に最新環境では正常にコンパイルできません。ご注意ください 2015/5