d3d12龙书阅读----绘制几何体(上) 课后习题
d3d12龙书阅读----绘制几何体(上) 课后习题
练习1 完成相应的顶点结构体的输入-布局对象
typedef struct D3D12_INPUT_ELEMENT_DESC
{
一个特定字符串
将顶点结构体数组里面的顶点映射到顶点着色器的输入签名
LPCSTR SemanticName;
语义索引 如果语义名相同的话 使用索引进行区分
UINT SemanticIndex;
顶点元素的格式 与顶点结构体元素的大小相对应
DXGI_FORMAT Format;
输入槽索引
UINT InputSlot;
代表着顶点结构体各元素的偏移量
UINT AlignedByteOffset;
D3D12_INPUT_CLASSIFICATION InputSlotClass;
UINT InstanceDataStepRate;
} D3D12_INPUT_ELEMENT_DESC;
而对于上图中的顶点结构体 顶点输入布局描述如下:
inputLayoutDesc =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
{ "TANGENT", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 24, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 36, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 1, DXGI_FORMAT_R32G32_FLOAT, 0, 44, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 52, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }
};
练习2 使用多个输入槽
主要分为两步 第一步不详细贴代码了 主要是对辅助几何结构体进行更改 将vertex拆分成位置与颜色:
struct MeshGeometry
{
std::string Name;
Microsoft::WRL::ComPtr<ID3DBlob> PositionBufferCPU = nullptr;
Microsoft::WRL::ComPtr<ID3DBlob> ColorBufferCPU = nullptr;
Microsoft::WRL::ComPtr<ID3DBlob> IndexBufferCPU = nullptr;
Microsoft::WRL::ComPtr<ID3D12Resource> PositionBufferGPU = nullptr;
Microsoft::WRL::ComPtr<ID3D12Resource> ColorBufferGPU = nullptr;
Microsoft::WRL::ComPtr<ID3D12Resource> IndexBufferGPU = nullptr;
Microsoft::WRL::ComPtr<ID3D12Resource> PositionBufferUploader = nullptr;
Microsoft::WRL::ComPtr<ID3D12Resource> ColorBufferUploader = nullptr;
Microsoft::WRL::ComPtr<ID3D12Resource> IndexBufferUploader = nullptr;
UINT VertexPosByteStride = 0;
UINT VertexPosBufferByteSize = 0;
UINT VertexColorByteStride = 0;
UINT VertexColorBufferByteSize = 0;
DXGI_FORMAT IndexFormat = DXGI_FORMAT_R16_UINT;
UINT IndexBufferByteSize = 0;
std::unordered_map<std::string, SubmeshGeometry> DrawArgs;
D3D12_VERTEX_BUFFER_VIEW PositionBufferView()const
{
D3D12_VERTEX_BUFFER_VIEW pbv;
pbv.BufferLocation = PositionBufferGPU->GetGPUVirtualAddress();
pbv.StrideInBytes = VertexPosByteStride;
pbv.SizeInBytes = VertexPosBufferByteSize;
return pbv;
}
D3D12_VERTEX_BUFFER_VIEW ColorBufferView()const
{
D3D12_VERTEX_BUFFER_VIEW cbv;
cbv.BufferLocation = ColorBufferGPU->GetGPUVirtualAddress();
cbv.StrideInBytes = VertexColorByteStride;
cbv.SizeInBytes = VertexColorBufferByteSize;
return cbv;
}
D3D12_INDEX_BUFFER_VIEW IndexBufferView()const
{
D3D12_INDEX_BUFFER_VIEW ibv;
ibv.BufferLocation = IndexBufferGPU->GetGPUVirtualAddress();
ibv.Format = IndexFormat;
ibv.SizeInBytes = IndexBufferByteSize;
return ibv;
}
void DisposeUploaders()
{
PositionBufferUploader = nullptr;
ColorBufferUploader = nullptr;
IndexBufferUploader = nullptr;
}
};
第二步在draw函数中使用不同的输入槽进行绘制:
mCommandList->IASetVertexBuffers(0, 1, &mBoxGeo->PositionBufferView());
mCommandList->IASetVertexBuffers(1, 1, &mBoxGeo->ColorBufferView());
练习3 使用不同的图元拓扑 练习8 使用线框模式 练习9 背面与正面剔除
这里启用线框模式可以帮助我们更好的观察
只需要在buildPSo函数中对光栅器状态进行修改即可
背面与正面剔除的设置也在这里修改
使用不同的图元拓扑在:
mCommandList->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST)
修改即可
练习4 绘制金字塔
定义顶点数组 与 索引数组
这里要特别注意索引顺序 看不见的面使用逆时针
看见的面使用顺时针
std::array<Vertex, 5> pyramid_vertices =
{
Vertex({ XMFLOAT3(-1.0f, 0.0f, -1.0f), XMFLOAT4(Colors::Green) }),
Vertex({ XMFLOAT3(-1.0f, 0.0f, 1.0f), XMFLOAT4(Colors::Green) }),
Vertex({ XMFLOAT3(+1.0f, 0.0f, -1.0f), XMFLOAT4(Colors::Green) }),
Vertex({ XMFLOAT3(+1.0f, 0.0f, 1.0f), XMFLOAT4(Colors::Green) }),
Vertex({ XMFLOAT3(0.0f, 2.0f, 0.0f), XMFLOAT4(Colors::Red) })
};
std::array<std::uint16_t, 18> pyramid_indices =
{
// 底面 逆时针
0, 2, 1,
1, 2, 3,
// 侧面 顺时针
1, 4, 0,
0, 4, 2,
2, 4, 3,
// 背面 逆时针
1, 3, 4
};
练习6 设置常量gTime
修改如下:
struct ObjectConstants
{
XMFLOAT4X4 WorldViewProj = MathHelper::Identity4x4();
float gTime = 0.0f;
};
然后在update函数进行相应修改:
ObjectConstants objConstants;
XMStoreFloat4x4(&objConstants.WorldViewProj, XMMatrixTranspose(worldViewProj));
objConstants.gTime = gt.TotalTime();
mObjectCB->CopyData(0, objConstants);
练习7 将金字塔与立方体合并到一个大的顶点缓冲区与索引缓冲区 同时使用不同的世界矩阵使得两者互不相交
本题的方法可以在完成第七章的学习之后再来看
我们可以先从初始化开始:
BuildDescriptorHeaps();
BuildConstantBuffers();
BuildRootSignature();
BuildShadersAndInputLayout();
BuildBoxGeometry();
BuildPSO();
第一步 构建常量缓冲区描述符堆(因为我们这里根签名还是采用描述符表的形式 所以需要构建描述符堆来存储 cbv描述符)
因为之前只绘制一个物体 而这里要绘制两个物体 每个物体都需要一个常量数据对应的描述子:
D3D12_DESCRIPTOR_HEAP_DESC cbvHeapDesc;
cbvHeapDesc.NumDescriptors = 2;//修改为2 这里就不再改为更通用的表示 第七章示例代码已经做出了示范
cbvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
cbvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
cbvHeapDesc.NodeMask = 0;
ThrowIfFailed(md3dDevice->CreateDescriptorHeap(&cbvHeapDesc,
IID_PPV_ARGS(&mCbvHeap)));
第二步 构建常量缓冲区视图
void BoxApp::BuildConstantBuffers()
{
mObjectCB = std::make_unique<UploadBuffer<ObjectConstants>>(md3dDevice.Get(), 2, true);
UINT objCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(ObjectConstants));
D3D12_GPU_VIRTUAL_ADDRESS cbAddress = mObjectCB->Resource()->GetGPUVirtualAddress();
for (UINT i = 0; i < 2; ++i)
{
// 偏移到第i个物体常量数据
cbAddress += i * objCBByteSize;
// 偏移到对应的描述符堆的第i个cbv
int heapIndex = i;
auto handle = CD3DX12_CPU_DESCRIPTOR_HANDLE(mCbvHeap->GetCPUDescriptorHandleForHeapStart());
handle.Offset(heapIndex, mCbvSrvUavDescriptorSize);
D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc;
cbvDesc.BufferLocation = cbAddress;
cbvDesc.SizeInBytes = objCBByteSize;
md3dDevice->CreateConstantBufferView(&cbvDesc, handle);
}
}
第三步 构建根签名 不变 要记住我们还是只使用了一个常量缓冲区来存储不同物体的常量数据 对应着色器的b0 而在第七章这里发生变化 因为使用了两个常量缓冲区 一个物体一个过程 对应着色器的b0 b1
第四步 着色器设置 与顶点输入布局描述设置 不变
第五步 构建box几何体 要变 需要设置两个物体的顶点 与 索引缓冲区 并且合并
void BoxApp::BuildBoxGeometry()
{
std::array<Vertex, 8> box_vertices =
{
Vertex({ XMFLOAT3(-1.0f, -1.0f, -1.0f), XMFLOAT4(Colors::White) }),
Vertex({ XMFLOAT3(-1.0f, +1.0f, -1.0f), XMFLOAT4(Colors::Black) }),
Vertex({ XMFLOAT3(+1.0f, +1.0f, -1.0f), XMFLOAT4(Colors::Red) }),
Vertex({ XMFLOAT3(+1.0f, -1.0f, -1.0f), XMFLOAT4(Colors::Green) }),
Vertex({ XMFLOAT3(-1.0f, -1.0f, +1.0f), XMFLOAT4(Colors::Blue) }),
Vertex({ XMFLOAT3(-1.0f, +1.0f, +1.0f), XMFLOAT4(Colors::Yellow) }),
Vertex({ XMFLOAT3(+1.0f, +1.0f, +1.0f), XMFLOAT4(Colors::Cyan) }),
Vertex({ XMFLOAT3(+1.0f, -1.0f, +1.0f), XMFLOAT4(Colors::Magenta) })
};
std::array<std::uint16_t, 36> box_indices =
{
// front face
0, 1, 2,
0, 2, 3,
// back face
4, 6, 5,
4, 7, 6,
// left face
4, 5, 1,
4, 1, 0,
// right face
3, 2, 6,
3, 6, 7,
// top face
1, 5, 6,
1, 6, 2,
// bottom face
4, 0, 3,
4, 3, 7
};
std::array<Vertex, 5> pyramid_vertices =
{
Vertex({ XMFLOAT3(-1.0f, 0.0f, -1.0f), XMFLOAT4(Colors::Green) }),
Vertex({ XMFLOAT3(-1.0f, 0.0f, 1.0f), XMFLOAT4(Colors::Green) }),
Vertex({ XMFLOAT3(+1.0f, 0.0f, -1.0f), XMFLOAT4(Colors::Green) }),
Vertex({ XMFLOAT3(+1.0f, 0.0f, 1.0f), XMFLOAT4(Colors::Green) }),
Vertex({ XMFLOAT3(0.0f, 2.0f, 0.0f), XMFLOAT4(Colors::Red) })
};
std::array<std::uint16_t, 18> pyramid_indices =
{
// 底面 逆时针
0, 2, 1,
1, 2, 3,
// 侧面 顺时针
1, 4, 0,
0, 4, 2,
2, 4, 3,
// 背面 逆时针
1, 3, 4
};
UINT boxVertexOffset = 0;
UINT pyramidVertexOffset = (UINT)box_vertices.size();
UINT boxIndexOffset = 0;
UINT pyramidIndexOffset = (UINT)box_indices.size();
SubmeshGeometry boxSubmesh;
boxSubmesh.IndexCount = (UINT)box_indices.size();
boxSubmesh.StartIndexLocation = boxIndexOffset;
boxSubmesh.BaseVertexLocation = boxVertexOffset;
SubmeshGeometry pyramidSubmesh;
pyramidSubmesh.IndexCount = (UINT)pyramid_indices.size();
pyramidSubmesh.StartIndexLocation = pyramidIndexOffset;
pyramidSubmesh.BaseVertexLocation = pyramidVertexOffset;
auto totalVertexCount =
box_vertices.size() +
pyramid_indices.size();
std::vector<Vertex> vertices(totalVertexCount);
UINT k = 0;
for (size_t i = 0; i < box_vertices.size(); ++i, ++k)
{
vertices[k].Pos = box_vertices[i].Pos;
vertices[k].Color = box_vertices[i].Color;
}
for (size_t i = 0; i < pyramid_vertices.size(); ++i, ++k)
{
vertices[k].Pos = pyramid_vertices[i].Pos;
vertices[k].Color = pyramid_vertices[i].Color;
}
std::vector<std::uint16_t> indices;
indices.insert(indices.end(), std::begin(box_indices), std::end(box_indices));
indices.insert(indices.end(), std::begin(pyramid_indices), std::end(pyramid_indices));
const UINT vbByteSize = (UINT)vertices.size() * sizeof(Vertex);
const UINT ibByteSize = (UINT)indices.size() * sizeof(std::uint16_t);
mBoxGeo = std::make_unique<MeshGeometry>();
mBoxGeo->Name = "boxGeo";
ThrowIfFailed(D3DCreateBlob(vbByteSize, &mBoxGeo->VertexBufferCPU));
CopyMemory(mBoxGeo->VertexBufferCPU->GetBufferPointer(), vertices.data(), vbByteSize);
ThrowIfFailed(D3DCreateBlob(ibByteSize, &mBoxGeo->IndexBufferCPU));
CopyMemory(mBoxGeo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
mBoxGeo->VertexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
mCommandList.Get(), vertices.data(), vbByteSize, mBoxGeo->VertexBufferUploader);
mBoxGeo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
mCommandList.Get(), indices.data(), ibByteSize, mBoxGeo->IndexBufferUploader);
mBoxGeo->VertexByteStride = sizeof(Vertex);
mBoxGeo->VertexBufferByteSize = vbByteSize;
mBoxGeo->IndexFormat = DXGI_FORMAT_R16_UINT;
mBoxGeo->IndexBufferByteSize = ibByteSize;
mBoxGeo->DrawArgs["box"] = boxSubmesh;
mBoxGeo->DrawArgs["pyramid"] = pyramidSubmesh;
}
第六步 构建渲染流水线状态 不变
最后我们需要在绘制阶段 根据金字塔与正方体的不同顶点与索引起点绘制:
mCommandList->IASetVertexBuffers(0, 1, &mBoxGeo->VertexBufferView());
mCommandList->IASetIndexBuffer(&mBoxGeo->IndexBufferView());
mCommandList->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
UINT cbvIndex = 0;
auto cbvHandle = CD3DX12_GPU_DESCRIPTOR_HANDLE(mCbvHeap->GetGPUDescriptorHandleForHeapStart());
cbvHandle.Offset(cbvIndex, mCbvSrvUavDescriptorSize);
mCommandList->SetGraphicsRootDescriptorTable(0, cbvHandle);
mCommandList->DrawIndexedInstanced(mBoxGeo->DrawArgs["box"].IndexCount, 1, mBoxGeo->DrawArgs["box"].StartIndexLocation, mBoxGeo->DrawArgs["box"].BaseVertexLocation, 0);
cbvIndex++;
cbvHandle.Offset(cbvIndex, mCbvSrvUavDescriptorSize);
mCommandList->SetGraphicsRootDescriptorTable(0, cbvHandle);
mCommandList->DrawIndexedInstanced(mBoxGeo->DrawArgs["pyramid"].IndexCount, 1, mBoxGeo->DrawArgs["pyramid"].StartIndexLocation, mBoxGeo->DrawArgs["pyramid"].BaseVertexLocation, 0);
同时为了将金字塔与立方体分开 还需要对它们的世界矩阵进行一些调整,在update函数中修改:
XMMATRIX world_box = XMLoadFloat4x4(&mWorld_box);
XMMATRIX proj = XMLoadFloat4x4(&mProj);
XMMATRIX boxworldViewProj = world_box*view*proj;
XMMATRIX world_pyramid = XMLoadFloat4x4(&mWorld_pyramid);
world_pyramid = XMMatrixTranslation(-3.0f, 0.0f, -1.0f);
XMMATRIX pyramidworldViewProj = world_pyramid * view * proj;
ObjectConstants objConstants_box;
XMStoreFloat4x4(&objConstants_box.WorldViewProj, XMMatrixTranspose(boxworldViewProj));
mObjectCB->CopyData(0, objConstants_box);
ObjectConstants objConstants_pyramid;
XMStoreFloat4x4(&objConstants_pyramid.WorldViewProj, XMMatrixTranspose(pyramidworldViewProj));
mObjectCB->CopyData(1, objConstants_pyramid);
最终结果:
练习5 练习11
三角形内的像素通过 三个顶点的属性插值得到
这两种都是能正常工作的
第一种虽然color 与 pos排列的顺序变了
但是它们与顶点结构体元素的偏移还是对应的
第二种 顶点着色器 与 顶点结构体的对应是通过语义来间接对应的 所以交换顺序也不会影响
练习12 调整视口 练习13 裁剪测试
视口修改:
mScreenViewport.TopLeftX = 0;
mScreenViewport.TopLeftY = 0;
mScreenViewport.Width = static_cast<float>(mClientWidth);
mScreenViewport.Height = static_cast<float>(mClientHeight);
mScreenViewport.MinDepth = 0.0f;
mScreenViewport.MaxDepth = 1.0f;
裁剪修改:
mScissorRect = { 0, 0, mClientWidth, mClientHeight };
练习10 14 15 16 略
d3d12龙书阅读----绘制几何体(上) 课后习题的更多相关文章
- 视觉slam十四讲第8章课后习题3+稀疏直接法程序注释
版权声明:本文为博主原创文章,转载请注明出处: http://www.cnblogs.com/newneul/p/8571653.html 3.题目回顾:在稀疏直接法中,假设单个像素周围小块的光度也不 ...
- DX12龙书第6章习题
1. { { , DXGI_FORMAT_R32G32B32_FLOAT, , , D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, }, { , DXGI_FO ...
- 正则表达式引擎的构建——基于编译原理DFA(龙书第三章)——3 计算4个函数
整个引擎代码在github上,地址为:https://github.com/sun2043430/RegularExpression_Engine.git nullable, firstpos, la ...
- 编译原理 #03# 龙书中缀转后缀JS实现版
// 来自龙书第2章2.5小节-简单表达式的翻译器 笔记 既然是语法制导翻译(Syntax-directed translation),那么最重要的东西当然是描述该语言语法的文法,以下为中缀表达式文法 ...
- 开发微信小程序——古龙小说阅读器
概述 由于面试的关系接触了一下微信小程序,花了2晚上开发了一个带书签功能的古龙小说阅读器,并且已经提交审核等待发布.这篇博文记录了我的开发过程和对微信小程序的看法,供以后开发时参考,相信对其他人也有用 ...
- [HLSL]HLSL 入门参考 (dx11龙书附录B译文)
原文:[HLSL]HLSL 入门参考 (dx11龙书附录B译文) HLSL 高级着色语言 参考文档 龙书DirectX12现已推出中文版,其附录B的高级着色器语言参考的翻译质量比本文更高,有条件的读者 ...
- web实验指导书和课后习题参考答案
实验指导书 :http://course.baidu.com/view/daf55bd026fff705cc170add.html 课后习题参考答案:http://wenku.baidu.com/li ...
- 龙书(Dragon book) +鲸书(Whale book)+虎书(Tiger book)
1.龙书(Dragon book)书名是Compilers: Principles,Techniques,and Tools作者是:Alfred V.Aho,Ravi Sethi,Jeffrey D. ...
- Directx11学习笔记【八】 龙书D3DApp的实现
原文:Directx11学习笔记[八] 龙书D3DApp的实现 directx11龙书中的初始化程序D3DApp跟我们上次写的初始化程序大体一致,只是包含了计时器的内容,而且使用了深度模板缓冲. D3 ...
- 機器學習基石(Machine Learning Foundations) 机器学习基石 课后习题链接汇总
大家好,我是Mac Jiang,非常高兴您能在百忙之中阅读我的博客!这个专题我主要讲的是Coursera-台湾大学-機器學習基石(Machine Learning Foundations)的课后习题解 ...
随机推荐
- OpenHarmony开源开发者成长计划 | 知识赋能第六期预告—从零上手OpenHarmony智能家居项目
OpenAtom OpenHarmony(以下简称"OpenHarmony")开源开发者成长计划项目自 2021 年 10 月 24 日上线以来,在开发者中引发高度关注. 成长计划 ...
- Redis Pipelining 底层原理分析及实践
作者:vivo 互联网服务器团队-Wang Fei Redis是一种基于客户端-服务端模型以及请求/响应的TCP服务.在遇到批处理命令执行时,Redis提供了Pipelining(管道)来提升批处理性 ...
- HarmonyOS音视频开发概述
在音视频开发指导中,将介绍各种涉及音频.视频播放或录制功能场景的开发方式,指导开发者如何使用系统提供的音视频API实现对应功能.比如使用TonePlayer实现简单的提示音,当设备接收到新消息时, ...
- 基于tapd的git commit规范
现状 开发团队中,总是有人提交代码时的commit内容乱写一通,或者不明确不完整.当回溯代码的时候,很难通过commit内容定位历史记录,只能一条一条查看,找不到就要去问历史参与开发的其他同事,沟通成 ...
- nginx重新整理——————http请求的11个阶段中的content阶段[十八]
前言 简单介绍一下content 阶段. 正文 下面介绍一下root和alias. 这个前面其实就提交过了,这里再说明一下. 功能都是一样的:将url映射为文件路径,以返回静态文件内容. 差别:roo ...
- Deep Learning on Graphs: A Survey第五章自动编码论文总结
论文地址:https://arxiv.org/pdf/1812.04202.pdf 最近老师让我们读的一片论文,已经开组会讲完了,我负责的是第五章,图的自动编码,现在再总结一遍,便于后者研读.因为这篇 ...
- lattice,altera,xilinx三合一的图像转rom,mif软件
免费发一个软件, 图像转成文件. 下载地址:https://files.cnblogs.com/files/fpga-design/image_mif08030.zip
- 微软自带的Hyper-V虚拟机使用、VMware16安装Win10虚拟机介绍
一.首先介绍VMware虚拟机. 安装WIN10统虚拟机推荐用VMware16. 1.镜像网址: MSD网址传送门1:https://msdn.itellyou.cn MSD新网址传送门2:https ...
- 物联网浏览器(IoTBrowser)-整合机器学习yolo框架实现车牌识别
最近一段时间在研究AI技术在.Net平台的使用,目前AI绝大部分是使用Python开发,偶然一次在头条看到一篇ML.NET的介绍,是Net平台下开放源代码的跨平台机器学习框架.ML.NET详细介绍 h ...
- 【GDKOI 2024 TG Day2】染色(set) 题解
发现我们给一个点染上色后有: 我们称这是一个大小为 1 的十字. 进一步地,我们给这 5 个点再次染上色后有: 我们称这是一个大小为 2 的十字. 同理可得,我们给这 5 个点染上相同的大小为 2 的 ...