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)的课后习题解 ...
随机推荐
- 推荐两款HTTP请求Mock利器
1.背景 在日常测试过程中或者研发开发过程中,目前接口暂时没有开发完成,测试人员又要提前介入接口测试中,测试人员不仅仅只是简单的编写测试用例,也可以通过一些mock的方法进行来提前根据接口测试的情况进 ...
- mysql 必知必会整理—触发器[十五]
前言 现在很多都是程序用于触发的,而不是触发器了. 正文 需要MySQL 5 对触发器的支持是在MySQL 5中增加的.因此,本章内容适用于MySQL 5或之后的版本. MySQL语句在需要时被执行, ...
- Python Flask获取iOS的UDID
测试iOS app时候,我们可以安装以下4种类型的包 : AdHoc -- 一般为正式环境验证AppStore -- 上传AppStore,只有 ...
- dom4j 通用解析器,解析成List<Map<String,Object>>
import java.io.InputStream; import java.util.Iterator; import java.util.LinkedHashMap; import java.u ...
- 妙用 drop-shadow 实现线条光影效果
本文将介绍一种利用 CSS 滤镜 filter 的 drop-shadow(),实现对 HTML 元素及 SVG 元素的部分添加阴影效果,以实现一种酷炫的光影效果,用于各种不同的场景之中.通过本文,你 ...
- 使用 Docker Compose 安装 APISIX
1.基本概念 APISIX 是 Apache 下的一款云原生的 API 网关,支持全生命周期的 API 管理,在应用中可以作为所有 API 调用的统一入口. APISIX 有一些基础概念如下: Ups ...
- 顺通ERP:精细敏捷的设计理念,得到了消费者的喜爱
顺通ERP是近年来备受关注的一款ERP品牌,其设计精细,操作便捷,备受消费者喜爱.那么,顺通ERP到底怎么样呢?属于什么档次呢? 首先,从品质上来看,顺通ERP具备高度的稳定性,能够确保企业的日常运营 ...
- 从操作系统层面分析Java IO演进之路
简介: 本文从操作系统实际调用角度(以CentOS Linux release 7.5操作系统为示例),力求追根溯源看IO的每一步操作到底发生了什么. 作者 | 道坚来源 | 阿里技术公众号 前言 本 ...
- [Caddy2] URL访问路径的重定向和重写规则 (redir/rewrite 指令)
当我们在规划网站路径时,为了保留搜索引擎收录 避免404的同时做到升级,常用到重定向跳转和URL重写. 重定向(redirect) 在 Caddy 中为 redir 指令. https://caddy ...
- [FE] 关于网页的一些反爬手段的解析思路,比如 58 等
这里主要是贴一些资料,有兴趣的可以再深入研究,比如做一些自动化库. www.cnblogs.com/TRHX/p/11740616.html blog.csdn.net/DzzzzzZzzzz/art ...