似乎之前有说到过纹理,不过继续是复习,再复习一下也没关系啦。恩,另外这里还要在复习下多重纹理,记得上星期没提到的。这里说下。

纹理

我们D3D中纹理也经常称为纹理映射,在D3D9里,我们的纹理映射是用IDirect3DTexture9这个接口来实现的。我们用它将一个象素矩阵或位图帖到模型面上。

下面我就跟着代码进行分步的说明。

首先我们需要修改顶点结构和灵活顶点格式

struct Vertex
{
  float x,y,z; //顶点坐标
  float nx,ny,nz; //顶点法线
  float u,v;  //纹理UV
};

const DWORD FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1;

其中D3DFVF_TEX1是说我们的顶点结构中包含一个纹理坐标。当然,从中可以推测出我们可以为一套顶点使用两套纹理坐标,这里我们就需要设置为D3DFVF_TEX2

创建纹理

设置好顶点信息后,我们将使用D3DXCreateTextureFromFile函数来从文件中读取我们的纹理数据。

这个函数可以读取的图象文件格式包括:BMP,JPG,PNG,TGA,DDS,DIB

其他格式的图象文件将需要专门的函数库来进行解码处理后才可用。恩,这里额外说一些吧。

我们的图片格式,音频视频格式我们都知道有很多,他们之间的区别是什么呢?

位图一般是指我们的BMP图,它是按象素来记录我们的图片信息的,而这样的图象文件一般很大,人们为了减少其体积,便对其进行了部分的压缩,例如将临近颜色相同的象素点整合在一起记录,减少字节数,但是由于不同的算法的问题,图象文件也分为了很多的格式,音频影频文件也是如此,如WMV格式的音频我们现在很少使用,而多用MP3格式,这就是对WMV格式的音频进行了部分的算法压缩生成的新的格式,这些压缩格式通常比较小,但是也有很多压缩格式在压缩中抛弃了一些精度,这就是有损压缩,如rm格式文件,我们播放时可以发现它体积很小,然而画面品质很低,就是它进行了有损压缩,当然通过一些视频转换工具,我们可以将其他格式转化为rm格式,而rm就很难转换为其他格式了,因为我们不知道它在压缩时抛弃了什么信息。

恩,回到正题,我们使用上列的6种形式的图象来创建一个纹理:

IDirect3DTexture9* MyTexture;  //声明一个纹理文件
D3DXCreateTextureFromFile( D3DDevice, "MyTexture.bmp", &MyTexture );

/* 将纹理信息从图象文件中赋给我们的纹理文件,其中第一个参数是我们建立的D3D设备,第二个参数是图象文件相对路径,第三个参数是我们声名的纹理文件地址 */

设置纹理

创建完毕纹理,我们需要对纹理进行设置,使用SetTexture函数

D3DDevice->SetTexture( 0, MyTexture );

其中第一个参数是纹理层级(mipmaps链级),可以从0-7之间进行选择。在十九章说到纹理的时候,我曾说过,我们的纹理建议是一个2次方的正方形,而且尽可能的小,原因就是避免占用我们显存,因为纹理在我们计算机中保存的并非一份,而是保存8份。其中0号是我们纹理本身,1号则是将我们纹理进行压缩1/2倍进行保存的,2号则是将我们的纹理进行压缩1/4倍进行保存的。。。

以此类推。这样保存的原因我们可以想到,在游戏中,近处的物体我们看的清晰,纹理当然也很清晰,我们需要使用清晰的纹理0号,但是当物体离我们视角很远的时候,它或许仅仅显示一个象素点的大小,我们若再对物体帖上一个完整的很大的纹理是没有必要的,因为我们并看不清楚纹理上到底是只老虎还是只猫,此时我们仅仅需要给它渲染上一个粗糙的纹理就可以了,可以大幅度节省显存。所以此时远方的渲染,可以使用被压缩多次的6号7号纹理,虽然模糊粗糙,然而玩家是不会在意的。 而第2个参数则是我们刚创建出的纹理。

纹理过滤

恩,我们可以想象一下,我们假如要在游戏中建立一个宏伟的埃及狮身人面像的模型,那么它一定是非常大的,这时我们对其进行纹理映射时候可以想象,是否我们也需要一个极大的配套的纹理?当然不行,我们的纹理需要根据模型的大小进行适当缩放,当然,这个过程我们不必操心,DX内部在设置UV时已经帮我们解决了,然而它解决的并不好,在纹理被拉伸或缩小时,纹理的变形是相当严重的,这就需要我们对其进行平滑的处理,我们就可以使用纹理过滤器。当然这是一个花费时间的东西,必要时候才使用,并且要注意在速度和品质之间选择一个平衡。

我们可以通过SetSampleState进行设置过滤器:

D3DDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR ):

其中第一个参数是过滤器编号,我们默认为0就好

第二个参数是过滤器的状态,它可以控制过滤的边界颜色,状态等信息,我们还是直接使用D3DSAMP_MAGFILITER就好,若使用多级纹理则需要再设置D3DSAMP_MAXMIPLEVEL或MINMIPLEVEL对其设置,这个之后我再说明

第三个参数是过滤方式,大体可以分为三类:

  • D3DTEXF_PIONT(临近点过滤)这是最简单粗糙的过滤,它过滤效果不好,然而它的计算很快。
  • D3DTEXF_LINEAR(线性过滤)这是一个比较折中的过滤,过滤效果比较好,计算也不会很慢,一般推荐使用。
  • D3DTEXF_ANISOTROPIC(各向异性过滤)是一个能产生优质效果的过滤方法,然而计算处理时间过长,很少使用。然而使用该过滤方式还需要设置它的等级,等级越高,则过滤后的效果更好,不过一般来说显卡对这个过滤等级是有限制的,通常可以设置为4。

纹理寻址

在十九章,我曾说过,我们的纹理UV取值都是在[0,1]中的,而实际上,我们是可以填写该区域之外的数值,程序也不会报错,因为当我们填写1以外的值时,程序将使用纹理寻址来实现一些特殊效果。

因为新浪帖图很麻烦的关系,这里不再详细说明了,大家有兴趣的可以将UV值改为(0,3)(3,0)(3,3)(0,0)尝试一下。可以实现的特效有类似于桌面的平铺,镜像等。

总结

为模型进行纹理映射的全部过程就可以分为4步:

  1. 创建物体顶点,设置FVF格式
  2. 使用D3DXCreateTextureFromFile函数将图象文件读取出
  3. 对图象进行缩放,设置mipmaps链级过滤(此步可选)
  4. 使用SetTexture函数将纹理关联到物体模型上。