DirectX12 3D 游戲開發與實戰第七章內容(下)


利用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、根參數的版本控制


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM