纹理映射(Texture Mapping)

xiaoxiao2021-02-28  72

无论是在现实生活中还是在游戏虚拟世界中,将任何一个物体进行投影,然后进解析,都会发现它是由若干个多边形所构成,再将多边形进行分解,可以划分为若干个四边形和三角形,再将四边形进行分解,可以发现,四边形又可以划分为2个或以上的三角形构成。 因此就是采用这种方法,将图像数据映射到三角形单元中去。 纹理映射技术,是一种将图形绘制(映射)到表面的技术,可以显著地增加所绘制场景的细节和真实感。 如:


纹理坐标 纹理实际上是一个二维数组,它的元素是一些颜色值。单个的颜色值被称为纹理元素或纹理像素。每一个纹理像素在纹理中都有一个唯一的地址。这个地址可以被认为是一个列和行的值,它们分别由U和V来表示。纹理坐标位于纹理空间中。也就是说,它们和纹理中的(0,0)位置相对应。当我们将一个纹理应用于一个图元时,它的纹理像素地址必须要映射到对象坐标系中。然后再被平移到屏幕坐标系或像素位置上。 纹理坐标是一对浮点值,用于访问纹理图像中的信息。在Direct3D中所使用的纹理坐标系由沿水平方向的x轴和沿垂直方向的y轴构成。 要注意,为了能够处理不同尺度的纹理,Direct3D将纹理坐标做了规范化的处理,使其限定在区间[0,1]内。 一般对于每个屏幕三角形单元,都可以在纹理中定义一个相应的三角形区域,然后将该三角形区域的纹理映射到屏幕三角形单元中。 添加一个纹理坐标对以标识纹理中的顶点: struct Vertex { float _x,_y,_z; float _nx,_ny,_nz; float _u,_v; static const DWORD FVF; }; const DWORD Vertex::FVF=D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1;

值得注意的是:当为一个3D三角形指定相应的纹理三角形时,并不是马上就会进行纹理映射,是直到光栅化的时候,纹理映射才会进行。

创建纹理: 一般纹理的数据都是从磁盘中的图像文件读入,然后再加载到IDirect3DTexture9对象中;同样该图像文件可以在场景中的多个表面上共享使用。 Direct3D支持的图像文件格式有: .jpg; .bmp; .tga; .png; .dds; .ppm; .dib; .hdr; .pfm;

从文件中加载纹理并将其加载到内存中,使用D3DXCreateTextureFromFile()函数 HRESULT D3DXCreateTextureFromFile( LPDIRECT3DDEVICE9 pDevice, //设备对象 LPCTSTR pSrcFile, //所需加载的图像文件名 LPDIRECT3DTEXTURE9 *ppTexture //定义一个指针用来接收所创建的纹理 );

如果想让文件所加载的图像发挥更多的控制作用,可以使用D3DXCreateTextureFromFileEx()函数

HRESULT D3DXCreateTextureFromFileEx( LPDIRECT3DDEVICE9 pDevice, //设备对象 LPCTSTR pSrcFile, //所需加载的图像文件名 UINT Width, //图像宽度 UINT Height, //图像高度 UINT MipLevels, //图片的图层,与图像质量有关 DWORD Usage, //设定纹理的使用方法 D3DFORMAT Format, //每个颜色使用的位数(8,16,24,36) D3DPOOL Pool, //纹理对象驻留的内存类别 DWORD Filter, //处理图像质量的方法 DWORD MipFilter, //像素过滤方式 D3DCOLOR ColorKey, //设置透明色 D3DXIMAGE_INFO *pSrcInfo, //记录载入图片信息 PALETTEENTRY *pPalette, //记录调色板信息 LPDIRECT3DTEXTURE9 *ppTexture //用来接收所创建的纹理 );

现在已经知道加载纹理的函数了,那怎么使用? 比如现在要加载一个名为“hell.bmp”的图像文件创建纹理: 1、创建设备对象和用来接收所创建纹理的指针

LPDIRECT3DDEVICE9 Device; IDiretct3DTexture9 *_hell; D3DXCreateTextureFromFile(Device, "hell.bmp", //如果不是放在当前项目下,就加上路径名 &_hell);

2、设置当前纹理,使用SetTexture()函数

//SetTexture()的函数原型 HRESULT SetTexture( DWORD Sampler, //纹理要施加的采样器阶段,该值在[0,7] IDirect3DBaseTexture9 *pTexture //Direct3D9纹理对象 ); Device->SetTexture(0,_hell); 纹理过滤器 如前面所说(在纹理中定义一个三角形,然后将三角线区域的纹理映射到屏幕三角形单元中),理论上是这样,但实际上,纹理三角形与屏幕三角形的大小并不一致,当纹理三角形比屏幕三角形小时,为了适应屏幕三角形,只能将纹理三角形进行放大;当纹理三角形比屏幕三角形大时,为了适应屏幕三角形,也只能将纹理三角形进行缩小。放大/缩小的过程其实就是将图像的某些像素数据进行复制/舍弃。因此会使得有些时候图形会变得很畸形,为了防止这类情况Direct3D提供了一种技术——纹理过滤(Texture filtering). Direct3D提供了四种类型的纹理过滤方式。 1、最近点采样(nearest point sampling):该方式处理的速度在3种类型里面是最快的,但效果也是最差的,内存开销小。 LPDIRECT3DDEVICE9 Device; Device->SetSmaplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_POINT);//放大 Device->SetSmaplerState(0,D3DSAMP_MINFILTER,D3DTEXF_POINT);//缩小 2、线性纹理过滤(linear filtering):该方式可以产生较好的效果,而且速度也是蛮快的,内存开销比较适宜得当。 Device->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_LINEAR);//放大 Device->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_LINEAR);//缩小 3、各向异性纹理过滤(anisotropic filtering):该方式可以产生最好的过滤效果,但处理速度却是最慢的,内存的开销也是最大的。再进行使用各向异性纹理过滤时,必须对D3DSAMP_MAXANISOTROPIC水平值进行设定,该值决定了各向异性过滤的质量水平,值越大,图像效果就越好。不过在使用前先使用GetDeviceCaps()函数进行检测下,看硬件能支持的数值是多少。 Device->SetSmaplerState(0,D3DSAMP_MAXANISOTROPIC,3);//假设值为3 Device->SetSmaplerState(0,D3DSAMP_MAGFILETER,D3DTEXF_ANISOTROPIC);//放大 Device->SetSmaplerState(0,D3DSAMP_MINFILETER,D3DTEXF_ANISOTROPIC);//缩小 4、多级渐进纹理(mipmap):由某一纹理的原式分辨率创建一系列逐渐减小(将像素分别缩小一半)的纹理图像,并且对每种分辨率下的纹理所采用的过滤方式进行定制,以便保留那些比较重要的细节。

Device->SetSamplerState(0,D3DSAMP_MIPFILTER,Filter);

Fileter可以取以下值:

D3DTEXF_NONE: 禁用多级渐进纹理过滤。

D3DTEXF_POINT: 采用最近点采样(nearest point sampling)进行过滤。

D3DTEXF_LINEAR: 采用线性纹理(linear filtering)进行过滤。

寻址模式 上面说过纹理坐标必须限制在[0,1]范围内,如果超出那怎么办,Direct3D提供了四种用来处理纹理坐标值超出[0,1]区间的纹理映射模式。

重复寻址模式(wrap address mode):

Device->SetSamplerState(0,D3DSAMP_ADDRESSU,D3DTADDRESS_WRAP); Device->SetSamplerState(0,D3DSAMP_ADDRESSV,D3DTADDRESS_WRAP); 边界颜色寻址模式(boarder color address mode)

Device->SetSamplerState(0,D3DSAMP_ADDRESSU,D3DTADDRESS_BORDER); Device->SetSamplerState(0,D3DSAMP_ADDRESSV,D3DTADDRESS_BORDER); Device->SetSmaplerState(0,D3DSAMP_BORDERCOLOR,0x000000ff); 钳位(calmp address mode):

Device->SetSmaplerState(0,D3DSAMP_ADDRESSU,D3DTADDRESS_CLAMP); Device->SetSmaplerState(0,D3DSAMP_ADDRESSV,D3DTADDRESS_CLAMP); 镜像(mirror):

Device->SetSamplerState(0,D3DSAMP_ADDRESSU,D3DTADDRESS_MIRROR); Device->SetSamplerState(0,D3DSAMP_ADDRESSV,D3DTADDRESS_MIRROR);

最后上传源代码(有点小问题,不过无伤大雅)

源码链接

转载请注明原文地址: https://www.6miu.com/read-68183.html

最新回复(0)