美文网首页
使用Dx11渲染纹理4——渲染纹理

使用Dx11渲染纹理4——渲染纹理

作者: 上官宏竹 | 来源:发表于2022-01-12 16:49 被阅读0次

    渲染纹理过程

    其余过程与渲染三角形一致,如下是多的操作步骤:

    1. 编写着色器
      具体见下[着色器]一节。
    2. 创建纹理
      使用CreateTexture2D创建一个带数据的纹理图像。
    3. 使用纹理创建资源视图
      传入创建的纹理,使用CreateSamplerState创建一个着色器资源视图。(注意:该纹理的BindFlags需要设置为D3D11_BIND_SHADER_RESOURCE)。使用GenerateMips为资源视图创建Mipmap层级。
    4. 绑定资源视图到管线
      使用PSSetShaderResources将资源视图绑定到像素着色器中。
    5. 创建采样器状态
      使用CreateSamplerState创建一个纹理采样器对象。
    6. 绑定采样器状态到管线
      使用PSSetSamplers将创建的纹理采样器对象绑定到像素着色器中。

    纹理映射

    要将.dds图形映射到像素我们用的是Texel坐标系统。这个系统将将整数值的像素变换到0.0f和1.0f之间的浮点数。例如,如果一张纹理宽为256个像素,那么第一个像素映射为0.0f,第256个像素映射为1.0f,中间的第128个像素映射为0.5f。
    在texel坐标系统中,水平方向的值名为“U"”,垂直方向为“V”。水平方向左边为0.0,右边为1.0。竖直方向顶部为0.0,底部为1.0。例如,左上角为U 0.0、V 0.0,右下角为U 1.0、 V 1.0。下图就表示了纹理坐标系统:


    纹理坐标

    着色器

    结构体定义

    • 顶点着色器输入结构
    struct tVinputType
    {
        float4 position : myPOSITION;   // 顶点位置(x/y/z/w)
        float2 tex : myTEXCOORD;        // 纹理坐标(u/v)
    };
    
    • 像素着色器输入结构
    struct tPinputtype
    {
        float4 position : SV_POSITION;  // 位置。SV_POSITION像素着色器内部变量
        float2 tex : myTEXCOORD;            // 纹理坐标
    };
    

    其中myPOSITIONmyTEXCOORD都是自定义语义,在创建顶点输入布局中指定。另,float4 position : myPOSITION;,由于只使用了2D,这里可以只传入float2类型的位置信息,在着色器中自动补全到float4

    const D3D11_INPUT_ELEMENT_DESC inputElementDescs[] =
    {
        { "myPOSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, // float4类型
        { "myTEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12u, D3D11_INPUT_PER_VERTEX_DATA, 0 },  // float2类型
    };
    

    顶点着色器

    纹理的顶点着色器中,输入需要顶点位置和纹理坐标,之前的三角形渲染中,顶点着色器中使用的输入是顶点位置和颜色。

    tPinputtype TextureVsMain(tVinputType input)
    {
        tPinputtype output;
    
        // w分量不从CPU传入,而默认设置为1.0f
        input.position.w = 1.0f;
    
        output.position = input.position;
        output.tex = input.tex;
    
        return output;
    }
    

    像素着色器

    /////////////
    // GLOBALS //
    /////////////
    Texture2D myShaderTexture;  // 使用PSSetShaderResources绑定到着色器的纹理资源
    SamplerState mySampleType;  // 使用PSSetSamplers绑定到着色器的采样器状态
    
    // 入口函数
    float4 TexturePsMain(tPinputtype input) : SV_TARGET
    {
        float4 textureColor;
    
        // Sample函数使用采样器状态(mySampleType)和该像素的纹理坐标(tex),
        // 来确定并返回多边形面上此UV位置的像素值。
        textureColor = myShaderTexture.Sample(mySampleType, input.tex);
    
        return textureColor;
    }
    

    Texture2D myShaderTexture,为定义为2D纹理的纹理资源,类型Texture2D,这是绑定到渲染管线的那个纹理资源(即使用PSSetShaderResources绑定到像素着色器的纹理资源)。这样shader就可以访问这个纹理并用于绘制了。
    SamplerState mySampleType,为采样状态。采样状态可以通过PSSetSamplers设置到像素着色器。

    2D纹理的描述

    typedef struct D3D11_TEXTURE2D_DESC
    {
        UINT Width;                     // 纹理宽度
        UINT Height;                    // 纹理高度
        UINT MipLevels;                 // 允许的Mip等级数
        UINT ArraySize;                 // 可以用于创建纹理数组,这里指定纹理的数目,单个纹理使用1
        DXGI_FORMAT Format;             // DXGI支持的数据格式,默认DXGI_FORMAT_R8G8B8A8_UNORM
        DXGI_SAMPLE_DESC SampleDesc;    // MSAA描述
        D3D11_USAGE Usage;              // 使用D3D11_USAGE枚举值指定数据的CPU/GPU访问权限
        UINT BindFlags;                 // 使用D3D11_BIND_FLAG枚举来决定该数据的使用类型
        UINT CPUAccessFlags;            // 使用D3D11_CPU_ACCESS_FLAG枚举来决定CPU访问权限
        UINT MiscFlags;                 // 使用D3D11_RESOURCE_MISC_FLAG枚举
    }   D3D11_TEXTURE2D_DESC;
    
    typedef struct DXGI_SAMPLE_DESC
    {
        UINT Count;                     // MSAA采样数
        UINT Quality;                   // MSAA质量等级
    } DXGI_SAMPLE_DESC;
    
    • MipLevels
    1. 如果你希望它不产生mipmap,则应当指定为1(只包含最大的位图本身)
    2. 如果你希望它能够产生完整的mipmap,可以指定为0,这样你就不需要手工去算这个纹理最大支持的mipmap等级数了,在创建好纹理后,可以再调用ID3D11Texture2D::GetDesc来查看实际的MipLevels值是多少
    3. 如果你指定的是其它的值,这里举个例子,该纹理的宽高为400x400,mip等级为3时,该纹理会产生400x400,200x200和100x100的mipmap
    • SampleDesc
      对于经常作为着色器资源的纹理,通常是不能对其开启MSAA的,应当把Count设为1,Quality设为0
    • Format
      它用于指定纹理存储的数据格式,最常用的就是DXGI_FORMAT_R8G8B8A8_UNORM了。这种格式在内存的排布可以用下面的结构体表示:
    struct {
        uint8_t r;
        uint8_t g;
        uint8_t b;
        uint8_t a;
    };
    
    • Usage
    D3D11_USAGE CPU读 CPU写 GPU读 GPU写
    D3D11_USAGE_DEFAULT
    D3D11_USAGE_IMMUTABLE
    D3D11_USAGE_DYNAMIC
    D3D11_USAGE_STAGING
    1. D3D11_USAGE_DEFAULT
      它可以使用下面的这些方法来更新纹理:
      ID3D11DeviceContext::UpdateSubresource(更建议使用此方法更新数据)
      ID3D11DeviceContext::CopyResource
      ID3D11DeviceContext::CopySubresourceRegion
      通过DDSTextureLoaderWICTextureLoader创建出来的纹理默认都是这种类型。
    2. D3D11_USAGE_IMMUTABLE
      必须在创建阶段就完成纹理资源的初始化。此后GPU只能读取,也无法对纹理再进行修改。
      D3D11_USAGE_IMMUTABLE非常适合纹理等数据,因为此类数据通常从某种文件格式读入内存。因此,当您使用D3D11_USAGE_IMMUTABLE创建纹理时,GPU 会直接将该纹理读取到内存中。
    3. D3D11_USAGE_DYNAMIC
      这种纹理通常需要频繁从CPU写入,使用ID3D11DeviceContext::Map方法将显存映射到内存,经过修改后再调用ID3D11DeviceContext::Unmap方法应用更改。
      D3D11_USAGE_DYNAMIC通常用于具有顶点数据的资源和常量缓冲区。
      该类型纹理MipLevels必须为1,且不能是纹理数组,即ArraySize必须为1。
    4. D3D11_USAGE_STAGING
      完全允许在CPU和GPU之间的数据传输,但它只能作为一个类似中转站的资源,而不能绑定到渲染管线上,即你也不能用该纹理生成mipmaps,即MipLevels必须为1。
      例如,你有一个D3D11_USAGE_DEFAULT类型的纹理A,想要将其数据拷贝到内存中,因为D3D11_USAGE_DEFAULT类型的纹理没有CPU读的权限,因此此时需要借助D3D11_USAGE_STAGING类型纹理做中转,即新建一个D3D11_USAGE_STAGING类型的纹理B,通过ID3D11DeviceContext::CopyResource或者ID3D11DeviceContext::CopySubresourceRegion方法将A纹理的数据复制到B纹理中,再通过ID3D11DeviceContext::Map方法将B纹理的数据映射到内存中。
    • BindFlags
    D3D11_BIND_FLAG 描述
    D3D11_BIND_RENDER_TARGET 纹理可以作为渲染目标的输出点,并且指定它可以用于生成mipmaps
    D3D11_BIND_SHADER_RESOURCE 纹理可以作为着色器资源绑定到渲染管线
    D3D11_BIND_STREAM_OUTPUT 纹理可以作为流输出阶段的输出点
    D3D11_BIND_DEPTH_STENCIL 纹理可以作为深度/模板缓冲区
    D3D11_BIND_UNORDERED_ACCESS 纹理可以绑定到无序访问视图作为输出
    • CPUAccessFlags
    1. 0
      可以获得更好的资源优化操作。
    2. D3D11_CPU_ACCESS_WRITE
      内存数据可以通过MapUnmap的方式拷贝到纹理中。
      纹理可以作为渲染目标的输出点,并且指定它可以用于生成mipmaps。与D3D11_BIND_RENDER_TARGET一致。
    3. D3D11_CPU_ACCESS_READ
      纹理可以作为着色器资源绑定到渲染管线。与D3D11_BIND_SHADER_RESOURCE一致。
    • MiscFlags
      D3D11_RESOURCE_MISC_GDI_COMPATIBLE
      启用与 GDI 兼容的资源。设置D3D11_RESOURCE_MISC_GDI_COMPATIBLE标志允许通过IDXGISurface1::GetDC在表面上呈现GDI。它有许多的限制,请参考官方说明

    参考:DirectX 10 教程5:纹理
    完整代码见:使用git log可以查看渲染纹理的过程

    相关文章

      网友评论

          本文标题:使用Dx11渲染纹理4——渲染纹理

          本文链接:https://www.haomeiwen.com/subject/ejkyqrtx.html