首页 > 技术文章 > DirectX11笔记5:纹理,从文件加载模型

Windogs 2015-11-26 13:51 原文

纹理部分:

1.创建纹理。

由于原来的D3DX系列的函数没法用了,许多资料上使用的D3DX11CreateShaderResourceViewFromFile就不行了,我使用了另一种方式。

开源代码:https://github.com/Microsoft/DirectXTex

相关博客:http://blogs.msdn.com/b/chuckw/archive/2012/03/02/directxtk.aspx

一些其它资料:https://github.com/Microsoft/DirectXTK

将DirectXTex中DDSTextureLoader的代码载入到我们的工程中,使用CreateDDSTextureFromFile加载纹理图像。

这里有个麻烦的地方,就是CreateDDSTextureFromFile只能加载DDS文件,不能使用其它格式。。。。。按照博客给的表格,应该是有方法加载其它格式的文件的吧。。。。。。

所以,我还要安装一个PS以及相关的DDS插件去编辑DDS文件。

    HRESULT CreateDDSTextureFromFile( _In_ ID3D11Device* d3dDevice,
                                      _In_z_ const wchar_t* szFileName,
                                      _Outptr_opt_ ID3D11Resource** texture,
                                      _Outptr_opt_ ID3D11ShaderResourceView** textureView,
                                      _In_ size_t maxsize = 0,
                                      _Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr
                                    );

 

使用:

//加载纹理资料
    hr = DirectX::CreateDDSTextureFromFile(dev, L"seafloor.dds", nullptr, &pTextureRV);

 

然后需要为纹理声明一个采样器对象:

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 = dev->CreateSamplerState(&sampDesc, &pSamplerLinear);
    if (FAILED(hr))
        return hr;

 

具体去看msdn吧,不多解释了。

当然,VS的输入部分与顶点的定义也要改一下,关于顶点对应的纹理坐标看书中的8.2节,请看我上传的代码食用。。。。。。。。。。如果有人看的话。

最后在渲染的循环中,需要设置采样器对象,与纹理资源:

    devContext->PSSetShaderResources(0, 1, &pTextureRV);
    devContext->PSSetSamplers(0, 1, &pSamplerLinear);

 

这样,C++代码部分暂时结束了。

 

然后是HLSL部分。

纹理采样:要解释纹理采样,就需要先理解过滤器。当我们的纹理映射到3D的图形上,大小不可能完全匹配的,而且,3D图形会进行放大与缩小。处理这种会使纹理出现变形的情况,我们可以指定过滤方式。具体在书中8.5节第一部分。

好了,现在经过了处理,每个像素对应了一个纹理坐标,就是说纹理坐标与我们的像素坐标一一对应了,使用纹理采样从纹理中提取颜色,并显示:

Texture2D txDiffuse;//定义纹理
SamplerState samLinear;//采样,过滤方式

struct PS_INPUT
{
    float4 Pos : SV_POSITION;
    float2 Tex : TEXCOORD0;
};
float4 PS(PS_INPUT input) : SV_Target
{
    return txDiffuse.Sample(samLinear, input.Tex);
}

 

纹理的寻址方式:

在纹理坐标中为了标准化坐标,所有的纹理坐标都在(0,1)内,那么当在0与1之外应该怎么处理?这个可由SamplerState决定,具体看书中8.8节。

整合纹理作为材质:

也就是把纹理放入光照或者其它的模型中去,书中代码:

// Modulate with late add.
litColor = texColor*(ambient + diffuse) + spec;
相关工程下载:

工程文件

 

 

 

///按照书中的流程,接下来应该学习混合与模板

但是看了下面几节的内容,发现都是需要复杂的模型才会有比较好的效果

所以,回头去看了如何从文件中导入模型的代码,很简单。

这里的模型是从书中提供的头骨与汽车,至于如何从3D建模软件导出的模型文件载入模型,需要我们自己去对那些文件的结构进行分析(我看原来有D3DX系列的方法去直接导入已有的模型,但是这里无法直接使用D3DX系列函数,都需要我们自己手动分析)

导入的代码:

//LoadTheModel
    std::ifstream fin("skull.txt");

    if (!fin)
    {
        printf("Models not found.\n");
        return hr;
    }

    UINT vcount = 0;        //vertex count
    UINT tcount = 0;        //index count
    std::string ignore;

    fin >> ignore >> vcount;
    fin >> ignore >> tcount;
    fin >> ignore >> ignore >> ignore >> ignore;

//    float nx, ny, nz;
    DirectX::XMFLOAT4 black(0.6f, 0.6f, 0.6f, 0.8f);
    std::vector<Vertex> vertices(vcount);
    for (UINT i = 0; i < vcount; ++i)
    {
        fin >> vertices[i].Pos.x >> vertices[i].Pos.y >> vertices[i].Pos.z;

        fin >> vertices[i].Normal.x >> vertices[i].Normal.y >> vertices[i].Normal.z;
    }
    fin >> ignore;
    fin >> ignore;
    fin >> ignore;

    mSkullIndexCount = 3 * tcount;//三角形,3*顶点数
    std::vector<UINT> indices(mSkullIndexCount);
    for (UINT i = 0; i < tcount; ++i)
    {
        fin >> indices[i * 3 + 0] >> indices[i * 3 + 1] >> indices[i * 3 + 2];
    }
    fin.close();//记得close
    /////
    //

 

具体输入方式看一下C++的文件操作(文件流)

 相关文件下载:

工程文件

 

推荐阅读