VC++游戏开发随记之三十.docx
《VC++游戏开发随记之三十.docx》由会员分享,可在线阅读,更多相关《VC++游戏开发随记之三十.docx(58页珍藏版)》请在冰豆网上搜索。
VC++游戏开发随记之三十
【VisualC++】游戏开发笔记三十DirectX112D纹理映射知识全攻略
本节知识先是对DirectX11关于2D纹理映射方面基础知识的一个讲解,然后通过一个demo的创建过程来将学到的理论知识付诸实践。
一、引言
在之前我们提到过,纹理实际上就是映射到物体表面的数据。
其实,纹理也可能是其他的一些信息片段,比如用于映射的常规映射值,用于控制透明度的alpha值,等等。
通常情况下,纹理是通过一个叫做纹理映射的过程来映射一幅图像到表面上的颜色值,这种功能能显著地增加所绘制场景的细腻感和真实感。
纹理和游戏开发中需要的其他数据一样,通常都是在运行时加载的。
由于纹理是Direct3D重要的组成的部分,微软为我们提供了众多功能强大而丰富的Direct3D内建的函数,来处理纹理相关的操作。
二、基础知识讲解
1.纹理的加载
在Direct3D11中,我们通常使用D3DX11CreateTextureFromFile函数用于从硬盘文件中加载纹理。
这个函数支持非常丰富的图像格式,比如BMP,PNG,以及DDS。
D3DX11CreateTextureFromFile函数拥有六个变量,具有以下的函数原型:
[cpp] viewplaincopyprint?
1.HRESULT D3DX11CreateTextureFromFile(
2.
3.ID3D11Device* pDevice,
4.
5.LPCTSTR pSrcFile,
6.
7.D3DX11_IMAGE_LOAD_INFO* pLoadInfo,
8.
9.ID3DX11ThreadPump* pPump,
10.
11.ID3D11Resource** ppTexture,
12.
13.HRESULT* pHResult
14.
15.);
D3DX11CreateTextureFromFile函数的第一个的参数为ID3D11Device类型的指针变量。
第二个参数pSrcFile为被加载文件的文件路径和文件名。
第三个参数pLoadInfo为一个图形信息结构体。
它为一个可选的参数,并允许我们通过指定CPU访问的标识、内部格式、宽度和高度来控制图像纹理的加载方式。
第四个参数pPump用于多线程加载纹理时的异步处理。
第五个参数ppTexture用是纹理对象被调用时这个函数创建出的地址。
如果D3DX11CreateTextureFromFile函数调用成功,这个变量就会拥有一个现成的纹理供使用。
最后一个参数pHResult是指向线程返回值的指针。
若此线程的参数不为空,pHResult必须为一个有效的内存地址。
在Direct3D中我们能够使用很多函数载入各种琳琅满目的图
像文件格式,下面我们对他们进行一个详细的列举:
WindowsBitmap(BMP)
JointPhotographicExpertGroup—i.e.,JPEG(JPG)
PortableNetworkGraphics(PNG)
TaggedImageFormat(TIFF)
GraphicsInterchangeFormat(GIF)
DirectDrawSurface(DDS)
WindowsMediaPlayer(WMP)
2.纹理接口
纹理接口通常用于管理一个特定类型的图像数据。
目前Direct3D纹理接口主要有三种类型,他们分别是:
ID3D11Texture1D——用于1D或者条形的纹理
ID3D11Texture2D——用于2D数据,这也是最常用的纹理资源类型、
ID3D11Texture3D——用于表示3D数据的纹理资源类型
上述3种纹理资源类型都包含一个或者多个子资源。
而游戏开发中使用的大多数纹理类型基本上都为二维的,他们都需要转化为ID3D11Texture2D型资源后再使用。
而这些子资源代表了纹理中不同的 MIP等级。
譬如Adobe’sPhotoshop这类的图像编辑器是创造2D纹理的最得力帮手。
3.纹理细节
在游戏开发的过程中,常常我们需要从加载的纹理中得到一些特定的信息,比如说维度或者像素格式。
这时候隶属于ID3D11Texture2D中的GetDesc函数就可以派上用场了。
这个函数的功能是为我们填充D3D11_TEXTURE2D_DESC结构体中的各种细节,从而通过这个结构体作为载体,有关的各类数据就一目了然了。
D3D11_TEXTURE2D_DESC是专用于2D纹理的纹理描述结构体家族中的一员。
对于其他的两个维度,Direct3D11为我们准备了D3D11_TEXTURE1D_DESC用于1D纹理,D3D11_TEXTURE3D_DESC用于3D纹理。
作为最常见的纹理,二维的D3D11_TEXTURE2D_DESC声明形式如下:
[cpp] viewplaincopyprint?
1.typedef struct D3D11_TEXTURE2D_DESC {
2.
3.UINT Width;
4.
5.UINT Height;
6.
7.UINT MipLevels;
8.
9.UINT ArraySize;
10.
11.DXGI_FORMAT Format;
12.
13.DXGI_SAMPLE_DESC SampleDesc;
14.
15.D3D11_USAGE Usage;
16.
17.UINT BindFlags;
18.
19.UINT CPUAccessFlags;
20.
21.UINT MiscFlags;
22.
23.} D3D11_TEXTURE2D_DESC;
三、DirectX112D纹理映射demo的创建
这里,我们先介绍一下这个demo的组成结构:
如图,头文件有Dx11DemoBase.h以及Texture2DDemo.h
源文件有Dx11DemoBase.cpp,Texture2DDemo.h以及main.cpp
在之前的TriangleDemo的基础上,我们再添加一个叫做TextureDemo的类,以及添加一个叫做colorMap_的D3D11ShaderResourceView类型的着色器资源视图和一个D3D11SamplerState类型的唤做colorMapSampler_的采样状态。
着色资源视图简单的来说是一个用于访问资源的对象。
当我们加载纹理到内存中的时候,必须创建一个着色器资源视图来通过着色器获取数据,而这些数据会被绑定到输出程序集当中。
着色器资源视图也有其他的作用,比如为DirectCompute提供异步运算时需要的数据,本节我们主要是介绍其在纹理方面的运用。
ID3D11Texture2D代表数据的缓存,而着色器资源视图允许我们在着色器中查看这个缓存的各项数据。
采样器声明(samplerstate)允许我们访问的纹理采样的状态信息。
后面将对其做更多更详细的讲解。
TextureDemo类的头文件代码书写风格如下:
代码段一 TextureDemo.h对TextureDemo类的轮廓书写
[cpp] viewplaincopyprint?
1.#ifndef _TEXTURE_2D_DEMO_H_
2.#define _TEXTURE_2D_DEMO_H_
3.
4.#include"Dx11DemoBase.h"
5.
6.
7.class TextureDemo :
public Dx11DemoBase
8.{
9. public:
10. TextureDemo( );
11. virtual ~TextureDemo( );
12.
13. bool LoadContent( );
14. void UnloadContent( );
15.
16. void Update( float dt );
17. void Render( );
18.
19. private:
20. ID3D11VertexShader* solidColorVS_;
21. ID3D11PixelShader* solidColorPS_;
22.
23. ID3D11InputLayout* inputLayout_;
24. ID3D11Buffer* vertexBuffer_;
25.
26. ID3D11ShaderResourceView* colorMap_;
27. ID3D11SamplerState* colorMapSampler_;
28.};
29.
30.#endif
由于我们正在执行纹理映射这项操作,我们需要对顶点结构体的代码进行更新,使其包含两个浮点型的变量。
这项工作可由XMFLOAT2结构体来完成。
代码段二中展示了这个demo中顶点结构体,LoadContent,函数和UnloadContent函数的写法
代码段二 顶点结构体以及LoadContent和UnloadContent的书写
[cpp] viewplaincopyprint?
1.struct VertexPos
2.
3.{
4.
5.XMFLOAT3 pos;
6.
7.XMFLOAT2 tex0;
8.
9.};
10.
11.bool TextureDemo:
:
LoadContent( )
12.
13.{
14.
15.... Load vertex Shader ...
16.
17.D3D11_INPUT_ELEMENT_DESC solidColorLayout[] =
18.
19.{
20.
21.{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT,
22.
23.0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
24.
25.{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,
26.
27.0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }
28.
29.};
30.
31.unsigned int totalLayoutElements = ARRAYSIZE( solidColorLayout );
32.
33.d3dResult = d3dDevice_->CreateInputLayout( solidColorLayout,
34.
35.totalLayoutElements, vsBuffer->GetBufferPointer( ),
36.
37.vsBuffer->GetBufferSize( ), &inputLayout_ );
38.
39.... Load Pixel Shader ...
40.
41.VertexPos vertices[] =
42.
43.{
44.
45.{ XMFLOAT3( 1.0f, 1.0f, 1.0f ), XMFLOAT2( 1.0f, 1.0f ) },
46.
47.{ XMFLOAT3( 1.0f, -1.0f, 1.0f ), XMFLOAT2( 1.0f, 0.0f ) },
48.
49.{ XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT2( 0.0f, 0.0f ) },
50.
51.{ XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT2( 0.0f, 0.0f ) },
52.
53.{ XMFLOAT3( -1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 1.0f ) },
54.
55.{ XMFLOAT3( 1.0f, 1.0f, 1.0f ), XMFLOAT2( 1.0f, 1.0f ) },
56.
57.};
58.
59.... Create Vertex Buffer ...
60.
61.d3dResult = D3DX11CreateShaderResourceViewFromFile( d3dDevice_,
62.
63."decal.dds", 0, 0, &colorMap_, 0 );
64.
65.if( FAILED( d3dResult ) )
66.
67.{
68.
69.DXTRACE_MSG( "Failed to load the texture image!
" );
70.
71.return false;
72.
73.}
74.
75.D3D11_SAMPLER_DESC colorMapDesc;
76.
77.ZeroMemory( &colorMapDesc, sizeof( colorMapDesc ) );
78.
79.colorMapDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
80.
81.colorMapDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
82.
83.colorMapDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
84.
85.colorMapDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
86.
87.colorMapDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
88.
89.colorMapDesc.MaxLOD = D3D11_FLOAT32_MAX;
90.
91.d3dResult = d3dDevice_->CreateSamplerState( &colorMapDesc,
92.
93.&colorMapSampler_ );
94.
95.if( FAILED( d3dResult ) )
96.
97.{
98.
99.DXTRACE_MSG( "Failed to create color map sampler state!
" );
100.
101.return false;
102.
103.}
104.
105.return true;
106.
107.}
108.
109.void TextureDemo:
:
UnloadContent( )
110.
111.{
112.
113.if( colorMapSampler_ ) colorMapSampler_->Release( );
114.
115.if( colorMap_ ) colorMap_->Release( );
116.
117.if( solidColorVS_ ) solidColorVS_->Release( );
118.
119.if( solidColorPS_ ) solidColorPS_->Release( );
120.
121.if( inputLayout_ ) inputLayout_->Release( );
122.
123.if( vertexBuffer_ ) vertexBuffer_->Release( );
124.
125.colorMapSampler_ = 0;
126.
127.colorMap_ = 0;
128.
129.solidColorVS_ = 0;
130.
131.solidColorPS_ = 0;
132.
133.inputLayout_ = 0;
134.
135.vertexBuffer_ = 0;
136.
137.}
UnloadContent函数释放了新对象,而LoadContent函数进行了纹理图像的加载。
我们可以使用Direct3D中的D3DX11CreateShaderResourceViewFromFile函数(这个函数名是不是略长啊,哈哈),来加载一个纹理然后在一个简单的调用之中创建着色器资源视图。
这个函数在我们想毕其功于一役的时候,即希望加载一个纹理连着创建一个新的着色器资源视图一步到位的时候,非常的好用。
D3DX11CreateShaderResourceViewFromFile函数的变量和D3DX11CreateTextureFromFile函数的相似度很高,这员大将有以下原型:
[cpp] viewplaincopyprint?
1.HRESULT D3DX11CreateShaderResourceViewFromFile(
2.
3.ID3D11Device* pDevice,
4.
5.LPCTSTR pSrcFile,
6.
7.D3DX11_IMAGE_LOAD_INFO* pLoadInfo,
8.
9.ID3DX11ThreadPump* pPump,
10.
11.ID3D11ShaderResourceView** ppShaderResourceView,
12.
13.HRESULT* pHResult
14.
15.);
LoadContent函数代码的最后一段完成的功能是采样器声明(samplerstate)的创建。
为了创建一个采样器声明(samplerstate)的对象,很容易就可以通过功能联想到函数名——CreateSamplerState。
这个函数以采样器描述作为其一个参数。
而采样器描述拥有以下的声明:
[cpp] viewplaincopyprint?
1.typedef struct D3D11_SAMPLER_DESC {
2.
3.D3D11_FILTER Filter;
4.
5.D3D11_TEXTURE_ADDRESS_MODE AddressU;
6.
7.D3D11_TEXTURE_ADDRESS_MODE AddressV;
8.
9.D3D11_TEXTURE_ADDRESS_MODE AddressW;
10.
11.FLOAT MipLODBias;
12.
13.UINT MaxAnisotropy;
14.
15.D3D11_COMPARISON_FUNC ComparisonFunc;
16.
17.FLOAT BorderColor[4];
18.
19.FLOAT MinLOD;
20.
21.FLOAT MaxLOD;
22.
23.} D3D11_SAMPLER_DESC;
为了渲染我们的几何纹理,我们必须添加纹理资源以及设置采样器描述。
这两项特殊的任务分别分配给PSSetShaderResources函数以及PSSetSamplers函数来完成,设置这些数据到像素着色器之中。
PSSetShaderResources函数具有以下原型:
[cpp] viewplaincopyprint?
1.void PSSetShaderResources(
2.
3.UINT StartSlot,
4.
5.UINT NumViews,
6.
7.ID3D11ShaderResourceView* const* ppShaderResourceViews
8.
9.
10.
11.);
PSSetSamplers函数也以起始点StartSlot以及采样数量NumViews作为其参数。
我们在之前demo里面关于Render的代码随着这节里面对这两个函数的加入,我们就可以看到更加出色的效果了。
目前需要做的就是就修改着色器的渲染效果了。
TextureMappingdemo类的Render函数如下代码段X
代码段三 TextureDemo 类的render函数的书写
[cpp] viewplaincopyprint?
1.void TextureDemo:
:
Render( )
2.
3.{
4.
5.if( d3dContext_ == 0 )
6.
7.return;
8.
9.float clearColor[4] = { 0.0f, 0.0f, 0.25f, 1.0f };
10.
11.d3dContext_->ClearRenderTargetView( backBufferTarget_, clearColor );
12.
13.unsigned int stride = sizeof( VertexPos );
14.
15.unsigned int offset = 0;
16.
17.d3dContext_->IASetInputLayout( inputLayout_ );
18.
19.d3dContext_->IASetVertexBuf