美文网首页
使用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——渲染纹理

    渲染纹理过程 其余过程与渲染三角形一致,如下是多的操作步骤: 编写着色器具体见下[着色器]一节。 创建纹理使用Cr...

  • 使用Dx11渲染纹理3——渲染矩形

    渲染矩形 渲染矩形只需要将顶点及顶点索引做修改,建立两个三角形,并且修改图元拓扑为:IASetPrimitiveT...

  • 纹理渲染

    直线 起点 终点。对于rgb 每一个像素点都要描述出来 纹理 起点在哪 终点在哪 中间描述如何渐变 纹理渲染 ...

  • 使用OpenGL绘制一个地球

    一、程序简介 本项目使用 OpenGL 实现了球型3D模型的生成和渲染;进行了纹理贴图,同时使用了多个纹理,渲染了...

  • 贴图的种类以及相关属性

    一般的贴图又称纹理贴图,是早期渲染工程师为了处理顶点渲染以及差值渲染所引起 的视觉误差而使用的位图影像。纹理通常含...

  • CPU优化

    渲染模块 降低DrawDall通过批渲染来达来降低DC。 简化资源模型面数,数量纹理数量纹理尺寸纹理格式选择硬件支...

  • OpenGL ES - 纹理

    纹理 什么是纹理 纹理是一个缓存,用来保存图像的颜色元素值 纹理可以使用任何图像 当纹理应用到图形中,会使渲染场景...

  • Ⅷ使用深度和法线纹理

    使用深度和法线纹理 获取深度和法线纹理 背后原理 深度纹理实际就是一张渲染纹理,只不过它里面存储的像素值不是颜色值...

  • OpenGL ES 分屏滤镜

    分屏滤镜的实现(分屏算法):主要渲染区域与纹理坐标映射对应关系。解析案例中2、3、4、6、9分屏中纹理坐标与渲染区...

  • mipmap纹理在各端显示的阈值

    近期在渲染模型的时候发现,在某个角度下,模型上有没有显示的纹理呈现黑色,经过是mipmap的纹理超出了系统渲染纹理...

网友评论

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

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