基本概念
纹理是增强计算机生成的三维图像的真实感的有力工具,早期计算机生成的三维图像看起来往往像是发亮的塑料,虽然这在当时也是比较先进的,但是它们缺乏各种纹路——如磨损、裂痕、指纹和污渍等,而这些纹路会增加三维物体的真实感。在计算机图形学中,纹理指的是一张表示物体表面细节的位图。
因为Direct3D中所有纹理都是位图,所以可以把任何位图贴到Direct3D图元的表面。例如,应用程序可以创建物体并使它们的表面看起来有木纹的样式。可以把草、泥土和岩石等纹理贴在构成山的图元的表面,这样就能得到看起来很真实的山坡。应用程序也可以用纹理创建其它的效果,如:路边的路标,悬崖边的岩层,或是地面上的大理石。
再举个例子:假如想在场景中放置一座砖墙,我们可能会在摄像机前创建一个正方形然后把它涂成红色。但是它看起来只是一个红色的正方形而不像一座砖墙,有许多砖块甚至还带有一个窗子的那种。这时,纹理就有了用武之地。所需的只是一个对象(正方形)和一个墙的纹理。
纹理的尺寸
理论上可以创建任何尺寸的纹理,但是为了提高效率,纹理最好是正方形(长和宽一样)的而且它的边长最好是2的n次幂的形式,例如
16×16、32×32、64×64,、128×128、256×256。
纹理坐标
大多数纹理,如位图,都是一个存放颜色值的二维数组。数组中的每个颜色值被称为texel。每个texel在纹理中有唯一的地址,可以认为这个地址是行和列的编号,它们分别被标记为u和v。
纹理坐标位于纹理空间中,也就是说,它们是相对于纹理坐标系的原点(0,0)的。当把纹理贴到三维空间中图元的表面时,纹理的texel必须先被映射到对象坐标系,然后再变换到屏幕坐标系的位置。
将Texel映射到屏幕空间
Direct3D直接把纹理中的texel映射到屏幕空间,这样就省略了中间步骤并极大地提高了效率。这个映射的过程实际上是一个反向映射,也就是说,系统根据每个像素在屏幕空间中的位置计算该像素在纹理空间中相应的texel的位置,然后对位于该点或该点附近的纹理颜色进行取样。取样的过程被称为纹理过滤。
纹理中每个texel的位置可以用它的texel坐标表示。但是为了把texel贴到图元表面,Direct3D需要所有的纹理中的texel具有相同的地址范围,所以Direct3D使用了一种通用的寻址方法。在这种寻址方法中,所有texel的地址都在闭区间0.0到1.0内。Direct3D用u,v值表示纹理坐标,这和用x,y坐标表示二维笛卡尔坐标系非常相似。从技术上讲,系统事实上可以处理0.0到1.0范围外的纹理坐标,这时系统根据应用程序设置的纹理寻址模式来进行此类处理.
采用这种方法的结果是相同的纹理地址在不同的纹理中会映射到不同的texel坐标。在下图中,正在使用的纹理地址是(0.5,1.0)。但是,因为纹理的大小不同,所以该纹理地址映射到不同的texel。左边纹理的大小为5x5,纹理地址(0.5,1.0)映射到texel (2,4)。右边纹理的大小为7x7,纹理地址(0.5,1.0)映射到texel (3,6)。
纹理映射
在场景中,我们可以把纹理应用到对象上,这个过程就叫做“纹理映射”。在此过程中,纹理坐标会被映射到顶点上,所以,顶点将额外增加两个值:U和V。下面的图表是一个纹理映射到立方体的例子,例子中的立方体的顶点序号我们以前建立的立方体相同。
在Direct3D中使用纹理
在Direct3D中使用纹理要遵循以下步骤
1 修改FVF和自定义顶点
2 创建纹理
3 设置纹理坐标
4 在渲染时设置怎样渲染纹理
下面以是一个立方体的贴图示例
修改FVF和自定义顶点
struct CUSTOMVERTEX { FLOAT x, y, z; // 顶点坐标 DWORD colour; // 颜色 FLOAT tu, tv; // 纹理坐标 }; #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
再定义一个全局变量指向我们创建的纹理对象
LPDIRECT3DTEXTURE9 g_pTexture = NULL;
创建纹理
Direct3D允许我们读图片文件来创建纹理,这需要用到函数D3DXCreateTextureFromFile();
函数原型:
HRESULT D3DXCreateTextureFromFile( LPDIRECT3DDEVICE9 pDevice, LPCTSTR pSrcFile, LPDIRECT3DTEXTURE9 *ppTexture );
为此,新建一个函数SetTexture()
HRESULT SetTexture(char *pszTexturePath) { if (FAILED(D3DXCreateTextureFromFile( g_pD3DDevice, pszTexturePath, &g_pTexture))) return E_FAIL; return S_OK; }
该函数调用的时机应该是在创建了3D设备后,渲染场景之前。
在InitD3D中调用SetTexture();
HRESULT InitD3D(HWND hWnd) { … if(FAILED(SetTexture("Texture.bmp"))) { return E_FAIL; } … }
设置纹理坐标
对应于立方体来说,其纹理坐标是比较简单的。
修改的InitVertexBuffer函数
HRESULT InitVertexBuffer() { … CUSTOMVERTEX cvVertices[] = { //Top Face {-1.0f , 1.0f , -1.0f, D3DCOLOR_XRGB(0, 0, 255),0.0f,1.0f}, {-1.0f , 1.0f , 1.0f, D3DCOLOR_XRGB(255, 0, 0),0.0f,0.0f}, {1.0f , 1.0f , -1.0f, D3DCOLOR_XRGB(255, 0, 0),1.0f,1.0f}, {1.0f , 1.0f , 1.0f, D3DCOLOR_XRGB(0, 255, 0),1.0f,0.0f}, //Face 1 {-1.0f, -1.0f, -1.0f, D3DCOLOR_XRGB(255, 0, 0),0.0f,1.0f}, {-1.0f, 1.0f, -1.0f, D3DCOLOR_XRGB(0, 0, 255),0.0f,0.0f}, {1.0f, -1.0f, -1.0f, D3DCOLOR_XRGB(0, 255, 0),1.0f,1.0f}, {1.0f, 1.0f, -1.0f, D3DCOLOR_XRGB(255, 0, 0),1.0f,0.0f}, //Face 2 {1.0f, -1.0f, 1.0f, D3DCOLOR_XRGB(0, 0, 255),0.0f,1.0f}, {1.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(0, 255, 0),0.0f,0.0f}, //Face 3 {-1.0f, -1.0f, 1.0f, D3DCOLOR_XRGB(0, 255, 0),1.0f,1.0f}, {-1.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(255, 0, 0),1.0f,0.0f}, //Face 4 {-1.0f, -1.0f, -1.0f, D3DCOLOR_XRGB(255, 0, 0), 0.0f, 1.0f}, {-1.0f, 1.0f, -1.0f, D3DCOLOR_XRGB(0, 0, 255), 0.0f, 0.0f}, /Bottom Face {1.0f, -1.0f, -1.0f, D3DCOLOR_XRGB(0, 255, 0),0.0f,1.0f}, {1.0f, -1.0f, 1.0f, D3DCOLOR_XRGB(0, 0, 255),0.0f,0.0f}, {-1.0f, -1.0f, -1.0f, D3DCOLOR_XRGB(255, 0, 0),1.0f,1.0f}, {-1.0f, -1.0f, 1.0f, D3DCOLOR_XRGB(0, 255, 0),1.0f,0.0f} }; … }
在渲染时设置怎样渲染纹理
void Render() { … g_pD3DDevice->SetTexture(0,g_pTexture); //渲染图元 … g_pD3DDevice->SetTexture(0,NULL); //渲染其它图元 … } 程序结束时,清除纹理对象 void CleanUp() { …… SafeRelease(g_pTexture); …… } HRESULT SetSamplerState( DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value);
纹理寻址模式
Direct3D应用程序可以把纹理坐标值赋给任何图元的任何顶点。一般来说,应用程序赋给顶点的u、v纹理坐标值在0.0到1.0范围内,闭区间。但是,通过把纹理坐标值赋为此范围外的值,应用程序可以创建某些特殊纹理效果。
通过设置纹理寻址模式,应用程序可以控制当纹理坐标位于范围[0.0, 1.0]外时希望Direct3D执行何种操作。例如,应用程序可以设置寻址模式,使纹理平铺于图元表面。
设置寻址模式
应用程序可以通过调用
IDirect3DDevice9:: SetSamplerState方法设置每个纹理的纹理寻址模式。
函数原型
设置纹理寻址模式,需要把Type参数设置为:
D3DSAMP_ADDRESSU,
D3DSAMP_ADDRESSV
当Type参数设置为上两个值时,value 参数可以设置为枚举类型
typedef enum _D3DTEXTUREADDRESS { D3DTADDRESS_WRAP = 1, D3DTADDRESS_MIRROR = 2, D3DTADDRESS_CLAMP = 3, D3DTADDRESS_BORDER = 4, D3DTADDRESS_MIRRORONCE = 5, D3DTADDRESS_FORCE_DWORD = 0x7fffffff } D3DTEXTUREADDRESS;
中的一个值
环绕纹理寻址模式
环绕纹理寻址模式由D3DTEXTUREADDRESS枚举类型的D3DTADDRESS_WRAP成员表示。它会使Direct3D在纹理坐标的整数边界重复使用该纹理。例如,设想应用程序创建了一个方的图元并把纹理坐标指定为(0.0,0.0), (0.0,3.0), (3.0,3.0)和(3.0,0.0),把纹理寻址模式设置为D3DTADDRESS_WRAP会使纹理在u和v方向都重复三次。
镜像纹理寻址模式
镜像纹理寻址模式由D3DTEXTUREADDRESS枚举类型的D3DTADDRESS_MIRROR成员表示,它会使Direct3D在纹理坐标的整数边界先对纹理进行镜像然后再重复使用。例如,设想应用程序创建了一个方的图元并把纹理坐标指定为(0.0,0.0), (0.0,3.0), (3.0,3.0)和(3.0,0.0),把纹理寻址模式设置为D3DTADDRESS_MIRROR会使纹理在u和v方向都重复三次,每一行和每一列的纹理都是相邻行和列的纹理的镜像。
截取纹理寻址模式
截取纹理寻址模式由D3DTEXTUREADDRESS枚举类型的D3DTADDRESS_CLAMP成员表示,它会使Direct3D把纹理坐标截取到[0.0, 1.0]范围内,也就是说,这种模式只应用纹理一次,然后就重复使用纹理边缘处像素的颜色。例如,设想应用程序创建了一个方的图元并把纹理坐标指定为(0.0,0.0), (0.0,3.0), (3.0,3.0)和(3.0,0.0),把纹理寻址模式设置为D3DTADDRESS_CLAMP会使纹理只被应用一次,列的顶端和行的末端处像素的颜色被相应地延伸至图元的顶端和右边。
边框颜色纹理寻址模式
边框颜色纹理寻址模式由D3DTEXTUREADDRESS枚举类型的D3DTADDRESS_BORDER成员表示,该寻址模式会使Direct3D对于位于[0.0, 1.0]范围之外的纹理坐标使用一个被称为边框颜色的指定颜色。应用程序可以通过调用IDirect3DDevice9::SetSamplerState
方法设置边框颜色。在调用时要把第一个参数设为想要设置的纹理层的标识,把第二个参数设为D3DSAMP_ADDRESSU或者D3DSAMP_ADDRESSV,并把第三个参数设为D3DTADDRESS_BORDER。
此时,边框默认的颜色是RGB(0,0,0)。在程序中可以通过调用SetSamplerState函数来设置边框的颜色,如下,将边框设置为红色
g_pD3DDevice->SetSamplerState( 0,D3DSAMP_BORDERCOLOR,D3DCOLOR_XRGB(255,0,0)); g_pD3DDevice->SetSamplerState( 0,D3DSAMP_ADDRESSU,D3DTADDRESS_BORDER ); g_pD3DDevice->SetSamplerState( 0,D3DSAMP_ADDRESSV,D3DTADDRESS_BORDER );
程序源代码下载地址:http://download.csdn.net/source/2920612