d3d12龙书阅读----绘制几何体(上) 课后习题

news/2024/11/17 6:41:23/文章来源:https://www.cnblogs.com/dyccyber/p/18200544

d3d12龙书阅读----绘制几何体(上) 课后习题

练习1 完成相应的顶点结构体的输入-布局对象

img


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 背面与正面剔除

这里启用线框模式可以帮助我们更好的观察
img
只需要在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

img

修改如下:

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个cbvint 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 face0, 1, 2,0, 2, 3,// back face4, 6, 5,4, 7, 6,// left face4, 5, 1,4, 1, 0,// right face3, 2, 6,3, 6, 7,// top face1, 5, 6,1, 6, 2,// bottom face4, 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);

最终结果:
img

练习5 练习11

img

三角形内的像素通过 三个顶点的属性插值得到

img
这两种都是能正常工作的

第一种虽然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 略

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/708856.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SAP PS 打开关闭的项目

1 ) 编辑-状态-关闭-撤销 2) TECO 撤销: ) 编辑-状态-技术完成-撤销

stm32f103c8t6使用bootloader进行ymodem下载和app程序测试,部分总结(暂未测试中断向量偏移问题)

bootloader程序部分(功能测试)print_boot_message();/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */uint8_t key_get_state;while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */key_get_state = get_key();switch(key_get_state){case 1: //…

夸克自动签到转存到emby

夸克自动签到不同于之前的阿里盘内夸克签到脚本,这里可以自动转存管理文件,添加到emby中 b站视频地址:https://www.bilibili.com/video/BV1ry411a7Lt 一、准备 你有服务器或者nas等等,有docker或者青龙都行。 由于nas在家关机了,我在外地。就不演示推到emby了。 来自于Cp0…

AI绘画拉取模型失败,DOS开启代理

我用了这么久的代理第一次知道DOS里面要开代理,惭愧惭愧。在我远程拉取模型的时候,挂科学也一直失败。在网上找报错找了很长时间没找到,最后经过一位群友的提示下,才知道问题出在DOS代理上面。直接看文章第一部分就行,要是直接tun不行,再看下面的直接开启tun这个是V2的开…

e语言 文本换行问题

我帮这人重写了下本文来自博客园,作者:__username,转载请注明原文链接:https://www.cnblogs.com/code3/p/18200506

【Quant102】如何计算 N 日斜率

一元线性回归的斜率公式是: \[k = \frac{(x - \bar{x})^T (y - \bar{y})}{\|x - \bar{x}\|^2} \]由于斜率具有平移不变性,x通常取 0 到窗口大小减一。 def slope(df, close_col=close, slope_col=slope, window=5, inplace=True):if not inplace: df = df.copy()x = np.arang…

利用MKL实现OpenCV的模板匹配(matchTemplate)

基于FFT实现OpenCV的模板匹配(matchTemplate) 以 TM_CCORR_NORMED 为例,因为这个实现简单,并且效率高。 先看公式 \[R(x,y)= \frac{\sum_{x,y} (T(x,y) \cdot I(x+x,y+y))}{\sqrt{ \sum_{x,y}T(x,y)^2 \cdot \sum_{x,y} I(x+x,y+y)^2}} \]显然,分子是I图和T图的卷积。 分母是…

主流原型设计工具介绍(●ϖ`●)

原型设计工具在产品设计、交互设计和用户体验设计中扮演着重要角色,本篇博客将介绍Axure RP、墨刀、Pixso、Adobe XD这4种主流原型设计工具。 Axure RP 特点强大的交互能力:强大的交互设计功能,支持复杂的交互流程和状态转换。 丰富的组件库:Axure RP 内置了大量的组件,包…

windev28 试用版 测试

下载地址 https://package.windev.com/pack/versiondemo/28/us/WDE28PACKDVDUS095g.zip建议迅雷下载 非常快 需要申请一个试用码 界面没啥变化 依旧只能生成32位程序,不过客户端在中国早就没落了 也没啥价值了 还不如去学electron

【Mybatis/Mybaits-Plus】【插件】插件执行时机

1 前言 我之前看过插件的执行过程:【Mybatis】【插件】Mybatis源码解析-插件机制,主要是通过一个 Executor 的创建以及执行过程串了一下插件,我们这里简单回忆下: (1)Mybatis 把所有的插件都放进了 InterceptorChain 类里的 interceptors 集合里 (2)插件的两个时机:入…

软件设计原则—开闭原则

对扩展开放,对修改关闭,使用接口或抽象类实现在程序需要进行拓展的时候,不能去修改原有的代码,而是实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。 想要达到这样的效果,我们需要使用接口和抽象类。 因为抽象灵活性好,适应性广,只要抽象的合理…

【开源】2024最新python豆瓣电影数据爬虫+可视化分析项目

项目介绍 【开源】项目基于python+pandas+flask+mysql等技术实现豆瓣电影数据获取及可视化分析展示,觉得有用的朋友可以来个一键三连,感谢!!! 项目演示 [video(video-C9B87WwE-1716106102936)(type-bilibili)(url-https://player.bilibili.com/player.html?aid=120451806…