現在「DirectX12の魔導書 3Dレンダリングの基礎からMMDモデルを踊らせるまで」という本を読みながらDirectX12を勉強中です。
MMDモデルを表示し、マテリアルやライティングまでは実装できましたが、リファクタリングをしている最中で定数バッファに問題が置きました。
【やりたかったこと】
定数バッファを、「視点用(ビュー・プロジェクション・視点)」「オブジェクト座標用(ワールドマトリクス)」「マテリアル用(マテリアル)」の3つに分けて、処理を分割しようとしました。
()内はGPUにマップしているものです。
視点用定数バッファで使用している構造体 視点用定数バッファ生成
HRESULT Object3D::CreateSceneCBuffer(MODEL_DX12* Model){
auto buffersize = sizeof(SCENEMATRIX);
buffersize = (buffersize + 0xff) & ~0xff;
CD3DX12_HEAP_PROPERTIES cd_hp = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD);
CD3DX12_RESOURCE_DESC cd_buffer = CD3DX12_RESOURCE_DESC::Buffer(buffersize);
HRESULT hr = DX12Renderer::GetDevice()->CreateCommittedResource(
&cd_hp,
D3D12_HEAP_FLAG_NONE,
&cd_buffer,
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
I ID_PPV_ARGS(Model->SceneConstBuffer.ReleaseAndGetAddressOf()));
// 視線
XMFLOAT3 eye(0, 15, -15);
// 注視点
XMFLOAT3 target(0, 15, 0);
// 上ベクトル
XMFLOAT3 v_up(0, 1, 0);
XMMATRIX viewMat = XMMatrixLookAtLH(XMLoadFloat3(&eye), XMLoadFloat3(&target), XMLoadFloat3(&v_up));
XMMATRIX projMat = XMMatrixPerspectiveFovLH(
XM_PIDIV4,//画角は90°
static_cast<float>(SCREEN_WIDTH) / static_cast<float>(SCREEN_HEIGHT),//アス比
0.1f,//近い方
1000.0f//遠い方);
hr = Model->SceneConstBuffer->Map(0, nullptr, (void**)&Model->SceneMatrix);
XMStoreFloat4x4(&Model->SceneMatrix->view, viewMat);
XMStoreFloat4x4(&Model->SceneMatrix->proj, projMat);
Model->SceneMatrix->eye = eye;
// ディスクリプタヒープ作成
D3D12_DESCRIPTOR_HEAP_DESC dhd = {};
dhd.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
dhd.NodeMask = 0;
dhd.NumDescriptors = 1;
dhd.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
hr = DX12Renderer::GetDevice()->CreateDescriptorHeap(&dhd, IID_PPV_ARGS(Model->sceneDescHeap.ReleaseAndGetAddressOf()));
D3D12_CONSTANT_BUFFER_VIEW_DESC cbvd = {};
cbvd.BufferLocation = Model->SceneConstBuffer.Get()->GetGPUVirtualAddress();
cbvd.SizeInBytes = Model->SceneConstBuffer.Get()->GetDesc().Width;
auto heapHandle = Model->sceneDescHeap.Get()->GetCPUDescriptorHandleForHeapStart();
DX12Renderer::GetDevice()->CreateConstantBufferView(&cbvd, heapHandle);
return hr;
}
HRESULT Object3D::CreateTransformCBuffer(MODEL_DX12* Model){
auto bufferSize = sizeof(TRANSFORM);
bufferSize = (bufferSize + 0xff) & ~0xff;
auto cd_hp = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD);
auto cd_rd = CD3DX12_RESOURCE_DESC::Buffer(bufferSize);
HRESULT hr = DX12Renderer::GetDevice()->CreateCommittedResource(
&cd_hp,
D3D12_HEAP_FLAG_NONE,
&cd_rd,
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(Model->TransfromConstBuffer.ReleaseAndGetAddressOf()));
XMMATRIX WorldMatrix = XMMatrixIdentity();
// マップ
hr = Model->TransfromConstBuffer.Get()->Map(0, nullptr, (void**)&Model->TransformMatrix);
XMStoreFloat4x4(&Model->TransformMatrix->world, WorldMatrix);
D3D12_DESCRIPTOR_HEAP_DESC transform_dhd = {};
transform_dhd.NumDescriptors = 1;
transform_dhd.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
transform_dhd.NodeMask = 0;
transform_dhd.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
hr = DX12Renderer::GetDevice()->CreateDescriptorHeap(&transform_dhd, IID_PPV_ARGS(Model->transformDescHeap.ReleaseAndGetAddressOf()));
D3D12_CONSTANT_BUFFER_VIEW_DESC cdvDesc = {};
cdvDesc.BufferLocation = Model->TransfromConstBuffer.Get()->GetGPUVirtualAddress();
cdvDesc.SizeInBytes = bufferSize;
auto heapHandle = Model->transformDescHeap.Get()->GetCPUDescriptorHandleForHeapStart();
DX12Renderer::GetDevice()->CreateConstantBufferView(&cdvDesc, heapHandle);
return hr;
}
HRESULT DX12Renderer::CreateRootSignature(){
// ディスクリプタレンジテーブル作成
// 定数(b0)(ビュープロジェクション用)
CD3DX12_DESCRIPTOR_RANGE dr[4] = {};
dr[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0);
// 定数(b1)(ワールド・ボーン用)
dr[1].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 1);
// マテリアル(b2)
dr[2].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 2);
// テクスチャ用(マテリアルとペア)
dr[3].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 4, 0);
// ルートパラメータ作成
D3D12_ROOT_PARAMETER rootparam[3] = {};
rootparam[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
rootparam[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; // 全シェーダーから見える
rootparam[0].DescriptorTable.pDescriptorRanges = &dr[0]; // ディスクリプタレンジのアドレス
rootparam[0].DescriptorTable.NumDescriptorRanges = 1; // ディスクリプタレンジ数
// ワールド・ボーン
rootparam[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
rootparam[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; // 頂点シェーダーから見える
rootparam[1].DescriptorTable.pDescriptorRanges = &dr[1]; // ディスクリプタレンジのアドレス
rootparam[1].DescriptorTable.NumDescriptorRanges = 1; // ディスクリプタレンジ数
// マテリアル
rootparam[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
rootparam[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
rootparam[2].DescriptorTable.pDescriptorRanges = &dr[2];
rootparam[2].DescriptorTable.NumDescriptorRanges = 2;
CD3DX12_STATIC_SAMPLER_DESC sd[2] = {};
sd[0].Init(0); // シェーダーレジスターは0番
sd[1].Init(1, D3D12_FILTER_ANISOTROPIC, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP); // シェーダーレジスターは1番、UVはクランプ
// ルートシグネチャー作成
D3D12_ROOT_SIGNATURE_DESC rsd = {};
rsd.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
rsd.pParameters = rootparam; // ルートパラメータの先頭アドレス
rsd.NumParameters = 3; // ルートパラメータ数
rsd.pStaticSamplers = sd; // サンプラーステートの先頭アドレス
rsd.NumStaticSamplers = 2; // サンプラーステート数
ID3DBlob* RootSigBlob = nullptr;
hr = D3D12SerializeRootSignature(&rsd, D3D_ROOT_SIGNATURE_VERSION_1, &RootSigBlob, &m_ErrorBlob);
hr = m_Device->CreateRootSignature(0, RootSigBlob->GetBufferPointer(), RootSigBlob->GetBufferSize(), IID_PPV_ARGS(m_RootSignature.ReleaseAndGetAddressOf()));
RootSigBlob->Release();
reutnr hr;
}
void Object::Draw(){
// プリミティブトポロジ設定
DX12Renderer::GetGraphicsCommandList()->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
// 頂点バッファービューセット
DX12Renderer::GetGraphicsCommandList()->IASetVertexBuffers(0, 1, &m_Model.vbView);
// インデックスバッファービューセット
DX12Renderer::GetGraphicsCommandList()->IASetIndexBuffer(&m_Model.ibView);
// 視点のデスクリプターヒープセット
ID3D12DescriptorHeap* scene_dh[] = { m_Model.sceneDescHeap.Get() };
DX12Renderer::GetGraphicsCommandList()->SetDescriptorHeaps(1, scene_dh);
// ルートパラメータとディスクリプターヒープの関連付け
auto scene_handle = m_Model.sceneDescHeap.Get()->GetGPUDescriptorHandleForHeapStart();
DX12Renderer::GetGraphicsCommandList()->SetGraphicsRootDescriptorTable(0, scene_handle);
ID3D12DescriptorHeap* trans_dh[] = { m_Model.transformDescHeap.Get() };
DX12Renderer::GetGraphicsCommandList()->SetDescriptorHeaps(1, trans_dh);
auto transform_handle = m_Model.transformDescHeap.Get()->GetGPUDescriptorHandleForHeapStart();
DX12Renderer::GetGraphicsCommandList()->SetGraphicsRootDescriptorTable(1, transform_handle);
// マテリアルのディスクリプタヒープセット
ID3D12DescriptorHeap* mdh[] = { m_Model.materialDescHeap.Get() };
DX12Renderer::GetGraphicsCommandList()->SetDescriptorHeaps(1, mdh);
// マテリアル用ディスクリプタヒープの先頭アドレスを取得
auto material_handle = m_Model.materialDescHeap.Get()->GetGPUDescriptorHandleForHeapStart();
unsigned int idxOffset = 0;
// CBVとSRVとSRVとSRVとSRVで1マテリアルを描画するのでインクリメントサイズを5倍にする
auto cbvsize = DX12Renderer::GetDevice()->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV) * 5;
for (auto& m : m_Model.material)
{
DX12Renderer::GetGraphicsCommandList()->SetGraphicsRootDescriptorTable(2, material_handle);
DX12Renderer::GetGraphicsCommandList()->DrawIndexedInstanced(m.indicesNum, 1, idxOffset, 0, 0);
// ヒープポインタとインデックスを次に進める
material_handle.ptr += cbvsize;
idxOffset += m.indicesNum;
}
}
cbuffer SceneView : register(b0) // 定数バッファー
{
matrix view; // ビュー
matrix proj; // プロジェクション
float3 eye; // 視線
};
cbuffer Transform : register(b1)
{
matrix world; // ワールド変換行列
};
cbuffer Material : register(b2)
{
float4 diffuse;
float4 specular;
float3 ambient;
};
エラーは出ずにexeは起動できますがモデルが全く表示されません。
ビュープロジェクションの内容が転送できてないのかと思いレジスタ番号1に全て転送するように変えてみると、正しく動作するのでレジスタ番号0への転送がうまく行っていないようでした。
上記の方法で定数バッファの設定は正しいのでしょうか。
長文になり申し訳ございません。ご教授いただけると幸いです。
ビルド環境
OS:Windows
コンパイラ:Microsoft VisualStudio2019 ver.16.11.19