DirectX (9) 纹理映射

引言

             在前面几篇博文中,都没有使用纹理来对我们世界进行渲染,本次博文将向大家介绍,如果在DirectX9.0中,使用Shader来进行纹理映射。


纹理坐标系统

              在DirectX中,使用的纹理坐标系统有两个轴向,分别称为u轴,和v轴。u轴从左到右依次增长,v轴从上到下依次增长。纹理坐标(u,v)定义了在纹理图片上的一个像素点,称为纹素。那么纹理坐标的范围取值该如何定义了?

             在使用纹理坐标系统的时候,由于纹理的大小不总是相同的,所以,我们使用归一化的坐标来表示纹理的坐标范围,也就是说纹理坐标的范围从0到1。比如,如果我们想要选取纹理的中间像素,那么我们可以这样定义纹理坐标(0.5,0.5)。而如果,我们想要选取纹理左上角的像素,就可以这样定义纹理坐标(0,0)。同样的,如果我们想要获取纹理的右下角的纹素值,我们可以这样定义(1,1)。


纹理映射方法

          为了能够让纹理图片正确的显示在我们的模型上,我们需要将纹理的坐标映射到模型上来。而在DirectX中,模型是以三角形的方式进行定义的。也就是说,我们该怎么样为三角形的三个顶点定义纹理坐标了?方法很简单,看看下面的图片就能够明白:

        

          假如,我们有一个上面这样的四边形。我们想要将上面显示的纹理映射到这个四边形上去。我们知道要组合成这个四边形需要两个三角形,我用红色的线将他们划分了。

为了,能够将图片以上面的方式映射上去,我们就需要为这两个三角形,共四个顶点,定义不同的带有纹理的坐标。为此,我们需要先来确定一下带有纹理坐标的顶点格式,我采用如下的格式来定义顶点:

            Vertex( x, y, z,   u , v)

         x和y,z定义了顶点的空间位置,而u和v定义了该顶点所拥有的纹理的坐标。所以,我们可以使用如下的方法来定义这四个顶点:

        A(0,0,0, 0,0), B(128,0,0, 1,0)  C(128,128,0, 1,1) D(0,128,0,  0,1)

         好了,通过上面的方式,我们就能够正确的定义一个四边形的带有纹理坐标的顶点了。


在DirectX中创建纹理

         在DirectX中,我们使用D3DXCreateTextureFromFile来创建一个纹理,它的函数原型如下所示:

HRESULT D3DXCreateTextureFromFile(
LPDIRECT3DDEVICE9 pDevice,
LPCSTR pSrcFile,
LPDIRECT3DTEXTURE9* ppTexture
);

          在程序中,创建了纹理之后,我们需要将纹理传进到Shader中去,所以,我们需要在Shader中定义一个纹理变量用来接受传进来的纹理,我们使用如下的Shader代码来定义:

uniform extern texture gTex ;

          定义了变量之后,我们就可以调用下面的方法,将纹理传递进去:

m_Fx->SetTexture(mhTex, mCreateTex)

         其中m_Fx是你使用Shader文件创建的特效类,mhTex是gTex的句柄,mCreateTex就是你创建的纹理。


 过滤器(Filters)

          在3D空间中,纹理图的大小往往并不总是和定义的三角形同样的大小。也就是说,我们需要对纹理进行放大和缩小,也就是进行缩放操作。那么我们如何对纹理进行操作,才能够让纹理能够放大和缩小之后,不会变的混乱不堪了?

         在这里,使用的就是各种采样方法,对纹理图进行采样,为了更好的效果可能还需要再使用滤波器进行过滤。在DirectX中,支持三种不同种类的采样方法。下面一一介绍他们。

        首先给出这三种采样方式的名称,他们分别是:

  •        点采样
  •        双线性采样
  •         三线性纹理滤波采样

        我们知道,在上面定义了几个顶点的纹理坐标,但是对于一个三角形来说,它是一个平面,它需要将纹理整个的映射到这个平面上来。也就是说,如何通过这三个顶点的纹理坐标,来铺满整个平面?       读者,可能注意到这个问题,和我们以前讨论的如何通过顶点的颜色,然后将整个三角形进行着色的问题很相似。对头,这里,我们也是使用插值的方式来获取每一个像素点的纹理坐标,然后通过这个纹理坐标,采用不同的采样方式来获取纹理图中的像素值,使用这个采集的值来填充这个像素。

        我们知道了如何进行纹理的插值(插值方法和前面介绍的颜色插值一致,这里不再赘述)之后,就要确定到底使用哪种采样方法来进行采样。下面将一一介绍不同的采样方法。

点采样

       点采样,故名示意,就是使用我们进行插值后的纹理坐标来将它扩展到与纹理图相应的尺寸大小(还记的前面说过的,纹理坐标实际上是归一化的坐标),然后将这个变换后的纹理坐标进行取整,也就是截取小数部分,只保留整数部分,然后就使用这个整数的坐标来获取纹理图中对应的纹素值。

      比如下面的数据:

      我们纹理图的尺寸是128*128 ;

      我们经过插值计算后的某个像素点的纹理坐标为(0,70,0.55)

      那么我们将这个纹理坐标进行变化,使得纹理坐标的尺寸和纹理图的尺寸一致,即:

     0.70 * 128 = 89.6,  0.55 * 128 = 70.4

      再进行取整操作得到最后的纹理图上的坐标为(89, 70)

      然后,我们就使用这样的坐标,来获取纹理图中第89列,第70行的那个像素的值,用这个值来填充我们计算的那个像素点的颜色。


     读者可以看出,由于我们截取了小数部分,所以失去的部分的信息,这样的采样方法效果肯定是很不理想的。一种稍微改进点的方法就是保留小数部分,而将采取纹理图中相邻的两个像素的值,使用小数部分作为权值来进行采样。

     拿上面的例子来说吧,我们计算后的保留小数的纹理图坐标为(89.6, 70.4),而取整之后的数据为(89,70)。

     那么我们可以发现,这个像素实际上占用的空间是89列和90列这两个像素的位置,也就是说它有0.6的(89,70)位置像素值,有0.4的(90,70)的像素值,所以最后的像素值应该为:

     0.6 * Texel(89,70) + 0.4 * Texel(90, 70)

      通过这样的方式,我们能稍微的改进点采样方法的效果。

      点采样方法效果很差,但是由于操作简单,所以效率会很高。


双线性采样

       读者可能发现,我们上面讨论改进版的点采样方法时,故意没有考虑v坐标的跨度关系。也就是说,我只考虑了u坐标,在相邻两个坐标上的权值关系。所以,如果将v坐标上的权值关系也考虑进去,效果是否更加的逼真了呢?

      的确ÿ

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值