指南五:使用纹理映射
尽管光照和材质大大增加了场景的真实感,但没有比在表面上添加纹理更能增加真实感的了。纹理能够被想象为一层紧紧包装在表面的贴纸。你能在一个立方体上放置一层木质纹理使它看起来就象用木头制成的一样。本 Texture 例程将在 指南四:创建和使用光照 中构造的圆柱上添加一幅类似香蕉的纹理。此指南介绍的内容包括如何载入纹理,设置纹理,与呈递带有纹理的物体。
本指南采用以下步骤实现纹理:
·第一步:定义一个定制顶点格式
·第二步:初始化屏幕几何
·第三步:演示场景
注意:Texture 示例程序的路径为:
(SDK root)\Samples\Multimedia\Direct3D\Tutorials\Tut05_Textures.
注意:除了 Texture 示例不创建材质和光照以外,Texture 工程中的示例代码与 Lights 工程的几乎完全一样。本“使用纹理映射”指南仅仅关注于有关于纹理的独特代码,而并不重复有关初始化 Microsoft Direct3D,处理 Microsoft Windows 消息,演示,或清理的内容。关于这些工作的信息,见:指南一:创建设备。
本指南使用自定义顶点和顶点缓冲区显示几何物体。关于选择一个自定义顶点格式并执行顶点缓冲的更多信息,见:指南二:演示顶点。
本指南采用矩阵进行几何变换。关于矩阵和变换的更多信息,参见:指南三:使用矩阵。
第一步:定义一个定制顶点格式
在使用纹理以前,必须使用包含纹理坐标的自定义顶点格式。纹理坐标告诉 Microsoft Direct3D 在物件上如何将纹理定位于每个顶点上。纹理坐标范围从 0.0 到 1.0,(0.0, 0.0) 的位置代表纹理贴图的左上角而 (1.0, 1.0) 代表纹理贴图的右下角。
以下示例代码说明了 Texture 例程是如何通过设置它的自定义顶点格式来包含纹理坐标的。
struct CUSTOMVERTEX
{
D3DXVECTOR3 position; // The position.
D3DCOLOR color; // The color.
FLOAT tu, tv; // The texture coordinates.
};
// The custom FVF, which describes the custom vertex structure.
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
关于纹理坐标的进一步信息,参见 SDK: Texture Coordinates 一章。
现在自定义顶点格式已经准备好了,下一步将是载入一幅纹理并创建一个圆柱体,见 第二步:初始化屏幕几何。
第二步:初始化屏幕几何
在绘制之前,Texture 例程调用 InitGeometry,一个程序自定义的函数用于创建一幅纹理并初始化圆柱体的几何参数。
纹理是由基于文件的图像构造的。以下示例代码使用 D3DXCreateTextureFromFile 从 Banana.bmp 文件创建一幅纹理并用它覆盖圆柱的表面。
if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice, "Banana.bmp",
&g_pTexture ) ) )
return E_FAIL;
D3DXCreateTextureFromFile 接受的第一个参数是一个指向 Microsoft Direct3D 设备的指针,这个设备将用于绘制纹理。第二个参数是一个指向 ANSI 字符串的指针,它指定用于创建纹理的文件名。本例程指定从此文件:“Banana.bmp” 来装载图像。第三个参数是一个指向纹理对象指针的地址。
当这个类似香蕉的纹理被装载并准备好之后,下一个步骤是创建圆柱体。以下示例代码用一个圆柱体填充顶点缓冲区。注意每一点都具备了纹理坐标 (tu, tv)。
for( DWORD i=0; i<50; i++ )
{
FLOAT theta = (2*D3DX_PI*i)/(50-1);
pVertices[2*i+0].position = D3DXVECTOR3( sinf(theta),-1.0, cosf(theta) );
pVertices[2*i+0].color = 0xffffffff;
pVertices[2*i+0].tu = ((FLOAT)i)/(50-1);
pVertices[2*i+0].tv = 1.0f;
pVertices[2*i+1].position = D3DXVECTOR3( sinf(theta), 1.0, cosf(theta) );
pVertices[2*i+1].color = 0xff808080;
pVertices[2*i+1].tu = ((FLOAT)i)/(50-1);
pVertices[2*i+1].tv = 0.0f;
}
每一个顶点包括位置,颜色,以及纹理坐标。上面的例程给每一点设置了纹理坐标并使此纹理能够平滑的包裹在圆柱体周围。
现在纹理和顶点缓冲区已经准备好用于演示了,现在能够呈递和着色图形了,参见 第三步:演示场景。
第三步:演示场景
在场景几何被初始化之后,应该是绘制场景的时候了。为了绘制一个带有纹理的物体,使用的纹理必须要设置成当前纹理中的一个。下一步将是设置纹存储器的状态。纹理存储器状态使你能够定义一个或者多个纹理被呈递的方式。比如说,你能将多个纹理混合在一起。
现在 Texture 示例开始设置需要使用的纹理。以下代码段使用 IDirect3DDevice8::SetTexture 设置 Microsoft Direct3D 设备用于绘制的纹理。
g_pd3dDevice->SetTexture( 0, g_pTexture );
SetTexture 接受的第一个参数是设置纹理存储器的标示符。一个设备能够支持八个已初始化的纹理,所以这儿的最大值是 7。本 Texture 示例仅仅使用一个纹理并且把它设置在存储器 0。第二个参数是一个指向纹理对象的指针。在这儿,Texture 示例使用由它的程序自定义函数 InitGeometry 创建的纹理。
以下代码片设置纹理存储器状态的值,通过调用 IDirect3DDevice8::SetTextureStageState 方法。
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
SetTextureState 的第一个参数是需要改变状态的存储器的索引。本示例代码改变位于存储器 0 的纹理,所以这儿置为 0。下一个参数是要设置的纹理状态。关于所有有效的纹理状态以及它们的意义,见 "SDK: D3DTEXTURESTAGESTATETYPE"。再下一个参数是设置为此纹理状态的参数。你放置这儿的值应取决于你要改变的纹理存储器状态。
在设置完每个纹理存储器状态的合适值之后,这个圆柱体可以被呈递了,现在纹理将被添加在它的表面上。
使用纹理坐标的其他方法是使它们自动的生成。这是用一种纹理坐标索引 (TCI) 实现的。TCI 使用一个纹理矩阵来变换 (x,y,z) TCI 坐标为 (tu, tv) 纹理坐标。在 Texture 例程中,位于摄像机空间中的顶点位置被用来产生纹理坐标。
第一步是创建用于转换的矩阵,示范在以下代码片段中:
D3DXMATRIX mat;
mat._11 = 0.25f; mat._12 = 0.00f; mat._13 = 0.00f; mat._14 = 0.00f;
mat._21 = 0.00f; mat._22 =-0.25f; mat._23 = 0.00f; mat._24 = 0.00f;
mat._31 = 0.00f; mat._32 = 0.00f; mat._33 = 1.00f; mat._34 = 0.00f;
mat._41 = 0.50f; mat._42 = 0.50f; mat._43 = 0.00f; mat._44 = 1.00f;
在矩阵创建好之后,它必须通过调用 IDirect3DDevice8::SetTransform 来设置它,如以下代码段所示:
g_pd3dDevice->SetTransform( D3DTS_TEXTURE0, &mat );
D3DTS_TEXTURE0 标志告诉 Direct3D 应用此变换到位于纹理存储器 0 的纹理。本示例的下一步是设置其他的存储器状态值,以得到所需的效果。这些处理在以下代码段中。
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2 );
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION );
纹理坐标被设置后,现在此场景已准备好被呈递了。注意到现在的坐标是自动设置到圆柱上的。这样精确的设置使几何物体被演示时纹理好象是覆盖在绘制的屏幕上。
关于纹理的更多信息,见 SDK: Texture 一章。
本指南已经向你说明了如何给表面添加纹理。指南六:使用Mesh模型 将告诉你如何应用Mesh模型呈递复杂的几何形体。
(指南六:使用Mesh模型 见本文第七部分)