【DirectX11】【学习笔记(9)】纹理贴图

最近在做UE4项目的时候,感觉自己对于贴图的部分理解还是不够,今天顺便复习一下。

本节内容,我们要学习如何导入贴图,并且把贴图映射到我们的物体上。

在DirectX3D中,我们使用UV坐标来映射贴图到物体。U是水平,V是垂直坐标。并且U,V都在0-1之间。所以当U,V都为1时,就是图像的结束位置。

如果我们把U,V的坐标都改成2的时候,它会在物体上重复

Global Declarations

声明的第一个接口对象是用来保存我们从文件中导入的贴图,

第二个接口对象是保存我们的采样信息的。

Vertex Structure/Input Layout

因为我们要对顶点进行UV映射,所以要在顶点结构中加入贴图坐标。

struct Vertex    //Overloaded Vertex Structure
{
    Vertex(){}
    Vertex(float x, float y, float z,
        float u, float v)
        : pos(x,y,z), texCoord(u, v){}

    XMFLOAT3 pos;
    XMFLOAT2 texCoord;
};

D3D11_INPUT_ELEMENT_DESC layout[] =
{
    { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },  
    { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },  
};

Vertex Structure/Buffer, Indice List

我们需要对顶点结构也进行修改,因为我们之前定义了八个顶点,这其中可能会有一个顶点分享多个贴图坐标,为了避免这种情况出现,我们需要给每个面都单独设立顶点。

        Vertex v[] =
        {
            // Front Face
            Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 1.0f),
            Vertex(-1.0f,  1.0f, -1.0f, 0.0f, 0.0f),
            Vertex( 1.0f,  1.0f, -1.0f, 1.0f, 0.0f),
            Vertex( 1.0f, -1.0f, -1.0f, 1.0f, 1.0f),
    
            // Back Face
            Vertex(-1.0f, -1.0f, 1.0f, 1.0f, 1.0f),
            Vertex( 1.0f, -1.0f, 1.0f, 0.0f, 1.0f),
            Vertex( 1.0f,  1.0f, 1.0f, 0.0f, 0.0f),
            Vertex(-1.0f,  1.0f, 1.0f, 1.0f, 0.0f),
    
            // Top Face
            Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 1.0f),
            Vertex(-1.0f, 1.0f,  1.0f, 0.0f, 0.0f),
            Vertex( 1.0f, 1.0f,  1.0f, 1.0f, 0.0f),
            Vertex( 1.0f, 1.0f, -1.0f, 1.0f, 1.0f),
    
            // Bottom Face
            Vertex(-1.0f, -1.0f, -1.0f, 1.0f, 1.0f),
            Vertex( 1.0f, -1.0f, -1.0f, 0.0f, 1.0f),
            Vertex( 1.0f, -1.0f,  1.0f, 0.0f, 0.0f),
            Vertex(-1.0f, -1.0f,  1.0f, 1.0f, 0.0f),
    
            // Left Face
            Vertex(-1.0f, -1.0f,  1.0f, 0.0f, 1.0f),
            Vertex(-1.0f,  1.0f,  1.0f, 0.0f, 0.0f),
            Vertex(-1.0f,  1.0f, -1.0f, 1.0f, 0.0f),
            Vertex(-1.0f, -1.0f, -1.0f, 1.0f, 1.0f),
    
            // Right Face
            Vertex( 1.0f, -1.0f, -1.0f, 0.0f, 1.0f),
            Vertex( 1.0f,  1.0f, -1.0f, 0.0f, 0.0f),
            Vertex( 1.0f,  1.0f,  1.0f, 1.0f, 0.0f),
            Vertex( 1.0f, -1.0f,  1.0f, 1.0f, 1.0f),
        };
    
        DWORD indices[] = {
            // Front Face
            0,  1,  2,
            0,  2,  3,
    
            // Back Face
            4,  5,  6,
            4,  6,  7,
    
            // Top Face
            8,  9, 10,
            8, 10, 11,
    
            // Bottom Face
            12, 13, 14,
            12, 14, 15,
    
            // Left Face
            16, 17, 18,
            16, 18, 19,
    
            // Right Face
            20, 21, 22,
            20, 22, 23
        };
    
        D3D11_BUFFER_DESC indexBufferDesc;
        ZeroMemory( &indexBufferDesc, sizeof(indexBufferDesc) );
    
        indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
        indexBufferDesc.ByteWidth = sizeof(DWORD) * 12 * 3;
        indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
        indexBufferDesc.CPUAccessFlags = 0;
        indexBufferDesc.MiscFlags = 0;
    
        D3D11_SUBRESOURCE_DATA iinitData;
    
        iinitData.pSysMem = indices;
        d3d11Device->CreateBuffer(&indexBufferDesc, &iinitData, &squareIndexBuffer);
    
        d3d11DevCon->IASetIndexBuffer( squareIndexBuffer, DXGI_FORMAT_R32_UINT, 0);
    
    
        D3D11_BUFFER_DESC vertexBufferDesc;
        ZeroMemory( &vertexBufferDesc, sizeof(vertexBufferDesc) );
    
        vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
        vertexBufferDesc.ByteWidth = sizeof( Vertex ) * 24;
        vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
        vertexBufferDesc.CPUAccessFlags = 0;
        vertexBufferDesc.MiscFlags = 0;

Loading the Texture from a File 

函数原型如下

HRESULT D3DX11CreateShaderResourceViewFromFile(
  __in   ID3D11Device *pDevice,
  __in   LPCTSTR pSrcFile,
  __in   D3DX11_IMAGE_LOAD_INFO *pLoadInfo,
  __in   ID3DX11ThreadPump *pPump,
  __out  ID3D11ShaderResourceView **ppShaderResourceView,
  __out  HRESULT *pHResult
);

pDevice - 指向设备的指针

pSrcFile - 文件名字

pLoadInfo - 指向D3DX11_IMAGE_LOAD_INFO 结构体的指针,这个结构体定义了贴图是如何被导入的。我们这里设为NULL

pPump - 指向ID3DX11ThreadPump 的指针,只有使用多线程的时候才考虑,可以一边让图片加载,一边让程序运行

ppShaderResourceView  - 保存图像数据对象的指针

pHResult - 函数返回结果

hr = D3DX11CreateShaderResourceViewFromFile( d3d11Device, L"braynzar.jpg",
    NULL, NULL, &CubesTexture, NULL );

Describing the Sample State

导入贴图之后,shader会如何渲染呢,我们需要定义一个采样状态。首先定义采样状态的描述信息。

typedef struct D3D11_SAMPLER_DESC {
  D3D11_FILTER               Filter;
  D3D11_TEXTURE_ADDRESS_MODE AddressU;
  D3D11_TEXTURE_ADDRESS_MODE AddressV;
  D3D11_TEXTURE_ADDRESS_MODE AddressW;
  FLOAT                      MipLODBias;
  UINT                       MaxAnisotropy;
  D3D11_COMPARISON_FUNC      ComparisonFunc;
  FLOAT                      BorderColor[4];
  FLOAT                      MinLOD;
  FLOAT                      MaxLOD;
} D3D11_SAMPLER_DESC;

Filter - 指定过滤方法

AddressU - 这是一个D3D11_TEXTURE_ADDRESS_MODE 枚举值,指定当U大于1或者小于0时的结果

AddressV - 同上

AddressW - 同上

MipLODBias - 从计算出的mipmap(这个概念不明白的可以google看看,很好理解)中的偏移。eg:当计算机算出贴图应该在mipmap的level3中采样,但是偏移为2,所以最终会在mipmap的Level 5中进行采样

MaxAnisotropy - 如果第一个参数指定了D3D11_FILTER_ANISOTROPIC or D3D11_FILTER_COMPARISON_ANISOTROPIC,那么会用一个夹紧值,有效数字为1-16

ComparisonFunc - 一个D3D11_COMPARISON_FUNC 枚举值,会比较mipmap数据和另一个mipmap采样数据

BorderColor[4] - 如果2 3 4中有一个指定了D3D11_TEXTURE_ADDRESS_BORDER ,那么这个颜色就会填充贴图和物体的边界区域。(只有u/v/w大于1时)

MaxLOD - 最大的mipmap等级,0是最大最清晰的,如果想要用所有的mipmap level,那么可以指定FLT_MAX

函数的参数默认值如下

Filter            MIN_MAG_MIP_LINEAR
AddressU        Clamp
AddressV        Clamp
AddressW        Clamp
MinLOD            -3.402823466e+38F (-FLT_MAX)
MaxLOD            3.402823466e+38F (FLT_MAX)
MipMapLODBias    0.0f
MaxAnisotropy    16
ComparisonFunc    Never
BorderColor        float4(0.0f,0.0f,0.0f,0.0f)

我们调用如下

D3D11_SAMPLER_DESC sampDesc;
ZeroMemory( &sampDesc, sizeof(sampDesc) );
sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
sampDesc.MinLOD = 0;
sampDesc.MaxLOD = D3D11_FLOAT32_MAX;

创建好了采样状态的描述信息之后,我们就要设置采样状态了。

hr = d3d11Device->CreateSamplerState( &sampDesc, &CubesTexSamplerState );

Sending the Sampler State and Texture to the Shader

我们可以对于一部分使用相同采样状态和相同贴图的物体集中调用函数,但是通常情况下,我们的一个物体都会有不同的贴图和采样状态,所以在实际使用中,我们需要对它调用多次

设置采样状态和贴图的函数分别为

ID3D11DeviceContext::PSSetSamplers().

ID3D11DeviceContext::PSSetShaderResources() 第一个参数是要发送的shader槽,第二个是要发送的贴图个数,第三个是保存了贴图数据的数组。

void DrawScene()
{
    //Clear our backbuffer
    float bgColor[4] = {(0.0f, 0.0f, 0.0f, 0.0f)};
    d3d11DevCon->ClearRenderTargetView(renderTargetView, bgColor);

    //Refresh the Depth/Stencil view
    d3d11DevCon->ClearDepthStencilView(depthStencilView, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 1.0f, 0);

    //Set the WVP matrix and send it to the constant buffer in effect file
    WVP = cube1World * camView * camProjection;
    cbPerObj.WVP = XMMatrixTranspose(WVP);    
    d3d11DevCon->UpdateSubresource( cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0 );
    d3d11DevCon->VSSetConstantBuffers( 0, 1, &cbPerObjectBuffer );
    ///**************new**************
    d3d11DevCon->PSSetShaderResources( 0, 1, &CubesTexture );
    d3d11DevCon->PSSetSamplers( 0, 1, &CubesTexSamplerState );
    ///**************new**************

    //Draw the first cube
    d3d11DevCon->DrawIndexed( 36, 0, 0 );

    WVP = cube2World * camView * camProjection;
    cbPerObj.WVP = XMMatrixTranspose(WVP);    
    d3d11DevCon->UpdateSubresource( cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0 );
    d3d11DevCon->VSSetConstantBuffers( 0, 1, &cbPerObjectBuffer );
    ///**************new**************
    d3d11DevCon->PSSetShaderResources( 0, 1, &CubesTexture );
    d3d11DevCon->PSSetSamplers( 0, 1, &CubesTexSamplerState );
    ///**************new**************

    //Draw the second cube
    d3d11DevCon->DrawIndexed( 36, 0, 0 );

    //Present the backbuffer to the screen
    SwapChain->Present(0, 0);
}

通过以上的步骤,我们的贴图就设置好了,其实非常的简单,但是其中一些描述结构的参数的具体效果还需要我们一个一个摸索。

本节内容就到这里拉。

本节内容代码可以在我的Github找到

游戏开发路途遥远,但我相信只要坚持,总能到达彼岸!

如果我的文章对于你学习DirectX11有点帮助,欢迎评论给出建议,让我们一起学习进步!

                                                                                               ———————— 小明 2018.12.3 18.09

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值