Direct-X学习笔记--纹理映射进阶

之前学习了纹理映射相关知识,但是仅仅是知道读取一个纹理贴图,然后在绘制之前设置一下纹理,但是并不知道纹理设置的一些具体细节,今天就来填坑啦!


一.四种纹理寻址方式

我们读取一个纹理图片,最好的情况是所需要的图片大小和图片本身的大小一致,但是事实往往不是这么美好。所以当纹理图片的大小和我们所绘制的模型大小不一致时,就需要通过不同的纹理寻址方式来解决这个问题。
通常,我们取的纹理坐标为(0.0f, 1.0f),这个纹理坐标刚好对应图片的大小。而现在,我们要把纹理坐标变大,即变成大于1的值,而大于1的部分就是下面我们要学习的纹理寻址方式管辖的范围啦。

四中纹理寻址方式分别为:
1)重复寻址模式(wrap texture address mode)
2)镜像纹理寻址模式(mirror texture address mode)
3)夹取寻址模式(clamp texture address mode)
4)边框颜色寻址模式(border color texture mode)
下面分别看一下四中寻址方式。

先来一张正常的纹理图片,我们绘制了一个正对摄像机的平面,平面共有四个点,设置为有一组纹理的灵活顶点格式:
Direct-X学习笔记--纹理映射进阶_第1张图片
然后我们修改一下之前玩过无数次的定点格式,把纹理坐标的最大值由1.0改为2.0:
//顶点数据
	vertex[0] = stVertex(-250.0f,   0.0f, 0.0f, 0.0f, 2.0f);
	vertex[1] = stVertex(-250.0f,   500.0f, 0.0f, 0.0f, 0.0f);
	vertex[2] = stVertex( 250.0f,   0.0f, 0.0f, 2.0f, 2.0f);
	vertex[3] = stVertex( 250.0f,   500.0f, 0.0f, 2.0f, 0.0f);
这样,一张图片就不能完整的覆盖住模型啦,我们的纹理寻址方式就要派上用场啦!

注意,寻址方式的设定在u,v两个方向是可以分别设定的!

关于设置,我们可以通过DX的一个API---SetSamplerState函数来设定。
第一个参数是纹理的层数,一共不是可以有8层纹理嘛,如果只用第一层的话,直接设置为0就好啦。
第二个参数为u,v方向,分别为D3DSAMP_ADDRESSU,或者D3DSAMP_ADDRESSV即可
第三个参数为纹理寻址方式,如下:
typedef enum D3DTEXTUREADDRESS {
 D3DTADDRESS_WRAP          = 1,   //重复寻址模式
 D3DTADDRESS_MIRROR        = 2,   //镜像寻址模式
 D3DTADDRESS_CLAMP         = 3,   //夹取寻址模式
 D3DTADDRESS_BORDER        = 4,   //边框颜色寻址模式
 D3DTADDRESS_MIRRORONCE    = 5,
 D3DTADDRESS_FORCE_DWORD   =0x7fffffff
} D3DTEXTUREADDRESS, *LPD3DTEXTUREADDRESS;
我们只需要在绘制之前,设置纹理,再设置一下纹理寻址方式就可以啦!

1.重复寻址模式

注意!重复寻址模式是DX默认的寻址方式,即使我们不设置,也是按照重复寻址模式来寻址的!

所谓重复寻址模式,其实就是字面理解就好,绘制完之后,继续重复之前的纹理,继续绘制。其实说的话并说不清楚,上图一下子就明白啦~!
Direct-X学习笔记--纹理映射进阶_第2张图片

设置方法:
//设置纹理寻址方式
	g_pDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
	g_pDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);




2.镜像寻址模式

所谓镜像寻址模式,就是大于1.0的部分,和之前的呈镜面对称。上图:
Direct-X学习笔记--纹理映射进阶_第3张图片
设置方式为:
//设置纹理寻址方式
	g_pDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_MIRROR);
	g_pDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_MIRROR);


3.夹取寻址模式

夹取寻址模式是在大于1.0f的部分边缘无限延伸的一种寻址模式。还是老规矩,看张图就能了解啦: Direct-X学习笔记--纹理映射进阶_第4张图片

设置方式:
	//设置纹理寻址方式
	g_pDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
	g_pDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);


4.边框寻址模式

这个更加简单,如果我们的纹理图片不够大了,那么系统将会使用边框的颜色作为大于1.0f部分的纹理。来看例子:
Direct-X学习笔记--纹理映射进阶_第5张图片

设置方法:

	g_pDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER);
	g_pDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER);


5.显示一部分纹理

纹理寻址一般是对于纹理坐标大于1的情况,而我们也可以把纹理坐标改为小于1,即显示出一部分纹理信息。
比如,我们在定义顶点格式的时候,将纹理坐标写成0.5:
//顶点数据
	vertex[0] = stVertex(-250.0f,   0.0f, 0.0f, 0.0f, 0.5f);
	vertex[1] = stVertex(-250.0f,   500.0f, 0.0f, 0.0f, 0.0f);
	vertex[2] = stVertex( 250.0f,   0.0f, 0.0f, 0.5f, 0.5f);
	vertex[3] = stVertex( 250.0f,   500.0f, 0.0f, 0.5f, 0.0f);
run一下:
Direct-X学习笔记--纹理映射进阶_第6张图片

关于纹理寻址方式的总结:
1)纹理寻址方式指的是纹理图片不够大的情况,设置的一种状态,使图像能够更好的和模型贴合。
2)上面每个设置都有u,v两个方向的分别设置,所以,可以分别对uv进行设置,融合成不同的效果。


二.纹理过滤方式

上面所说的纹理寻址方式,一般是在纹理坐标大于1.0的时候,怎么处理大于1.0的部分,而关于0-1.0f这个区间,即正常的纹理区间,怎么让纹理更好的显示。在0-1这个区间,纹理会完整的贴在模型上,但是,纹理的大小很可能与模型大小不一样,如果纹理图片大于模型大小,那么就会出现多个纹理像素被绘制到一个像素点上,而如果纹理图片过小,那么又会出现一个纹理像素绘制在好几个像素点上,这两种情况如果不处理好,都会影响效果。适当的设置纹理过滤方式,就可以更好的表现出纹理。下面看一下各种纹理
过滤方式,一共有四种纹理过滤方式:
1)最近点采样过滤方式
2)线性过滤方式
3)各向异性过滤方式
4)多级渐进过滤方式
下面分别学习一下:

1.最近点采样过滤方式

最近点采样是效果最差的纹理过滤方式,但是速度最快。其实这个貌似就是我们不设置纹理过滤方式时的默认方式,直接用像素最近的点进行采样,相当于直接将纹理图片压缩或者拉伸,如果纹理图片和实际大小相差较大的话,效果非常糟糕。
设置方式如下:
//设置为最近点采样过滤方式
	g_pDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
	g_pDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);


2.线性过滤方式

线性过滤方式是DX中使用最广泛的纹理过滤方式,与最近点采样的方式相比能很好的提高显示质量,而且开销不大。线性纹理过滤取得与计算得到的纹理元素的浮点地址最接近的上下左右4个纹理元素,对这四个纹理元素进行加权平均,从而得到最终显示得颜色值。
//设置为线性纹理过滤方式
	g_pDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
	g_pDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);

3.各向异性过滤方式

我们知道,世界不止是由四四方方的物体构成的,传统的线性过滤方式都是各向同性的,即各个方向上的矢量值是一致的。它需要对映射点周围方形8个或更多的像素进行取样,获得平均值后映射到像素点上。对于3D游戏来说,各向异性过滤则是很重要的一个功能,因为它可以使画面更加逼真,但是处理起来比线性过滤会更慢。

//设置为各向异性纹理过滤
	g_pDevice->SetSamplerState(0, D3DSAMP_MAXANISOTROPY, 3);		//设置各向异性最大程度值(大于1的值)
	g_pDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC);
	g_pDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC);

4.多级渐进过滤

Direct-X学习笔记--纹理映射进阶_第7张图片
上面一张图就表明了多级渐进纹理的思想,当物体离摄像机越近,就用越大的纹理,当离摄像机较远,就使用小的纹理。这样的好处是当物体较远时,所使用的纹理小,性能较好。但是多级渐进纹理解决的仅是根据远近切换不同的纹理贴图而已,我们还需要额外设置纹理过滤的方式,换句话说,多级渐进纹理是和其他三种纹理过滤方式结合着使用的。

这里面要使用之前创建纹理贴图CreateTextureFromFile的加强版,在后面加个Ex,函数原型如下:
HRESULT D3DXCreateTextureFromFileEx(
 _In_     LPDIRECT3DDEVICE9pDevice,   //D3D设备接口对象
 _In_     LPCTSTR pSrcFile,   //纹理贴图的文件地址
 _In_     UINT Width,        //纹理宽度,为0的话表示使用贴图的宽度
 _In_     UINT Height,       //纹理高度,为0的话表示使用贴图的高度
 _In_     UINT MipLevels,         //生成的渐进纹理的级数
 _In_     DWORD Usage,          //用法的标志,通常设为0
 _In_     D3DFORMAT Format, //纹理贴图的格式
 _In_     D3DPOOL Pool,         //保存纹理的方式
 _In_     DWORD Filter,        //纹理过滤方式
 _In_     DWORD MipFilter,     //生成纹理序列的过滤方式
  _In_     D3DCOLOR ColorKey, //替换Alpha值得颜色值
 _Inout_  D3DXIMAGE_INFO *pSrcInfo,  //通常设为NULL就可以了
 _Out_    PALETTEENTRY *pPalette,   //调色板的地址,通常设为NULL即可
 _Out_    LPDIRECT3DTEXTURE9*ppTexture   //纹理接口对象
);

通过这个函数,我们可以设置生成渐进纹理的级数,然后DX就会帮我们自动生成多个层级的多级渐进纹理。

设置的方法如下:
	//设置纹理最大级过滤级数
	g_pDevice->SetSamplerState(0, D3DSAMP_MAXMIPLEVEL, 5);
	//设置为多级渐进纹理过滤方式配合渐进纹理方式
	g_pDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);






附上一篇讲纹理很详细的文章:http://www.cppblog.com/liangairan/articles/77682.html


你可能感兴趣的:(Direct-X)