利用Direct3D绘制几何体(续)

学习目标

  1. 学会一种无须每帧都要刷新命令队列的渲染流程,由此来优化程序的性能

  2. 了解另外两种跟签名参数类型:根描述符和根常量

  3. 探索如何在程序中生成和绘制常见的几何体,如栅格、圆台和球体

  4. 研究如何通过动态顶点缓冲区来更新CPU中的顶点数据,并且向GPU中上传顶点新的位置信息

7.6、 细探根签名

在前面我们已经介绍过跟签名,它定义了在绘制调用之前,需要绑定到渲染流水线上的资源,以及这些资源如何映射到着色器的输入寄存器中。

7.6.1 、根参数

根签名是由一系列根参数组成的,到目前为止,我们只创建过只含有一个描述符表的根参数。实际上,根参数有三个类型可以选择:

  1. 描述符表:描述符表引用的是描述符堆中的一块连续范围,用于确定要绑定的资源
  2. 根描述符:通过直接设置根描述符就可以指示要绑定的资源,无需将它存在描述符堆中。但是,只有常量缓冲区的CBV,缓冲区的SRV/UAV才能使用根描述符进行绑定
  3. 根常量:借助根常量即可直接绑定一系列32位的常量值

考虑到性能的原因,一个根签名最好不要放置超过64DWORD的根参数,下面是三种根参数的空间占用情况:

  1. 描述符表:1DWORD
  2. 根描述符:2DWORD
  3. 根常量:每个常量32位,占1DWORD

在代码中,我们需要通过填写CD3DX12_ROOT_PARAMETER结构体来描述根参数,CD3DX12_ROOT_PARAMETER是对结构体D3D12_ROOT_PARAMETER进行的扩展,并增加一些辅助初始化函数而得到的

typedef struct D3D12_ROOT_PARAMETER
{
//用于指示根参数的类型(描述符表,根常量或者根描述符)
D3D12_ROOT_PARAMETER_TYPE ParameterType;
//描述根参数的结构体
union
{
D3D12_ROOT_DESCRIPTOR_TABLE DescriptorTable;
D3D12_ROOT_CONSTANTS Constants;
D3D12_ROOT_DESCRIPTOR Descriptor;
};
//指定此根参数在着色器程序中的可见性
D3D12_SHADER_VISIBILITY ShaderVisibility;
}D3D12_ROOT_PARAMETER;

7.6.2、描述符表

通过填写D3D12_ROOT_PARAMERTER结构体中的成员DescriptorTable,即可将根参数的类型定义为描述符表(Descriptor Tabel)

typedef struct D3D12_ROOT_DESCRIPTOR_TABLE
{
//D3D12_DESCRIPTOR_RANGE类型数组的元素个数
UINT NumDescriptorRanges;
//指向D3D12_DESCRIPTOR_RANGE类型数组的指针
const D3D12_DESCRIPTOR_RANGE *pDescriptorRanges;
}D3D12_ROOT_DESCRIPTOR_TABLE;

通过上述的结构体,我们可以指定一个D3D12_DESCRIPTOR_RANGE类型的数组:

typedef struct D3D12_DESCRIPTOR_RANGE
{
//此范围中的描述符类型
D3D12_DESCRIPTOR_RANGE_TYPE RangeType;
//此范围内描述符的数量
UINT NumDescriptors;
//此描述符范围要绑定的基准着色器寄存器
UINT BaseShaderRegister;
//此描述符范围要绑定的寄存器空间
UINT RegisterSpace;
//此描述符范围距离描述符表起始地址的偏移量
UINT OffsetInDescriptorsFromTableStart;
}D3D12_DESCRIPTOR_RANGE;

接下来我们举个例子:用3个CBV、2个SRV和1个UAV创建一个描述符表

//用3个CBV、2个SRV和1个UAV来创建一个描述符表
CD3DX12_DESCRIPTOR_RANGE descRange[3];
descRange[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 3, 0, 0, 0);
descRange[1].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 2, 0, 0, 3);
descRange[2].Init(D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 1, 0, 0, 5);
CD3DX12_ROOT_PARAMETER slotRootParameter[1];
slotRootParameter[0].InitAsDescriptorTable(3, descRange, D3D12_SHADER_VISIBILITY_ALL);

7.6.3、根描述符

通过填写结构体D3D12_ROOT_PARAMETER中的成员Descriptor,即可将根参数类型定义为根描述符(Root Descriptor)

typedef struct D3D12_ROOT_DESCRIPTOR
{
//指定要绑定的着色器寄存器
UINT ShaderRegister;
//指定要绑定的着色器寄存器空间
UINT RegisterSpace;
}D3D12_ROOT_DESCRIPTOR;

和描述符表需要在描述符中设置对应的描述符句柄不同,要配置描述符,我们只需要绑定资源的虚拟地址即可

//计算常量缓冲区的大小
UINT objCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(ObjectConstants));
//资源的虚拟地址
D3D12_GPU_VIRTUAL_ADDRESS cbAddress = objectCB->GetGPUVirtualAddress();
//偏移到缓冲区中此物体常量的地址
cbAddress += i*objCBByteSize;
cmdList->setGraphicsRootVConstnatBufferView(0, objCBAddress);

7.6.4、根常量

通过填写结构体D3D12_ROOT_PARAMETER的成员Constants,即可进一步将根参数类型定义为根常量(Root Constant)

typedef struct D3D12_ROOT_CONSTANTS
{
//指定绑定的寄存器
UINT ShaderRegister;
//指定绑定的寄存器空间
UINT RegisterSpace;
//根参数所需要的32位常量个数
UINT Num32BitValues;
}D3D12_ROOT_CONSTANTS;

根参数的使用示例就不展示了。

7.6.5、 更复杂的根签名示例

考虑一下着色器所需要的下列资源的情景:

Texture2D gDiffuseMap : register(t0);

cbuffer cbPerObject : register(b0)
{
float4x4 gWorld;
float4x4 gTexTransform;
} cbuffer cbPass : register(b1)
{
float4x4 gView;
float4x4 gInvView;
float4x4 gProj;
float4x4 gInvProj;
float4x4 gViewProj;
float4x4 gInvViewProj;
float3 gEvePosW;
float cbPerObjectPad1;
float2 gRenderTargetSize;
float2 gInvRenderTargetSize;
float gNearZ;
float gFarZ;
float gTotalTime;
float gDeltaTime;
float4 gAmbientLight;
} cbuffer cbMaterial : register(b2)
{
float4 gDiffuseAlbedo;
float3 gFresne1R0;
float gRoughness;
float4x4 gMatTransform;
}

此着色器对应的根签名描述:

//描述符范围,给描述符表使用
CD3DX12_DESCRIPTOR_RANGE texTable;
texTable.Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0); CD3DX12_ROOT_PARAMETER slotRootParameter[4];
//性能提示:按变更频率由高到低进行排列
slotRootParameter[0].InitAsDescriptorTable(1, &texTable, D3D12_SHADER_VISIBILITY_PIXEL);
slotRootParameter[1].InitAsConstantBufferView(0);
slotRootParameter[2].InitAsConstantBufferView(1);
slotRootParameter[3].InitAsConstantBufferView(2);
CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(4, slotRootParameter, 0, nullptr,
D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);

7.6.6、根参数的版本控制

DirectX12 3D 游戏开发与实战第七章内容(下)的更多相关文章

  1. DirectX12 3D 游戏开发与实战第七章内容(上)

    利用Direct3D绘制几何体(续) 学习目标 学会一种无须每帧都要刷新命令队列的渲染流程,以此来优化性能 了解另外两种根签名参数类型:根常量和根描述符 探索如何在程序中生成和绘制常见的几何体:如栅格 ...

  2. DirectX12 3D 游戏开发与实战第五章内容

    渲染流水线 学习目标: 了解用于在2D图像中表现出场景立体感和空间深度感等真实效果的关键因素 探索如何用Direct3D表示3D对象 学习如何建立虚拟摄像机 理解渲染流水线,根据给定的3D场景的几何描 ...

  3. DirectX12 3D 游戏开发与实战第六章内容

    利用Direct3D绘制几何体 学习目标 探索用于定义.存储和绘制几何体数据的Direct接口和方法 学习编写简单的顶点着色器和像素着色器 了解如何用渲染流水线状态对象来配置渲染流水线 理解怎样创建常 ...

  4. DirectX12 3D 游戏开发与实战第四章内容(上)

    Direct3D的初始化(上) 学习目标 了解Direct3D在3D编程中相对于硬件所扮演的角色 理解组件对象模型COM在Direct3D中的作用 掌握基础的图像学概念,例如2D图像的存储方式,页面翻 ...

  5. DirectX12 3D 游戏开发与实战第四章内容(下)

    Direct3D的初始化(下) 学习目标 了解Direct3D在3D编程中相对于硬件所扮演的角色 理解组件对象模型COM在Direct3D中的作用 掌握基础的图像学概念,例如2D图像的存储方式,页面翻 ...

  6. DirectX12 3D 游戏开发与实战第三章内容

    变换 学习目标 理解如何使用矩阵表示线性变换和仿射变换 学习对几何体进行缩放.旋转和平移的坐标变换 根据矩阵之间的乘法运算性质,将多个变换矩阵合并为一个单独的净变换矩阵 找寻不同坐标系之间的坐标转换方 ...

  7. DirectX12 3D 游戏开发与实战第十一章内容

    仅供个人学习使用,请勿转载.谢谢! 11.模板 模板缓冲区(stencil buffer)是一种"离屏"(off-screen)缓冲区,我们可以利用它来实现一些效果.模板缓冲区.后 ...

  8. DirectX12 3D 游戏开发与实战第八章内容(下)

    DirectX12 3D 游戏开发与实战第八章内容(下) 8.9.材质的实现 下面是材质结构体的部分代码: // 简单的结构体来表示我们所演示的材料 struct Material { // 材质唯一 ...

  9. DirectX12 3D 游戏开发与实战第八章内容(上)

    8.光照 学习目标 对光照和材质的交互有基本的了解 了解局部光照和全局光照的区别 探究如何用数学来描述位于物体表面上某一点的"朝向",以此来确定入射光照射到表面的角度 学习如何正确 ...

随机推荐

  1. UML快速概述 - All you need to know about UML

    UML 是统一建模语言的缩写,就像使用一组图表来可视化软件建模的蓝图(或设计计划).它不仅可以让您彻底评估整个概念,还可以确保团队中的每个人都在同一页面上.   UML 图可以组织成两个不同的组. 结 ...

  2. pagelayout在py中的引用不支持size_hint和pos_hint

    from kivy.uix.pagelayout import PageLayout from kivy.uix.button import Button from kivy.app import A ...

  3. Beta Scrum Meeting汇总

    第0次Alpha Scrum Meeting 第1次Alpha Scrum Meeting 第2次Alpha Scrum Meeting 第3次Alpha Scrum Meeting 第4次Alpha ...

  4. makedown笔记

    makedown语法 表格 这个表格的主题 |姓名|性别|年龄|职业| | ----- | ----- | ----- | ----- | |张三|男|34|码农| |李四|男|27|代驾| 这个表格 ...

  5. 华为HCIP-Eth-trunk原理知识点

    Eth-trunk(端口聚合.链路捆绑.链路聚合.以太通道) Eth-trunk技术出现的原因: • 随着网络中部署的业务量不断增长,对于全双工点对点链路,单条物理链路的带宽已不能满足正常的业务流量 ...

  6. 【做题记录】 [HEOI2013]SAO

    P4099 [HEOI2013]SAO 类型:树形 \(\text{DP}\) 这里主要补充一下 \(O(n^3)\) 的 \(\text{DP}\) 优化的过程,基础转移方程推导可以参考其他巨佬的博 ...

  7. Huffman算法

    一.Huffman算法介绍 霍夫曼编码(英语:Huffman Coding),又译为哈夫曼编码.赫夫曼编码,是一种用于无损数据压缩的熵编码(权编码)算法.在计算机数据处理中,霍夫曼编码使用变长编码表对 ...

  8. PCIE学习笔记--PCIe错误源详解(二)

    转载地址:http://blog.chinaaet.com/justlxy/p/5100057799 这篇文章主要介绍事务(Transaction)错误.链路流量控制(Link Flow Contro ...

  9. linux 虚拟网络设备的使用

    1. linux 常见虚拟网络设备分类 常见虚拟网络设备有:bridge, tun/tap, veth-pairs, macvlan, macvtap等.有一篇博文写的挺好的,图文并茂:虚拟网络设备, ...

  10. QuantumTunnel:协议路由 vs 端口路由

    本篇来聊一下内网穿透中流量转发的问题 内网穿透和核心逻辑是根据流量的路由信息准确地将公网流量路由到指定的机器端口上,从而完成一次流量的内网穿透. 这里有一个核心问题,路由信息从哪里获取? 常见的有将路 ...