纹理映射(Texture Mapping)

时间:2022-09-10 18:49:11

纹理映射技术,是一种将图形绘制(映射)到表面的技术,可以显著地增加所绘制场景的细节和真实感。
如:
纹理映射(Texture Mapping)
纹理映射(Texture Mapping)


  • 纹理坐标
    纹理实际上是一个二维数组,它的元素是一些颜色值。单个的颜色值被称为纹理元素或纹理像素。每一个纹理像素在纹理中都有一个唯一的地址。这个地址可以被认为是一个列和行的值,它们分别由U和V来表示。纹理坐标位于纹理空间中。也就是说,它们和纹理中的(0,0)位置相对应。当我们将一个纹理应用于一个图元时,它的纹理像素地址必须要映射到对象坐标系中。然后再被平移到屏幕坐标系或像素位置上。
    纹理坐标是一对浮点值,用于访问纹理图像中的信息。在Direct3D中所使用的纹理坐标系由沿水平方向的x轴和沿垂直方向的y轴构成。
    纹理映射(Texture Mapping)
    要注意,为了能够处理不同尺度的纹理,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):由某一纹理的原式分辨率创建一系列逐渐减小(将像素分别缩小一半)的纹理图像,并且对每种分辨率下的纹理所采用的过滤方式进行定制,以便保留那些比较重要的细节。

纹理映射(Texture Mapping)

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):

纹理映射(Texture Mapping)

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

    纹理映射(Texture Mapping)

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

    纹理映射(Texture Mapping)

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

    纹理映射(Texture Mapping)

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

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

源码链接