0
点赞
收藏
分享

微信扫一扫

十、D3D12学习笔记——纹理

勇敢的趙迦禾 2022-04-13 阅读 25

首先声明,本人是自学DX12,有很多的理解也许不到位,不过都是自己的理解。在很长一段时间里边,我从迷茫到有一天开始能看懂,现在是第三次开始刷DX12了,于是在此表明写作的初衷:

1.有一些DX12的学习心得,希望发出来,有大佬如果愿意指教,万分感谢;

2.如果对于才入门的人来说,这可能是我的白话教程,也许会对你有所帮助,但不可尽信,因为我也不确定我对不对;

3.DX12的概念很多,也是想把这作为自己的学习笔记来做,希望对自己也有帮助,如果有一天我发现哪里错了会及时回来更正。

那么话不多说,现在开始!!!

一、概述

纹理给人的感觉就是图片,但这种理解比较局限.....

你懂的,都是些套话,我不想这么写,因为我不想水字数,因此我就直接上强度吧:

1.纹理也是ID3D12Resource类型,但是不同于缓冲区,因为纹理可以有多个mipmap,这是要依赖与特定的数据结构的。

2.我们创建数据的时候一般都会给一个数据类型,但是有时候也可能是typeless,使用无类型。无类型会增加开销,因为涉及到数据的转化。不过对于无类型在创建描述符(视图)来进行解释的时候一定要明确。

3.纹理都要作为渲染管线使用的资源,都要存储到显存当中,为了减少存储空间的占用,一般会压缩纹理,但是经过压缩之后的纹理只可以作为着色器资源,不可以作为渲染目标。

二、创建纹理与数据传输

前提:使用DDS纹理,亲测PS方法有效,不过注意尺寸为4整数倍。

1.加载纹理资源(DDS文件)——数据

函数直接返回加载的数据texture以及对应的上传堆textureUploadHeap。

auto waterTex = std::make_unique<Texture>();
    waterTex->Name = "waterTex";
    waterTex->Filename = L"../../Textures/water1.dds";
    ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
        mCommandList.Get(), waterTex->Filename.c_str(),
        waterTex->Resource, waterTex->UploadHeap)); 

2.资源描述符堆——存数据的“数组”

创建可存储三个纹理的描述符堆:
D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {};
    srvHeapDesc.NumDescriptors = 3;
    srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
    srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
    ThrowIfFailed(md3dDevice->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&mSrvDescriptorHeap)));

3.创建描述符——将数据放入“数组”

CD3DX12_CPU_DESCRIPTOR_HANDLE hDescriptor(mSrvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());//获得描述符堆的地址

偏移到准确地址:hDescriptor.Offset(1, mCbvSrvDescriptorSize);

waterTex = mTextures["waterTex"]->Resource;//数据的上传堆

//填写解释结构体

D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
    srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
   srvDesc.Format = waterTex->GetDesc().Format;
    srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
    srvDesc.Texture2D.MostDetailedMip = 0;
    srvDesc.Texture2D.MipLevels = -1;

//使用结构体创建:数据资源上传堆,解释结构,堆地址——将数据及其解释方法放到数组存起来
    md3dDevice->CreateShaderResourceView(waterTex.Get(), &srvDesc, hDescriptor);

4.绑定到渲染流水线——根签名

CD3DX12_DESCRIPTOR_RANGE texTable;
    //数量,寄存器:(书记)
    texTable.Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0);
    CD3DX12_ROOT_PARAMETER slotRootParameter[1];
    slotRootParameter[0].InitAsDescriptorTable(1, &texTable, D3D12_SHADER_VISIBILITY_PIXEL);

根描述符表定义寄存器的槽,然后传入根参数,创建根签名后设置:

CD3DX12_GPU_DESCRIPTOR_HANDLE tex(mSrvDescriptorHeap->GetGPUDescriptorHandleForHeapStart());
tex.Offset(ri->Mat->DiffuseSrvHeapIndex, mCbvSrvDescriptorSize);//获得纹理数据在显存的位置

cmdList->SetGraphicsRootDescriptorTable(0, tex);//根参数0号索引定义了寄存器槽,与显存资源绑定

根据绑定结果在shader中自动填充以下结构:
Texture2D    gDiffuseMap : register(t0);

三、使用纹理资源

我们已经将纹理数据存入了显存,并且设置了其绑定到流水线,可自动填充shader中变量,但是该如何使用?——采样器。

采样器也是一种资源,我们先介绍一种简单的用法:

1.静态采样器

这种采用采样器虽然也是资源,但是不用创建堆来存储、解释,只需要进行如下两步设置:

1).填写静态采样器结构:

const CD3DX12_STATIC_SAMPLER_DESC pointWrap(
        0, // shaderRegister
        D3D12_FILTER_MIN_MAG_MIP_POINT, // 过滤方式
        D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // 寻址方式
        D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // 寻址方式
        D3D12_TEXTURE_ADDRESS_MODE_WRAP); // 寻址方式

......

都传入数据staticSamplers;

2).使用根签名预留参数传入渲染流水线

CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(1, slotRootParameter,
        (UINT)staticSamplers.size(), staticSamplers.data(),//这里就是上边静态采样器的数据,以前我们总是设置为0和nullptr
        D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);

经过以上两步设置,我们在shader中就能为如下结构传递数据:

SamplerState gsamPointWrap        : register(s0);
SamplerState gsamPointClamp       : register(s1);
SamplerState gsamLinearWrap       : register(s2);
SamplerState gsamLinearClamp      : register(s3);
SamplerState gsamAnisotropicWrap  : register(s4);
SamplerState gsamAnisotropicClamp : register(s5);

静态采样器最多可以创建2032个,有点类似跟常量或者是根描述符,不需要堆,但是会有一定的空间占用,那么如果超过2032个,我们还可以使用根描述符表来设置,这是需要堆来解释的,如下。

2.使用根描述符表设置的采样器

这部分我主要粘贴D3D的图片,因为静态采样的2032个采样器一般我们是用不完的,所以这部分没有多大的使用必要。

1).创建根签名

使用 rootSigDesc...完成根签名的创建,把采样器放在根参数的1号索引上

2).创建描述符堆和描述符来对采样器资源进行存储与解释

这个资源是解释采样的方式和参数等,比如过滤和寻址模式等:

堆:

描述符:将数据描述放入堆存起来

2).绑定到渲染流水线

根参数的1号索引记录的寄存器槽与描述符堆地址串联,方便数据自动填充到shader中

 大概的形式如下:
SamplerState gsamPointWrap        : register(s0);

3.shader中使用采样器

gDiffuseMap.Sample(gsamAnisotropicWrap, pin.TexC);

//纹理.Sample(采样器,纹理坐标);

上述过程虽然没有一个完整的代码展示,但是只要你了解我们之前在初级篇讲解的所有内容,不难发现我们实际是没有很多新东西的,纹理资源的创建传输,采样器的使用等都有迹可循,希望你喜欢。

 

 

 

 

举报

相关推荐

0 条评论