又开始做练习题了,第一题很简单,单纯替换下几何创建函数就可以了。
第二题,使用16个根常量替换描述表来设置每个物体的世界坐标变换矩阵。
CD3DX12_ROOT_PARAMETER slotRootParam[2];
//CD3DX12_DESCRIPTOR_RANGE cbvTable;
//cbvTable.Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0);
//slotRootParam[0].InitAsDescriptorTable(1, &cbvTable);
slotRootParam[0].InitAsConstants(17, 0);
渲染的时候:
ConstantData constantData;
XMMATRIX worldMatrix = XMLoadFloat4x4(&item->world);
XMStoreFloat4x4(&constantData.worldViewProj, XMMatrixTranspose(worldMatrix));
constantData.gTime = gt.TotalTime();
cmdList->SetGraphicsRoot32BitConstants(0, 17, &constantData, 0);
最后一个练习题:在本书的光盘中有一个Models/Skull.txt文件,它包含了一个骷髅头模型所需要的顶点和索引列表数据。使用文本编辑器来学习这个文件然后修改“Shape” Demo来加载骷髅头网格。
我们可以比较容易的看出来文件的格式,就是单纯的把顶点坐标,法线坐标用逗号隔开,所以我们直接读取文件生成网格就好。
void ShapeApp::CreateSkullGeometry()
{
std::ifstream fin("Models/skull.txt");
if (!fin)
{
MessageBox(0, L"Models/skull.txt not found.", 0, 0);
return;
}
UINT vcount = 0;
UINT tcount = 0;
std::string ignore;
fin >> ignore >> vcount;
fin >> ignore >> tcount;
fin >> ignore >> ignore >> ignore >> ignore;
std::vector vertices(vcount);
for (UINT i = 0; i < vcount; ++i)
{
fin >> vertices[i].pos.x >> vertices[i].pos.y >> vertices[i].pos.z;
fin >> vertices[i].normal.x >> vertices[i].normal.y >> vertices[i].normal.z;
}
fin >> ignore;
fin >> ignore;
fin >> ignore;
std::vector<:int32_t> indices(3 * tcount);
for (UINT i = 0; i < tcount; ++i)
{
fin >> indices[i * 3 + 0] >> indices[i * 3 + 1] >> indices[i * 3 + 2];
}
fin.close();
Mesh* skull = new Mesh();
UINT allVertexSize = sizeof(Vertex) * vertices.size();
UINT allIndexSize = sizeof(std::int32_t) * indices.size();
skull->vertexBuffer = DXUtil::CreateDefaultBuffer(device.Get(), allVertexSize, vertices.data(), cmdList.Get(),
skull->vertexUploadBuffer);
skull->indexBuffer = DXUtil::CreateDefaultBuffer(device.Get(), allIndexSize, indices.data(), cmdList.Get(),
skull->indexUploadBuffer);
skull->vertexBufferSize = allVertexSize;
skull->vertexByteStride = sizeof(Vertex);
skull->indexBufferSize = allIndexSize;
skull->indexFormat = DXGI_FORMAT_R32_UINT;
skull->name = "Skull";
DrawMeshInfo skullInfo;
skullInfo.indexCount = (UINT)indices.size();
skullInfo.startIndexLocation = 0;
skullInfo.baseVertexLocation = 0;
skull->DrawInfoMap["skull"] = skullInfo;
meshesMap[skull->name] = std::move(skull);
}
这里要注意,这个骷髅头的索引数是超过65536的,所以我们要使用32位的索引buffer。
最后,因为大佬提过一个cmdList对应多个cmdAlloctor在多线程的时候需要自己管理,会比较麻烦以及性能上的问题,所以我们改成一一对应的模式。
FrameResource::FrameResource(ID3D12Device* device, UINT maxtrixCount, UINT waterVertexCount, UINT passCount)
{
ThrowIfFailed(device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&alloctor)));
ThrowIfFailed(device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, alloctor.Get(), nullptr, IID_PPV_ARGS(&cmdList)));
cmdList->Close();
matrixUploader = new UploadBuffer(device, maxtrixCount, true);
matrixUploader->Upload();
waterVertexBuffer = std::make_unique>(device, waterVertexCount, false);
waterVertexBuffer->Upload();
passUploader = new UploadBuffer(device, passCount, true);
passUploader->Upload();
}
注意每个cmdList创建后都要先Close()掉,不然alloctor reset的时候会报错,提示当前命令列表处于record状态。Draw的时候拿到当前FrameRes的cmdList即可。
这次练习题比较简单,本篇就到这里。下一章是光照相关的。