纹理

  Direct3D支持广泛的纹理特性设置,使程序员可以轻松的访问提供高级纹理技术。下面我们来讨论Direct3D中的纹理的一些内容:

  • 1.

  • 纹理的基本概念
  • 2.
  • 纹理句柄
  • 3.
  • 纹理接口
  • 4.
  • 纹理过滤
  • 5.
  • 纹理Wrapping
  • 6.
  • 纹理融合
  • 7.
  • 纹理压缩
  • 8.
  • 自动纹理管理
  • 9.
  • 对于纹理的硬件考虑

     

     

     

     

     

  • 对于纹理的硬件考虑

     

     

     

     

     

  这一部分中讲述了

Direct3D中有关纹理的一些概念,我们分以下几个部分来分别讨论:

  •  
    1.  

        •  

            1. // This code fragment assumes that lpDDS is a valid pointer to
              // a DirectDraw surface that was created with the DDSCAPS_TEXTURE
              // surface capability, and that lpD3D3 is a valid pointer to
              // an IDirect3D3 interface.

              LPDIRECT3DTEXTURE2 lpD3DTexture2;

              // Get the texture interface.
              lpDDS->QueryInterface(IID_IDirect3DTexture2, (void**)&lpD3DTexture2);

               

              // Load the texture.
              // (This only applies to textures that were
              // created with the DDSCAPS_ALLOCONLOAD flag.
              lpD3DTexture2->Load(lpD3DTexture2);

              // Load the texture.
              // (This only applies to textures that were
              // created with the DDSCAPS_ALLOCONLOAD flag.
              lpD3DTexture2->Load(lpD3DTexture2);

               

                注:用IDirect3DTexture2::Load方法加载纹理要为纹理分配一定的内存。然后,使用DirectDrawblitting方法将一个位图从资源或文件中加载到表面上。(如果不支持blitting操作,可以使用DirectDraw IDirectDrawSurface4::LockIDirectDrawSurface4::Unlock方法直接访问表面内存。)

              •  
                  1.  

                    4.  纹理过滤

                     

                      Direct3D渲染一个图元时,会将三维图元映射到二维屏幕上。如果图元有纹理,Direct3D就必须用纹理来产生图元的二维渲染图象上每个像素的颜色。对于图元在二维屏幕上图象的每个像素来说,都必须从纹理中获得一个颜色值。我们把这一过程称为纹理过滤(texture filtering)。

                      进行纹理过滤时,正在使用的纹理通常也正在被进行放大或缩小。换句话说,这个纹理将被映射到一个比它大或小的图元的图象上。纹理的放大会导致许多像素被映射到同一个纹理像素上。那么结果看起来就会使矮矮胖胖的。纹理的缩小会导致一个像素被映射到许多纹理像素上。其结果将会变得模糊或发生变化。要解决这些问题,我们可以将一些纹理像素颜色融合到一个像素颜色上。

                     

                      Direct3D提供了一些方法来简化纹理过滤的过程。它提供了三种类型的纹理过滤:线性过滤(linear filtering)、各向异性过滤(anisotropic filtering)和mipmap过滤(mipmap filtering)。如果不选择纹理过滤,Direct3D还会使用一种叫做最近点采样(nearest point sampling)的技术。

                      每种类型的纹理过滤都有各自的优缺点。例如,线性过滤会产生锯齿状的边缘和矮胖的效果。但是,它对系统的消耗却是最小的。另一方面,

                    mipmap过滤的效果通常是最好的,特别是和各项异性过滤混合使用时。但是它却需要很大的内存消耗。

                      如果程序使用纹理句柄,可以调用

                    IDirect3DDevice3::SetRenderState方法来设置当前的纹理过滤方法,同时要将第一个参数设置为D3DRENDERSTATE_TEXTUREMAGD3DRENDERSTATE_TEXTUREMIN,第二个参数要设置为D3DTEXTUREFILTER枚举类型的一个成员。

                      程序也可以使用纹理接口指针来设置纹理过滤方法,这是要调用

                    IDirect3DDevice3::SetTexture平台State方法,并将第一个参数设置为要进行纹理过滤的那个纹理的整数索引号(0-7),将第二个参数设置为D3DTSS_MAGFILTERD3DTSS_MINFILTERD3DTSS_MIPFILTER,将第三个参数设置为D3DTEXTUREMAGFILTERD3DTEXTUREMINFILTERD3DTEXTUREMIPFILTER枚举类型的一个成员。

                      下面我们来分别讨论几种纹理过滤方法:

                    • 4.1
                    • 最近点采样
                    • 4.2
                1. 线性纹理过滤
                2. 4.3
                3. 各向异性纹理过滤
                4. 4.4 mipmap
                5. 纹理过滤
                6. 纹理过滤

          1. 线性纹理过滤
          2. 4.3
          3. 各向异性纹理过滤
          4. 4.4 mipmap
          5. 纹理过滤
          6. 纹理过滤

        • 1.3.1
        • 什么是纹理寻址模式?
        • 1.3.2
        • 纹理寻址模式
        • 1.3.3 镜像纹理寻址模式
        • 1.3.4 钳位(clamp)纹理寻址模式
        • 1.3.5 边界颜色纹理寻址模式
        • 1.3.6 设置并恢复纹理寻址模式
        • 1.3.7 纹理寻址模式和纹理Wrapping
        • Wrapping
        • 纹理寻址模式
        • 镜像纹理寻址模式
        • 钳位纹理寻址模式
        • 边界颜色纹理寻址模式
        •  

          1.4 纹理句柄和纹理接口

          1.4 纹理句柄和纹理接口

           

           

            Direct3D提供了两种操作和控制纹理的方法,纹理句柄和纹理接口。其中纹理句柄是老方法。IDirect3DIDirect3D2

          接口使用这种方法。

            在

           

          IDirect3D3接口中,我们通过纹理接口指针来创建和使用纹理。调用IUnknown::QueryInterface方法对IDirect3DTexture2接口查询DirectDrawSurface

          对象,可以得到一个纹理接口指针。

            使用纹理接口,我们可以得到一些新的纹理特性。它支持对一个图元同时使用最多

           

          8

          个纹理的融合,也加入了一些新的纹理融合操作。详细内容见“纹理接口”。

           

           

           

          1.5 调色板纹理

           

           

            Direct3D设备支持从带调色板的纹理表面进行纹理操作。这种纹理类型有时被称为“调色板纹理(palettized textures)”。一个调色板纹理是一个DirectDrawSurface对象,在创建时使用了DDSCAPS_TEXTURE能力,它使用一种DDPF_PALETTEINDEXEDn像素格式(n1248)。这些能力包含在用来创建纹理的DDSURFACEDESC2结构中。和所有的调色板表面(palettized surfaces)一样,每个像素都是相应的DirectDrawPalette对象中的一个索引值,而不是一个颜色值。在检查与纹理相关的设备能力时,一定要调用IDirect3DDevice3::EnumTextureFormats

          方法来检验所支持的纹理像素格式。

            准备一个调色板纹理,需要以下步骤:

          • 检查

          DirectDrawDirect3D
        • 能力。
        • 创建一个包含
        • DDSCAPS_TEXTURE 能力的适当大小的表面,并使用一种 DDPF_PALETTEINDEXEDn
        • 像素格式。
        • 创建并初始化一个
        • DirectDrawPalette 对象。(要使用 alpha-only 的调色板纹理,在创建调色板时就要包含 DDPCAPS_ALPHA
        • 能力。)
        • 对纹理表面调用
        • IDirectDrawSurface4::SetPalette ,将调色板配属于这个表面。

          IDirect3DTexture2接口。同时展示了调用IDirect3DTexture2::GetHandle方法来获得纹理句柄的过程。然后,程序还使用IDirect3DTexture2::Load方法加载了纹理。(使用这种方法加载纹理时,需要在创建纹理时使用DDCAPS_ALLOCONLOAD标志。)注意查询的DirectDraw表面必须包含DDSCAPS_TEXTURE能力,这样才能支持一个Direct3D纹理。

           


          // This code fragment assumes that lpDDS is a valid pointer to
          // a DirectDraw surface, and that lpD3DDevice is a valid pointer to
          // an IDirect3DDevice3 interface.

          LPDIRECT3DTEXTURE2 lpD3DTexture2;
          D3DTEXTUREHANDLE d3dhTextureHandle;
          // Get the texture interface pointer.
          lpDDS->QueryInterface( IID_IDirect3DTexture2, &lpD3DTexture2);
          // Associate the texture with a device.
          lpD3DTexture2->GetHandle( lpD3DDevice,d3dhTextureHandle);// Load the texture.
          lpD3DTexture2->Load(lpD3DTexture2);

           

           

            注:用IDirect3DTexture2::Load方法加载纹理时,需要为纹理分配一定的内存。这样,程序就能将纹理从一个资源或文件中加载到表面上。Direct3D使用设备无关位图(DIBs)来作为纹理位图。

           

          2.2 用纹理句柄进行渲染

            创建了一个纹理句柄并将位图加载到纹理表面之后,我们就可以使用纹理来进行渲染了。不管程序使用执行缓冲方法还是

    2. 线性纹理过滤
    3. 4.3
    4. 各向异性纹理过滤
    5. 4.4 mipmap
    6. 纹理过滤
    7. 纹理过滤
  • 1.1
  • 什么是纹理
  • 1.2
  • 纹理坐标
  • 1.3
  • 纹理寻址模式
  • 1.4
  • 纹理句柄和纹理接口
  • 1.5
  • 调色板纹理

     

     

  • 3-D图象,它们的表面看起来就象是一个发亮的塑料表面。它们总是缺少一些能使物体看起来更加真实的东西,如表面的磨损、裂纹、人手的印记或是一些污点等等。近几年来,纹理的使用使得计算机三维图象具有了更好的真实感。

      一个纹理实际上就是一个位图。从这个意义上来讲,当纹理一词被用于计算机图形学时,它就有了一个明确的定义。从语义学角度来讲,纹理一词既是指一个物体上颜色的模式,又是指物体表面是粗糙的还是光滑的。

    Direct3D的纹理不会使物体表面真的变得“崎岖不平”,而只是使它的表面看起来是“崎岖不平”的。

      由于

    Direct3D的纹理就是简单的位图,因此任何纹理否可以被用在Direct3D图元上。例如,我们可以创建一些具有木头和谷物图案的对象;也可以将一些青草、泥土和岩石用于一些三维图元,并将它们堆成一座小山,这样就有了一个山坡的背景;或者搞一些路标、悬崖等等。

      另外,

    Direct3D还支持一些高级的纹理技术,如纹理融合(透明或不透明)、光线映射(light mapping)等。

      如果程序创建了一个

    HAL设备、MMX设备或RGB设备,它就可以使用8-16-24-32-bit纹理。使用单色设备的程序可以使用8-bit纹理。

     

     

    1.2 纹理坐标

    1.2 纹理坐标

      纹理实际上是一个二维数组,它的元素是一些颜色值。单个的颜色值被称为纹理元素(

    texture elements)或纹理像素(texel)。每一个纹理像素在纹理中都有一个唯一的地址。这个地址可以被认为是一个列(column)和行(row)的值,它们分别由UV来表示。

      纹理坐标位于纹理空间中。也就是说,它们和纹理中的

    (0,0)位置相对应。当我们将一个纹理应用于一个图元时,它的纹理像素地址必须要映射到对象坐标系中。然后再被平移到屏幕坐标系或像素位置上。

     

      Direct3D直接将纹理空间中的纹理像素pic73.gif (10215 bytes)映射到屏幕空间中的像素,跳过了中间过程,从而提高了效率。这一映射过程实际上是一个相反的(inverse)映射。也就是说,对于屏幕空间中的每一个像素,我们来计算相应的纹理空间中的纹理像素位置。对那一点上的或那一点周围的纹理颜色进行采样(sample)。采样过程被称为纹理过滤(texture filtering)。

     

     

     

     

     

     

     

     

      纹理中的每一个纹理像素可以通过它的坐标来声明。但是,为了将纹理像素映射到图元上,对于所有纹理上的所有纹理像素,

     

    Direct3D 需要有一个统一的地址范围。因此,它使用了一个通用的地址方案,在这个方案中所有纹理像素地址的范围都在 0.0 1.0 之间,包括 0.0 1.0 Direct3D 程序用 U V 的值来声明纹理坐标,它和用 x y

    坐标来声明二维迪卡尔坐标系一样。

      在这种情况下,不同纹理中的同一纹理地址又可能被映射为不同的纹理像素坐标。如左面插图中的纹理地址

     

    (0.0,0.5) 。由于纹理的大小有所不同,因此纹理地址将会映射为不同的纹理像素。左边的纹理 1 ,大小为 5x5 ,纹理地址 (0.0,0.5) 映射到纹理像素 (0,2) ;右边的纹理 2 ,大小为 7x7 ,纹理地址 (0.0,0.5) 映射到纹理像素 (0,3)

      左图展示了一个简单的纹理像素映射的过程:pic74.gif (16563 bytes)

      我们要给图中左边的像素确定一定的颜色。像素四个角的地址被映射到对象空间中的图元上,这时,像素的形状会有一些变形,这是由图元的形状和观察的角度造成的。然后,与像素角相对应的图元表面上的几个角被映射到纹理空间中。这一映射过程再次使像素的形状产生变形。像素最终的颜色值就由该像素映射到的区域中的纹理像素计算而得。在设置纹理过滤方法时,要决定

     

    Direct3D 使用什么方法来得到像素的颜色。

      程序可以直接将纹理坐标分配给顶点。这一能力使我们能够控制将一个纹理的哪些部分映射到一个图元上。现在假定我们要创建一个矩形图元,它的大小恰好与下图中纹理的大小一样。我们要将整个纹理都映射到一整堵墙上,那么分配给图元顶点的纹理坐标就应该是

     

    (0.0,0.0) (1.0,0.0) (1.0,1.0) (0.0,1.0)

      现在我们要将墙的高度缩小一半。我们可以将纹理变形以适应墙的变化,也可以在分配纹理坐标时只使用纹理的下面一半。

    pic75.gif (16004 bytes)

      如果使用纹理变形或缩放的方法,那么所使用的纹理过滤方法就会对图象的质量产生影响。详细内容见“纹理过滤”。

     

      如果采用分配纹理坐标的方法,那么分配给图元顶点的纹理坐标就应该是

     

    (0.0,0.0)(1.0,0.0)(1.0,0.5)(0.0,0.5)Direct3D

    会将纹理的下面一半应用到墙上。

      有时,一个顶点的纹理坐标可能比

     

    1.0大。当分配给顶点的纹理坐标不在0.01.0

    (包括它们)范围内时,就要设置纹理寻址模式了。

     

     

     

    1.3 纹理寻址模式

      下面我们来讨论

    Direct3D纹理寻址模式。

     

     

    1.3.1 什么是纹理寻址模式?

    1.3.1 什么是纹理寻址模式?

     

      Direct3D程序可以将纹理坐标分配给任何图元的顶点。一般来说,分配的UV纹理坐标值都在0.01.0范围内(包括它们)。但是,如果我们分配了超出这个范围的纹理坐标,可能会得到一些特别的纹理效果。

      通过设置纹理寻址模式,我们就可以在纹理坐标超出范围时进行控制。详细的内容请看下面的相关讨论:

     

    1.3.2 Wrapping纹理寻址模式

      “

     

    Wrapping ”纹理寻址模式由 D3DTEXTUREADDRESS 枚举类型的 D3DTADDRESS_WRAP 成员来确定,它使 Direct3D 在每一个整数结点( integer junction )对纹理进行重复。假设我们要创建一个正方形图元,并将纹理坐标声明为 (0.0,0.0) (0.0,3.0) (3.0,3.0) (3.0,0.0) 。这时,如果我们设置了纹理寻址模式,就可以使纹理在 U V 方向都重复三次。,如下图所示:

    pic76.gif (64086 bytes)

      这种纹理寻址模式的效果与“镜像”模式比较相似,但在本质上是不同的。

     

     

     

    1.3.3 镜像纹理寻址模式

      “镜像”纹理寻址模式由

    D3DTEXTUREADDRESS枚举类型的D3DTADDRESS_MIRROR成员来确定,它使Direct3D在每个整数边界处(integer boundary)对纹理进行镜像处理。想在我们创建一个正方形图元,为坐标为(0.0,0.0)(0.0,3.0)(3.0,3.0)(3.0,0.0)。我们设置镜像纹理寻址模式,纹理在UV方向都重复了三次,并且每一行、每一列都与相邻的行和列成镜像关系。如下图所示:

    pic77.gif (15582 bytes)

      镜像纹理寻址模式的效果与

    Wrapping寻址模式比较相似,但本质上是不同的。

     

     

    1.3.4 钳位纹理寻址模式

    1.3.4 钳位纹理寻址模式

      “钳位”纹理寻址模式由

    D3DTEXTUREADDRESS枚举类型的D3DTADDRESS_CLAMP成员确定,它使Direct3D将纹理坐标钳制在[0.0, 1.0]范围内。也就是说,它只使用一次纹理,然后将边缘像素的颜色抹去。我们创建一个正方形图元,纹理地址分配为(0.0,0.0)(0.0,3.0)(3.0,3.0)(3.0,0.0)。这时,设置钳位纹理寻址模式,纹理将只使用一次,并且最顶一行和最后一列上的像素颜色会一直延伸到图元的最顶端和最右段,如下图所示:

    pic78.gif (5443 bytes)

     

     

    1.3.5 边界颜色纹理寻址模式

    1.3.5 边界颜色纹理寻址模式

      “边缘颜色”纹理寻址模式由

    D3DTEXTUREADDRESS枚举类型的D3DTADDRESS_BORDER成员确定,它使Direct3D可以在纹理坐标超过范围的地方使用一个任意的颜色,也就是边界颜色。

      下图中展示了一个使用了纹理的图元,它使用了红色的边界色:

     

    pic79.gif (5657 bytes)

     

      程序如何来设置边界色依赖于使用什么版本的

     

    Direct3D 设备接口。如果程序使用 IDirect3DDevice3 接口,可以调用 IDirect3DDevice3::SetTexture 平台 State 来设置边界颜色。将第一个参数设为要调用的纹理 stage 标识符,第二个参数设置为 D3DTSS_BORDERCOLOR 平台状态值,第三个参数为 RGBA

    边界颜色。

      如果使用

     

    IDirect3DDevice2 接口,可以调用 IDirect3DDevice2::SetRenderState 方法来设置边界颜色,将 D3DRENDERSTATE_BORDERCOLOR 渲染状态值和 RGBA

    颜色值作为它的参数。

      注:IDirect3DDevice3::SetRenderState方法仍然认可D3DRENDERSTATE_BORDERCOLOR渲染状态。IDirect3DDevice3不会放弃这种方法,它会将这一渲染状态的效果映射到stage 0上。程序不应将这种遗留下来的渲染状态与相应的纹理stage状态相互混淆,否则结果将难以预料。

     

     

     

     

     

    1.3.6 设置并获得纹理寻址模式

      程序如何设置和获得纹理寻址模式只要依赖于使用什么版本的

    Direct3D设备接口。在使用IDirect3DDevice3进行多纹理融合时,可以调用IDirect3DDevice3::SetTexture平台State方法来为每个纹理stage设置纹理寻址模式。将所需的纹理stage标识符作为第一个参数。将第二个参数设置为D3DTSS_ADDRESS,同时改变UV纹理寻址模式;也可以设置为D3DTSS_ADDRESSUD3DTSS_ADDRESSV,分别来改变UV寻址模式。第三个参数决定设置哪种纹理寻址模式;它可以使D3DTEXTUREADDRESS枚举类型的任何一个成员。要得到一个给定纹理stage的当前的纹理寻址模式,可以调用IDirect3DDevice3::GetTexture平台State,并使用D3DTEXTURE平台STATETYPED3DTSS_ADDRESSD3DTSS_ADDRESSUD3DTSS_ADDRESSV成员以决定要了解哪种寻址模式的信息。

      如果程序使用

    IDirect3DDevice2接口,可以调用IDirect3DDevice2::SetRenderState方法来设置纹理寻址模式,同时用D3DRENDERSTATE_TEXTUREADDRESS渲染状态来设置UV纹理寻址。也可以使用D3DRENDERSTATE_TEXTUREADDRESSUD3DRENDERSTATE_TEXTUREADDRESSV来分别设置UV寻址。和SetTexture平台State方法一样,它也使用D3DTEXTUREADDRESS枚举类型的值。

      注:IDirect3DDevice3::SetRenderState仍认可D3DRENDERSTATE_TEXTUREADDRESSD3DRENDERSTATE_TEXTUREADDRESSUD3DRENDERSTATE_TEXTUREADDRESSV渲染状态。IDirect3DDevice3会将它们的效果映射到stage 0上。我们不能将遗留的渲染状态与相应的纹理stage状态相互混淆,否则结果将难以预料。

     

    1.3.7 纹理寻址模式与纹理Wrapping

     

      Direct3D允许程序执行纹理Wrapping。但是,将纹理寻址模式设置为D3DTADDRESS_WRAP与执行纹理Wrapping使不同的。设置Wrapping纹理寻址模式只会在纹理应用使产生多个拷贝,而纹理Wrapping则会改变系统对纹理多边形的光栅方式。详细内容见“纹理Wrapping”。

      纹理

    Wrapping有效时,超出范围的纹理坐标将是不正确的,并且对这样的纹理坐标进行光栅操作也没有进行定义。同时,在使用纹理Wrapping时,不能使用纹理寻址模式。

     

     

     

     

     

     

     

    注:如果创建一个调色板纹理表面,但是却忽略了配属一个调色板,在进行渲染时会导致错误的访问。

      调色板纹理使用的调色板不仅仅只限于使用颜色数据。有时,也可以使用

    alpha信息。如果这样的话,在调用IDirectDraw4::GetCaps方法时,DirectDraw会显示使用了DDPCAPS_ALPHA调色板能力标志——这个标志在相应的DDCAPS结构的dwPalCaps成员中。如果渲染设备能够执行具有alpha能力的调色板纹理,那么在调用IDirect3DDevice3::GetCaps方法时,就会看到D3DPTEXTURECAPS_ALPHAPALETTE能力标志。(D3DPTEXTURECAPS_ALPHAPALETTED3DDEVICEDESC结构包含的两个D3DPRIMCAPS结构中。)

     

     

     

     

     

     

     

     

    2. 纹理句柄

      使用纹理句柄时,我们应该使用

     

    IDirect3DIDirect3D2接口。一个Direct3D纹理就是一个DirectDraw表面。通过调用IDirectDrawSurface4::QueryInterface方法来得到一个IDirect3DTexture2接口,这样我们就能将一个DirectDraw表面作为一个纹理映射来使用了。使用IDirect3DTexture2

    接口来加载纹理,得到句柄,并跟踪调色板的变化。

      由

     

    IDirect3DTexture2接口创建的一个纹理映射必须与一个3-D设备相对应。一个纹理句柄就反映出了一个纹理映射与一个设备之间的相互对应关系。一个给定的纹理可以与一个以上的设备相对应当程序调用IDirect3DTexture2::GetHandle方法将一个纹理与一个设备相互联系起来时,Direct3D对它进行进一步的确认,以确保所选设备可以支持声明的纹理格式和纹理大小。如果调用成功,GetHandle

    方法会返回一个纹理句柄。程序可以使用这个纹理句柄来作为渲染状态的参数。

      程序可以交替的将纹理句柄用于给定的设备。

     

     

     

      IDirect3DTexture2接口中去掉了一些原先在IDirect3DTexture

    接口中存在的方法。

      下面我们来讨论有关纹理句柄的应用问题:

     

    • 2.1

    •  
      • 使用纹理句柄进行渲染

         

         

    • 创建一个纹理句柄
    • 2.2
    •  

      2.1 创建一个纹理句柄

    DrawPrimitive方法,纹理句柄都可以用来设置与纹理相关的渲染状态。如果使用的是DrawPrimitive方法,那么所有的渲染状态设置都应该调用IDirect3DDevice3::SetRenderState方法。我们将与纹理相关的渲染状态作为第一个参数,将纹理句柄作为第二个参数。

      当程序将一个纹理设置位当前纹理时,

    Direct3D就会将它用于所有使用DrawPrimitive方法渲染的图元上。详细内容见“当前纹理”。

      通过设置纹理寻址渲染状态,程序控制纹理坐标映射到屏幕坐标的过程。详细内容见“纹理寻址状态”。

      对于某些

    3-D硬件,程序可以进行透视修正处理。许多3-D硬件能够无条件的执行透视修正。缺省情况下,Direct3D的透视修正是有效的。详细内容见“纹理透视状态”。

     

      Direct3D还具有很强的纹理过滤能力。详细内容见“纹理过滤”和“纹理过滤状态”。

      当我们将一个纹理应用到一个图元表面上时,程序可以将图元表面的颜色与纹理的纹理像素颜色进行融合。再使用纹理句柄时,我们一次只能融合一幅纹理。详细内容见“纹理融合状态”。

      使用执行缓冲的程序也可以使用纹理句柄。在使用时,要引用

    IDirect3DDevice3::SetRenderState方法,并将D3DRENDERSTATE_TEXTUREHANDLE渲染状态(它是D3DRENDERSTATETYPE枚举类型的一部分)作为第一个参数,将纹理句柄作为第二个参数。

     

     

     

     

     

     

     

    3. 纹理接口

    3. 纹理接口

      创建了一个

     

    IDirect3D3 接口的程序可以使用Direct3D中的一些新的纹理特性,并将使用IDirect3DTexture2接口指针,而不是纹理句柄。现在,如果硬件支持的话,Direct3D可以执行多纹理操作。详细内容见“多纹理融合”。

    • 3.1

    获得一个纹理接口指针
  • 3.2
    • 用纹理接口指针进行渲染

       

      3.1 获得纹理接口指针

     

     

      IDirect3D3接口下的纹理也是DirectDraw表面。因此,获得纹理接口指针的第一步就是要创建一个带有DDSCAPS_TEXTURE能力设置的DirectDraw

    表面。

      创建了表面之后,程序就能够来得到一个指向它的纹理接口的指针了。接下来要做的就是对

     

    IDirect3DTexture2接口来查询这个表面。(如果创建纹理时使用了DDSCAPS_ALLOCONLOAD标志,那么程序就必须调用IDirect3DTexture2::Load

    方法来加载纹理。)

      下面的代码展示了从一个已经存在的

     

    DirectDrawSurface对象表面来创建纹理的过程,以及如何来加在一个纹理:

    1.1 什么是纹理?

      早期的计算机生成的

 

 

 

4.1 最近点采样

  在程序中,我们并不是必须要使用纹理过滤。

Direct3D可以被设置来计算纹理像素的地址,这个地址通常不是一个整数值,这时,可以简单的取一个与它最接近的整数地址来代替原地址,并使用这个整数地址上的纹理像素颜色。我们把这一过程称为最近点采样(nearest point sampling)。当纹理的大小与图元图象的大小差不多时,这种方法非常有效和快捷。如果大小不同,纹理就需要进行放大或缩小,这样,结果就会变得矮胖、变形或模糊。

  调用

IDirect3DDevice3::SetTexture平台State方法可以来选择最近点采样方法,将它的第一个参数设置为纹理的整数平台索引号(0-7),第二个参数设置为D3DTEXTUREMAGFILTERD3DTEXTUREMIPFILTERD3DTEXTUREMIPFILTER,将第三个参数设置为D3DTFG_POINT(设置放大过滤时)、D3DTFN_POINT(缩小时)或D3DTFP_POINTmipmap时)。

  使用最近点采样是要特别小心,因为在两个纹理像素的分界线上进行采样时,可能产生图象失真(

graphic artifacts)。在进行采样时,系统会选择这个采样纹理像素或者是那个采样纹理像素,在穿越分界线时,得到的结果将会产生很大的变化,也许会得到我们不想要的结果。(在使用线性过滤时,当纹理索引穿越两个纹理像素的边界时,最终的纹理像素将会是这两个纹理像素的融合结果。)

  当我们将一个很小的纹理映射到一个很大的多边形上——这被称为“放大(

magnification)”——时,我们会看到这种效果。例如,当我们使用一个看起来象西洋跳棋盘一样的纹理时,最近顶采样会得到一个更大的西洋跳棋盘,并带有明显的边界;而采用线性过滤时,最后在多边形上,跳棋格颜色会平滑的进行过渡,不会有明显的边界出现。

  大多数时候,不使用最近点采样往往能得到最好的结果。并且在现在,大部分的硬件都是针对线性过滤进行优化的。如果你确实想得到最近顶采样那样的效果——比如要清晰的显示一些文本特征——那么就要尽量避免在纹理像素分界处进行采样,否则,就会产生图象的失真。下图中向我们展示了一种图象的失真:

 

pic80.gif (3829 bytes)

  注意上面的两个靠右的方格,它们就产生了失真。要避免这样的失真,我们首先要了解

Direct3D最近点采样的规则。Direct3D是将一个浮点纹理坐标,范围为[0.0, 1.0](包括它们),映射到一个整数的纹理像素空间,范围为[0.5, n0.5]n是一个给定大小的纹理中纹理像素的数量。最终的纹理索引是最近的整数。这样的映射会导致在纹理像素分界处进行采样。

  下面我们来看一个例子,我们使用

D3DTADDRESS_WRAP纹理寻址模式来对多边形进行渲染,使用Direct3D提供的映射对一个有4个纹理像素宽度的纹理进行映射,u纹理索引如下:

pic81.gif (4017 bytes)

  注意图中的纹理坐标

0.01.0,它们正好在两个纹理像素的分界处。更具最近点采样法的规则,纹理坐标的范围为[0.5, 40.5]4是纹理的宽度。这样,被采样的纹理像素就是第0个纹理像素,它的纹理索引值就为1.0。但是,如果纹理坐标只比1.0小一点,那么被采样的纹理像素就应该是第n个而不是第0个。

  这也就表示在将一个小的纹理使用最近点采样方法放大映射到屏幕空间时,会产生在纹理像素分界处采样的情况,这样就会产生失真。

  要将浮点纹理坐标映射到整数纹理像素上是很困难的,并且通常也没有必要这样做。大多数硬件在执行时使用一种迭代的方法来计算每个像素位置上的纹理坐标。这种方法往往会隐藏这些错误,因为它们在迭代过程中会逐渐积累起来。

 

  Direct3D参考光栅使用直接估计(direct-evaluation)的方法来计算每个像素位置上的纹理索引。与迭代法不同,直接估计过程中的一些错误会比较自由的表现出来。这样,在使用最近点采样时出现的错误就会比较明显。

  我们最好只在必需时再使用最近点采样法。在使用它时,最好能使纹理坐标明显的偏离纹理像素的分界处。

 

 

 

4.2 线性纹理过滤

4.2 线性纹理过滤

 

  Direct3D使用的线性过滤方法是双线性过滤(bilinear filtering)。和最近点采样一样,双线性过滤首先要计算一个纹理像素的地址,这个地址通常不是整数地址。然后,找到一个地址最接近的整数地址纹理像素。另外,Direct3D渲染模块还要计算与最近采样的点相邻的四个纹理像素的加权平均(weighted average)。

  可以调用

IDirect3DDevice3::SetTexture平台State方法来选择双线性纹理过滤,并将第一个参数设置为纹理的整数索引号(0-7),将第二个参数设置为D3DTEXTUREMAGFILTERD3DTEXTUREMIPFILTERD3DTEXTUREMIPFILTER,将第三个参数设置为D3DTFG_LINEAR(放大)、D3DTFN_LINEAR(缩小)或D3DTFP_LINEARmipmap)。

 

 

4.3 各向异性纹理过滤

  各向异性是对一个三维物体纹理像素的可见的变形,这个物体的表面朝向屏幕平面,并与之有一定的角度。各向异性图元的像素在映射到纹理像素时,它的形状会发生变形。

4.3 各向异性纹理过滤

  各向异性是对一个三维物体纹理像素的可见的变形,这个物体的表面朝向屏幕平面,并与之有一定的角度。各向异性图元的像素在映射到纹理像素时,它的形状会发生变形。

Direct3D用反映射到纹理空间的屏幕像素的延伸率(长度/宽度)来度量一个像素的各向异性(anisotropy)。

  各向异性纹理过滤可以和线性过滤或

mipmap过滤联合使用。调用IDirect3DDevice3::SetTexture平台State方法可以使各项异性过滤有效,同时要将第一个参数设置为纹理的整数索引值(0-7),将第二个参数设置为D3DTEXTUREMAGFILTERD3DTEXTUREMINFILTER,将第三个参数设置为D3DTFG_ANISOTROPIC(放大)或D3DTFN_ANISOTROPIC(缩小)。

  程序还要调用

IDirect3DDevice3::SetTexture平台State方法将各向异性度(degree of anisotropy)设置在01之间(不包含它们),同时将诶一个参数设置为纹理的整数索引值(0-7),将第二个参数设置为D3DTSS_MAXANISOTROPY,最后一个参数就是各向同性度(degree of isotropy)。

  将各向同性度(

degree of isotropy)设置为1将使各向同性过滤无效(设置为任何比1大的值将会使它有效)。检查D3DPRIMCAPS结构中的D3DPRASTERCAPS_ANISOTROPY标志,以确定各向异性度的可能的范围。

 

 

4.4 Mipmap

纹理过滤

纹理过滤

 

  Mipmap纹理技术用来降低场景渲染的时间消耗。同时也提高了场景的真实感。但它的缺点是要占用大量的内存空间。

  下面我们来讨论

mipmap纹理技术的有关内容:

  • 4.4.1

  • 什么是mipmap
  • 创建一系列mipmap
  • 选择和显示Mipmap
  • 选择和显示Mipmap

 

 

 

4.4.1 什么是mipmap

  一个

4.4.1 什么是mipmap

  一个

mipmap就是一系列的纹理,每一幅纹理都与前一幅是相同的图样,但是分辨率都要比前一幅有所降低。mipmap中的每一幅或者每一级图象的高和宽都比前一级小二分之一。Mipmap并不一定必须是正方形。

  高分辨率的

mipmap图象用于接近观察者的物体。当物体逐渐远离观察者时,使用低分辨率的图象。Mipmap可以提高场景渲染的质量,但是它的内存消耗却很大。

 

  Direct3Dmipmap描绘成一系列相互联系的表面。高分辨率的纹理位于开始处,并与下一级纹理相互联系。以此类推,纹理相互联系,逐渐排列到分辨率最小的一级。

  下面这套插图显示了这样的一个例子。这套纹理是一个三维场景中一个集装箱的标签。当我们创建了一个

mipmap时,分辨率最高的一幅纹理就是这一套纹理的第一个。这套mipmap中的每一个纹理宽高都是前一个纹理宽高的二分之一。这样,最大分辨率的纹理是256x256,接下来的纹理就是128x128,最后一个纹理就是64x64

  我们有一个能看到这个标签的最大距离。如果观察者从远处向标签走近,那么场景中首先会显示最小的一幅纹理,它的大小是

64x64的。

pic82.gif (3304 bytes)

  当观察者走进标签时,我们就使用更高分辨率一幅纹理:

 

pic83.gif (8944 bytes)

  当观察者走到允许的最近距离时,我们使用分辨率最高的那幅纹理:

pic84.gif (19673 bytes)

  这是方法能够模拟纹理的透视效果并能够减少处理时的计算量。与将一幅纹理用于不同的分辨率相比,这种方法更加快速。

 

  Direct3D能够访问mipmap中与我们想要输出的分辨率最接近的那个纹理设置,并将像素映射到它的纹理像素空间中。如果最终图象的分辨率在mipmap纹理的分辨率的中间,那么Direct3D会对两幅纹理中的纹理像素进行检查,并将它们的颜色值进行融合。

  如果要使用

mipmap,首先要创建一套mipmap。详细内容见“创建一系列mipmap”。如果程序使用的使纹理句柄,那么就必须将mipmap选择作为当前纹理。如果使用纹理接口指针,那么就要将mipmap选择作为当前纹理设置中的第一个纹理。详细内容见“多纹理融合”。

接下来,程序要设置用来对纹理像素采样的过滤方法。

Mipmap过滤最快的方法就是让Direct3D选择最近的纹理像素。我们用D3DTFP_POINT枚举值来选择这一方法。如果程序使用D3DTFP_LINEAR枚举值,可以得到更好的过滤效果。它会选择最近的mipmap,然后找到当前像素映射在纹理中的位置,计算这个位置周围纹理像素的加权平均。

 

 

 

4.4.2 创建一系列Mipmap

4.4.2 创建一系列Mipmap

  要创建一个表示

mipmap中某一级的表面,需要在DDSURFACEDESC结构中声明DDSCAPS_MIPMAPDDSCAPS_COMPLEX标志,并将这个结构传递给IDirectDraw4::CreateSurface方法。由于所有的mipmap也是纹理,因此也要声明DDSCAPS_TEXTURE标志。

  我们也可以自己来创建

mipmap中的每一级,然后使用IDirectDrawSurface4::AddAttachedSurface方法将它们链接在一起。但是我们并不推荐使用这样的方法。许多3-D硬件都对IDirectDraw4::CreateSurface方法优化了它们的驱动程序。因此,通过调用IDirectDrawSurface4::AddAttachedSurface来建立mipmap链接的程序可能会发现mipmapping没有想象中的那么快捷。

  下面的例子向我们展示了如何使用

IDirectDraw4::CreateSurface方法来创建一个mipmap链接,这个mipmap分为5级,大小分别为256×256128×12864×6432×3216×16

 


// This code fragment assumes that the variable lpDD is a
// valid pointer to a DirectDraw interface.

DDSURFACEDESC ddsd;
LPDIRECTDRAWSURFACE4 lpDDMipMap;
ZeroMemory(&ddsd, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_MIPMAPCOUNT;
ddsd.dwMipMapCount = 5;
ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_MIPMAP | DDSCAPS_COMPLEX;
ddsd.dwWidth = 256UL;
ddsd.dwHeight = 256UL;

 

ddres = lpDD->CreateSurface(&ddsd, &lpDDMipMap);
if (FAILED(ddres))

ddres = lpDD->CreateSurface(&ddsd, &lpDDMipMap);
if (FAILED(ddres))

 …… …… 

  在用

IDirectDraw4::CreateSurface方法创建一系列表面时,我们可以忽略mipmap的级数,这样每一级都是前一级大小的二分之一,直到最小的尺寸大小为止。我们也可以忽略高和宽,这样IDirectDraw4::CreateSurface就会创建我们所声明的级数,并将最小一级的大小设为1×1

注:一个mipmap链接中的每一个表面的大小都是链接中前一个表面大小的二分之一。如果一mipmap中最顶端一级的大小为256

×128,那么第二级的大小就是128×64,第三级为64×32,直到2×1为止。如果你声明了dwWidth和dwHeight成员的大小,就要注意一些限制条件。也就是要注意,在dwMipMapCount中声明的级数大小不能使任何一级mipmap的高或宽的值小于1。我们来看一个简单的最顶端一级大小为4×2的mipmap表面:dwMipMapCount所允许的最大值为2。任何大于2的值都会使高或宽变成小数,这是不允许的。

  创建了

mipmap表面之后,需要将表面与一个纹理相互联系起来。如果使用纹理句柄,就可以使用前面在“创建一个纹理句柄”中介绍的方法。如果使用的是纹理接口指针,请看“获得一个纹理接口指针”部分。

 

 

 

4.4.3 选择并显示Mipmap

  如果程序使用纹理句柄,就要将

mipmap纹理的句柄指派为当前纹理。详细内容见“当前纹理”部分。

  如果程序使用纹理接口指针,就要将

mipmap纹理设置作为当前纹理列表的第一个纹理。详细内容见“多纹理融合”部分。

  程序选择了

mipmap纹理设置之后,it must assign values from the D3DTEXTUREFILTER enumerated type to the D3DRENDERSTATE_TEXTUREMAG and D3DRENDERSTATE_TEXTUREMIN render states.然后,Direct3D会自动执行mipmap纹理过滤。

  程序也可以自己来设置

mipmap表面的链接,这是要使用IDirectDrawSurface4::GetAttachedSurface方法,并要在DDSCAPS结构中声明DDSCAPS_MIPMAPDDSCAPS_TEXTURE标志。下面的例子中展示了这一过程:


LPDIRECTDRAWSURFACE lpDDLevel, lpDDNextLevel;
DDSCAPS ddsCaps;
HRESULT ddres;

 

lpDDLevel = lpDDMipMap;
lpDDLevel->AddRef();
ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_MIPMAP;
ddres = DD_OK;
while (ddres == DD_OK)
{
 
// Process this level.
 
ddres = lpDDLevel->GetAttachedSurface( &ddsCaps, &lpDDNextLevel);
 
lpDDLevel->Release();
 
lpDDLevel = lpDDNextLevel;
}

 

if ((ddres != DD_OK) && (ddres != DDERR_NOTFOUND))
{
 
// Code to handle the error goes here
}

  程序还需要自己实现一个

mipmap链接来将位图数据加载到链接中的每一个表面。

 

  Direct3D会明确保存一个mipmap链接中的级数。当程序获得一个mipmap的表面描述时(调用IDirectDrawSurface4::LockIDirectDrawSurface4::GetSurfaceDesc方法),DDSURFACEDESC结构的dwMipMapCount成员就获得了mipmap的级数,包括最顶端一级。对于mipmap中的那些不是最顶端的级来说,dwMipMapCount成员详细说明了链接中的级数。

 

 

 

5.  纹理Wrapping

  下面我们来讨论纹理

Wrapping

  • 5.1

  • 什么是纹理Wrapping
  • 5.2
  • 使用纹理Wrapping
  • 使用纹理Wrapping

  注:不要将纹理

Wrapping与有相似名称的纹理寻址模式相混淆。

 

 

5.1 什么是纹理Wrapping

  简单来说,纹理

Wrapping就是要改变Direct3D光栅使用纹理坐标对有纹理的多边形进行光栅操作的基本方式。我们对一个多边形进行光栅操作时,系统在每一个多边形顶点的纹理坐标之间进行内插运算,这样来决定在多边形的每个像素上所使用的纹理像素。通常,系统将纹理看作一个二维平面,在这个平面内AB两点间的连线上进行内插。如果点AUV坐标为(0.8, 0.3),点B(0.1,.9),那么进行内插的连线就如下图所示:

pic85.gif (2608 bytes)

  注意,上图中

AB两点的最短连线穿过了纹理的中间部分。UV纹理Wrapping的使用会影响Direct3DUV方向上对纹理坐标间最短连线的选取。现在我们假定0.01.0重合,那么通过定义,纹理Wrapping就会导致光栅在纹理坐标设置之间来选择最短距离。我们可以认为一个方向上的纹理Wrapping就是让系统认为将一个纹理包裹在了一个圆筒上,就象下图中那样:

pic86.gif (3890 bytes)

  上图中我们在

U方向上进行了Wrapping,它影响了系统对纹理坐标进行的内插操作。我们使用同样的两个点AB,可以看到,它们之间最短的连线不再通过纹理的中间部分;它现在穿越了0.01.0所在的交界线。沿V方向的Wrapping与它相似,只不过纹理所包裹的圆筒横躺在地上。UV方向上同时进行Wrapping比较复杂,这时我们可以将纹理想象成一个园环面或者是面包圈的形状。

  纹理

Wrapping最实际的应用就是执行环境映射(environment mapping)。通常,使用了纹理环境映射的对象看起来具有反射性,也就是能够表现出场景中这个对象周围环境的镜像图象。下面我们来看一个有四堵墙的空间,墙上分别绘制了一个字母:RGBY,以及相应的颜色:红、绿、蓝和黄,如下图所示:

. pic87.gif (7471 bytes)

  我们可以想象这个空间的天花板由一个有四个面的反射的柱子支撑着。将环境映射纹理映射到柱子上比较简单,但是要将纹理中的字母和颜色映射到墙上却并不很容易。下图展示了一个柱子的线框,并将所用的纹理坐标列在了柱子顶上(图中的虚线表示纹理的边缘):

 

pic88.gif (4291 bytes)

  我们在U方向上进行Wrapping,并假定U坐标的0.01.0的位置相互重叠,那么我们的得到的图象如下所示:

pic89.gif (11317 bytes)

  如果不进行纹理

Wrapping,光栅就不会进行内插,也就不能产生出一个可信的、反射的图象。而且,柱子前面的区域的纹理在U坐标0.1750.875之间进行了压缩,因为它们包括了纹理的中间部分。

 

 

5.2 使用纹理Wrapping

5.2 使用纹理Wrapping

  使纹理

Wrapping的过程根据使用的Direct3D设备接口不同而不同。如果程序使用IDirect3DDevice3接口,就要对多纹理层叠中的每个纹理分别进行纹理Wrapping。这样,就要调用IDirect3DDevice3::SetRenderState方法来使纹理Wrapping有效,将D3DRENDERSTATE_WRAP0D3DRENDERSTATE_WRAP7枚举值作为第一个参数来确定要设置哪个平台的Wrapping状态,在第二个参数中声明D3DWRAP_UD3DWRAP_V标志使Wrapping在相应的方向上有效,也可以将两个方向混合使用。要使一个纹理stage的纹理Wrapping无效,可以将相应的渲染状态值设置为0

  如果程序使用

IDirect3DDevice2IDirect3DDevice接口,可以调用SetRenderState方法使Wrapping有效;但是,这些接口不支持D3DRENDERSTATE_WRAP0D3DRENDERSTATE_WRAP7。相反,它们使用D3DRENDERSTATE_WRAPUD3DRENDERSTATE_WRAPV作为第一个参数。将第二个参数设置为TRUE使Wrapping生效,如果设置为FALSE则使Wrapping无效。

  注:IDirect3DDevice3接口不接受遗留的D3DRENDERSTATE_WRAPU和D3DRENDERSTATE_WRAPV渲染状态,它们被D3DRENDERSTATE_WRAP0到D3DRENDERSTATE_WRAP7所取代。这些老的渲染状态在被传递给SetRenderState的IDirect3DDevice3时,会影响stage 0的U、V纹理Wrapping。

6.  纹理融合

 

  Direct3D可以将一个纹理与图元的颜色进行融合来产生透明效果,也可以将多个纹理融合到一个图元上。下面我们来讨论纹理融合的实现,分以下几个部分:

  • 6.1 Alpha

  • 纹理融合
  • 6.2
  • 多通道(Multipass)纹理融合
  • 6.3
  • 多纹理融合
  • 6.4
  • 纹理光线映射
  • 纹理光线映射

  在程序中使用纹理融合之前,我们要先检查所用的硬件是否支持使用纹理融合。我们可以在

D3DPRIMCAPS结构的dwTextureCaps成员中找到相关的信息。要想详细了解如何查询硬件的纹理融合能力,请看IDirect3DDevice3::GetCapsD3DDEVICEDESC

 

6.1 Alpha纹理融合

 

  Direct3D渲染一个图元时,总是根据图元的材质和有关的光线信息来产生图元的颜色。如果程序中纹理融合有效,Direct3D就必须将一个或多个纹理的纹理像素颜色与图元的当前颜色进行融合。Direct3D用下面的公式来决定一个图元图象中每个像素最终的颜色:

 

  FinalColor = TexelColor * SourceBlendFactor + PixelColor * DestBlendFactor

  上面的公式中,FinalColor是最后输出到目标渲染表面的像素颜色;TexelColor表示对应于当前像素的纹理像素的颜色(有关Direct3D将像素映射到纹理像素的内容见“纹理过滤”);SourceBlendFactor是一个计算得到的值,它决定将纹理像素颜色的百分之多少应用于最后的颜色;PixelColor是图元图象中当前像素的颜色;DestBlendFactor用来决定当前像素颜色的百分之多少用于最后的颜色。SourceBlendFactorDestBlendFactor的范围从0.01.0,包括0.01.0

  从上式中我们可以看到,当SourceBlendFactor0.0并且DestBlendFactor1.0时,纹理是完全透明的。如果它们是其他的值,那么得到的纹理就会有不同程度的透明。

  纹理中的每个纹理像素都有一个红、绿和蓝颜色值。缺省情况下,Direct3Dalpha值作为SourceBlendFactor。因此,程序可以通过设置纹理的alpha值来控制透明度。

  程序可以用D3DRENDERSTATE_SRCBLENDD3DRENDERSTATE_DESTBLEND枚举值来控制融合因子。要使用它们,就要引用IDirect3DDevice3::SetRenderState方法,并将D3DRENDERSTATE_SRCBLENDD3DRENDERSTATE_DESTBLEND作它的第一个参数,将D3DBLEND枚举类型的一个成员作为第二个参数。

 

6.2 多通道纹理融合

 

  Direct3D通过将多个纹理应用到图元上可以达到许多特殊的效果。我们最常用的形式就是多通道纹理融合。它的一个最通常的用法就是将阴影应用于图元。详细内容见“纹理的光线映射”。

  所有的Direct3D设备接口都支持多通道纹理融合。从IDirect3DDevice3接口开始,DirectX能够在一个通道里将多纹理应用到图元,当然要求用户的硬件支持者一功能。详细内容见“多纹理融合”。

  如果用户的硬件不支持多纹理融合,那么程序可以使用多通道纹理融合来达到相同的视觉效果。但是,我们将不能继续维持在使用多纹理映射所能达到的帧速率。

  通过引用IDirect3DDevice3::SetRenderState方法可以使多通道纹理融合有效,同时要将D3DRENDERSTATE_ALPHABLENDENABLE作为第一个参数,将第二个参数设为TRUE使它有效,

设为FALSE使它无效。

  纹理融合有效之后,我们还要根据所要达到的效果设置相应的源和目的融合因子。程序通过调用IDirect3DDevice3::SetRenderState来控制源融合因子,并将D3DRENDERSTATE_SRCBLEND作为它的第一个参数;如果将第一个参数设为D3DRENDERSTATE_DESTBLEND,就可以控制目的融合因子了,第二个参数要设置为相应的D3DBLEND枚举类型的成员。

  调用IDirect3DDevice3::SetRenderState方法,并将第一个参数设置为D3DRENDERSTATE_TEXTUREMAPBLEND可以来设置融合操作,第二个参数必须是D3DTEXTUREBLEND枚举类型的成员。

  在每一个通道上,程序都要设置当前纹理。它的纹理像素颜色将会和帧缓存中现有的像素颜色进行融合。

 

6.3 多纹理融合

  使用IDirect3D3IDirect3DDevice3接口,Direct3D可以在一个通道内将最多8个纹理融合到图元上。多纹理融合的使用能够很大程度的提高程序执行时的帧速。程序使用多纹理融合可以在一个通道内使用纹理、阴影、镜面光、漫射光和其他一些特殊效果。

pic90.gif (3244 bytes)

  要融合多个纹理,程序将纹理分配到当前纹理设置中,然后创建纹理融合

stage。下面我们分几个部分来进行讨论:

  • 6.3.1
  • 纹理stage和纹理融合级联
  • 6.3.2
  • 纹理融合操作与变元
  • 6.3.3
  • 分配当前纹理
  • 6.3.4
  • 创建融合stage
  • 6.3.5
  • 遗留的融合模式与纹理stage
  • 遗留的融合模式与纹理stage

 

 

6.3.1 纹理stage与纹理融合级联

 

  Direct3通过使用“纹理stage”支持单通道多纹理融合。一个纹理stage包含两个变元(argument),并对他们执行融合操作,将结果传递给下一个操作或光栅操作。一个纹理stage如下图所示:

pic91.gif (10790 bytes)

  上图中,纹理

stage使用指定的操作符(operator)对两个变元进行融合。通常的操作包括对变元的颜色或alpha成分进行简单的调制(modulation)或相加(addition),但是现在也支持多过24个的操作。平台的边缘可以是相关的纹理、迭代的(iterated)颜色或alpha值(在Gouraud明暗处理时进行迭代)、任意颜色和alpha或者是前一级纹理stage的结果。

  纹理

stage中的边缘和操作的联合实际上定义了一种简化的基于流程的融合语言。上一级stage的结果传递给另外一级stage,然后再依次传递下去。这样一级一级的传递结果,最终到达光栅进行多边形的光栅操作,我们把这一过程称为“纹理融合级联”。右图展示了单独的纹理stage如何来组成纹理融合级联:

  一个设备中的每个

stage都有一个基于0的索引。Direct3D接受最多8个融合stage,并且要通过检查设备的能力来决定当前的硬件支持使用几个纹理stage。第一个stage的索引值为0,第二个为1,直到7为止。

  只使用我们需要使用的

stage数量,缺省时,不用的融合stage是无效的。因此,如果程序仅使用了前两个stage,那么就只需要设置stage 01的操作和变元,而不用管其他的。

性能优化

:如果在程序中根据不同的情况使用不同数量的渲染平台,那么不需要将前面使用过的所有平台都明确的声明为无效。如果使第一个没有使用的平台的颜色操作无效,那么所有它以后的平台都将无法使用。你可以将第一个纹理

stage的纹理映射与颜色操作一起设置为无效。

 

 

6.3.2 纹理融合操作与变元

  程序将一个纹理融合

6.3.2 纹理融合操作与变元

  程序将一个纹理融合

stage与当前纹理设置中的每个纹理相联系。正如前面我们所讨论的那样,Direct3D依次估计每一个融合stage,以第一个纹理为开始,以第8个纹理为结束。

 

  Direct3D将当前纹理设置中的每个纹理的信息应用到与之相关的融合stage。程序通过IDirect3DDevice3::SetTexture State方法来控制使用一个给定纹理中的信息。我们可以分别为颜色与alpha通道设置操作,每操作使用两个变元。使用D3DTSS_COLOROP stage状态来声明颜色通道操作,D3DTSS_ALPHAOP声明alpha操作,它们都使用D3DTEXTUREOP枚举类型中的值。

  纹理融合变元使用

D3DTEXTURE stage STATETYPE枚举类型的 D3DTSS_COLORARG1D3DTSS_COLORARG2D3DTSS_ALPHARG1D3DTSS_ALPHARG2成员。使用纹理变元标志来声明相应的变元值。

注:通过将stage的颜色操作设置为D3DTOP_DISABLE,我们可以使一个纹理stage无效——包括级联中它后面的任何纹理融合stage。设置颜色操作无效同时也使alpha操作无效。

 

 

6.3.3 分配当前纹理

6.3.3 分配当前纹理

 

  Direct3D作多可以将8个纹理依次融合到图元上。在当前纹理设置中,只能使用以纹理接口指针形式创建的纹理。

  程序调用

IDirect3DDevice3::SetTexture方法将纹理分配到当前纹理集中。第一个参数必需是一个从07的数字,第二个参数是纹理接口指针。

  下面我们来看一个例子:


// This code fragment assumes that the variable lpd3dDev is a valid
// pointer to an IDirect3D3 interface and lpd3dTexture is a valid
// pointer to an IDirect3DTexture2 interface.

// Set the third texture.
lpd3dDev->SetTexture(2, lpd3dTexture);

 

注:软件设备不支持一次将一个纹理分配到多个纹理stage

 

 

6.3.4 创建融合stage

6.3.4 创建融合stage

  一个纹理

stage就是一系列纹理操作以及它们的变元。创建融合stage时,程序调用IDirect3DDevice3::SetTexture平台State函数。第一次调用声明要执行的操作,另两次调用定义变元。下面的代码就是创建融合stage的例子:

  纹理中的纹理像素数据包含了颜色和alpha值。程序可以在融合stage上同时定义颜色和alpha操作。每个操作都有自己的变元。

  下面这些不是

Direct3D API中的一部分,但是我们仍然可以使用这些宏来创建纹理融合stage


// This example assumes that lpD3DDev is a valid pointer to an
// IDirect3DDevice3 interface.

// Set the operation for the 1st texture.
lpD3DDev->SetTexture
平台State(0,D3DTSS_COLOROP,D3DTOP_ADD);

 

// Set arg1 for the texture operation.
lpD3DDev->SetTexture
平台State(0,            
// First texture
              D3DTSS_COLORARG1,  
// Set color arg 1
              D3DTA_TEXTURE);    // Color arg 1 value

 

// Set arg2 for the texture operation.
lpD3DDev->SetTexture
平台State(0,        
// First texture
               D3DTSS_COLORARG2,  
// Set color arg 2
               D3DTA_DIFFUSE);     
// Color arg 2 value

// Set arg2 for the texture operation.
lpD3DDev->SetTexture
平台State(0,        
// First texture
               D3DTSS_COLORARG2,  
// Set color arg 2
               D3DTA_DIFFUSE);     
// Color arg 2 value

 

 

6.3.5 遗留的融合模式与纹理stage

 

6.3.5 遗留的融合模式与纹理stage

 

  Direct3D仍然支持纹理融合渲染状态,D3DRENDERSTATE_TEXTUREMAPBLEND,但是它所提供的融合模式不能与基于纹理融合的纹理stage混合使用。但是我们可以使用纹理stage“建立”我们自己的遗留的融合模式的等价物。

  下面展示了遗留的融合模式(由

D3DTEXTUREBLEND枚举类型的成员来确认),后面都跟着通过纹理stage状态设置相应的融合的简短的例子。(对于所有的例子,g_lpDev使一个指向IDirect3DDevice3接口的正确的指针):


#define SetTextureColor平台( dev, i, arg1, op, arg2 )    /
dev->SetTexture
平台State( i, D3DTSS_COLOROP, op);   /
dev->SetTexture
平台State( i, D3DTSS_COLORARG1, arg1 ); /
dev->SetTexture
平台State( i, D3DTSS_COLORARG2, arg2 );

 

#define SetTextureAlpha平台( dev, i, arg1, op, arg2 )    /
dev->SetTexture
平台State( i, D3DTSS_ALPHAOP, op);  
   /
dev->SetTexture
平台State( i, D3DTSS_ALPHARG1, arg1 );  
/
dev->SetTexture
平台
State( i D3DTSS_ALPHARG2, arg2 );

#define SetTextureAlpha平台( dev, i, arg1, op, arg2 )    /
dev->SetTexture
平台State( i, D3DTSS_ALPHAOP, op);  
   /
dev->SetTexture
平台State( i, D3DTSS_ALPHARG1, arg1 );  
/
dev->SetTexture
平台
State( i D3DTSS_ALPHARG2, arg2 );


D3DTBLEND_ADD
g_lpDev->SetTexture
平台State(0, COLOROP, D3DTOP_ADD);
g_lpDev->SetTexture
平台State(0, COLORARG1, D3DTA_TEXTURE);
g_lpDev->SetTexture
平台State(0, COLORARG2, D3DTA_DIFFUSE);
g_lpDev->SetTexture
平台State(0, ALPHAOP, D3DTOP_SELECTARG2);
g_lpDev->SetTexture
平台State(0, ALPHAARG2, D3DTA_DIFFUSE);

 

D3DTBLEND_COPY and D3DTBLEND_DECAL
g_lpDev->SetTexture
平台State(0, COLOROP, D3DTOP_SELECTARG1);
g_lpDev->SetTexture
平台
State(0, COLORARG1, D3DTA_TEXTURE);
g_lpDev->SetTexture
平台
State(0, ALPHAOP, D3DTOP_SELECTARG1);
g_lpDev->SetTexture
平台State(0, ALPHAARG2, D3DTA_TEXTURE);

 

D3DTBLEND_DECALALPHA
g_lpDev->SetTexture
平台State(0, COLOROP, D3DTOP_BLENDTEXTUREALPHA);
g_lpDev->SetTexture
平台
State(0, COLORARG1, D3DTA_TEXTURE);
g_lpDev->SetTexture
平台
State(0, COLORARG2, D3DTA_DIFFUSE);
g_lpDev->SetTexture
平台
State(0, ALPHAOP, D3DTOP_SELECTARG2);
g_lpDev->SetTexture
平台State(0, ALPHAARG2, D3DTA_DIFFUSE);

 

D3DTBLEND_MODULATE
g_lpDev->SetTexture
平台State(0, COLOROP, D3DTOP_MODULATE);
g_lpDev->SetTexture
平台
State(0, COLORARG1, D3DTA_TEXTURE);
g_lpDev->SetTexture
平台State(0, COLORARG2, D3DTA_DIFFUSE);

 

if ( the_texture_has_an_alpha_channel )
{
 g_lpDev->SetTexture平台
State(0, ALPHAOP, D3DTOP_SELECTARG1);
 g_lpDev->SetTexture平台
State(0, ALPHAARG1, D3DTA_TEXTURE);
}
else
{
 g_lpDev->SetTexture平台
State(0, ALPHAOP, D3DTOP_SELECTARG2);
 g_lpDev->SetTexture平台
State(0, ALPHAARG2, D3DTA_DIFFUSE);
}

 

D3DTBLEND_MODULATEALPHA
g_lpDev->SetTexture
平台State(0, COLOROP, D3DTOP_MODULATE);
g_lpDev->SetTexture
平台
State(0, COLORARG1, D3DTA_TEXTURE);
g_lpDev->SetTexture
平台
State(0, COLORARG2, D3DTA_DIFFUSE);
g_lpDev->SetTexture
平台
State(0, ALPHAOP, D3DTOP_MODULATE);
g_lpDev->SetTexture
平台
State(0, ALPHAARG1, D3DTA_TEXTURE);
g_lpDev->SetTexture
平台State(0, ALPHAARG2, D3DTA_DIFFUSE);

 

D3DTBLEND_DECALMASK and D3DTBLEND_MODULATEMASK
Not supported in DirectX 6.0.


D3DTBLEND_ADD
g_lpDev->SetTexture
平台State(0, COLOROP, D3DTOP_ADD);
g_lpDev->SetTexture
平台State(0, COLORARG1, D3DTA_TEXTURE);
g_lpDev->SetTexture
平台State(0, COLORARG2, D3DTA_DIFFUSE);
g_lpDev->SetTexture
平台State(0, ALPHAOP, D3DTOP_SELECTARG2);
g_lpDev->SetTexture
平台State(0, ALPHAARG2, D3DTA_DIFFUSE);

 

D3DTBLEND_COPY and D3DTBLEND_DECAL
g_lpDev->SetTexture
平台State(0, COLOROP, D3DTOP_SELECTARG1);
g_lpDev->SetTexture
平台
State(0, COLORARG1, D3DTA_TEXTURE);
g_lpDev->SetTexture
平台
State(0, ALPHAOP, D3DTOP_SELECTARG1);
g_lpDev->SetTexture
平台State(0, ALPHAARG2, D3DTA_TEXTURE);

 

D3DTBLEND_DECALALPHA
g_lpDev->SetTexture
平台State(0, COLOROP, D3DTOP_BLENDTEXTUREALPHA);
g_lpDev->SetTexture
平台
State(0, COLORARG1, D3DTA_TEXTURE);
g_lpDev->SetTexture
平台
State(0, COLORARG2, D3DTA_DIFFUSE);
g_lpDev->SetTexture
平台
State(0, ALPHAOP, D3DTOP_SELECTARG2);
g_lpDev->SetTexture
平台State(0, ALPHAARG2, D3DTA_DIFFUSE);

 

D3DTBLEND_MODULATE
g_lpDev->SetTexture
平台State(0, COLOROP, D3DTOP_MODULATE);
g_lpDev->SetTexture
平台
State(0, COLORARG1, D3DTA_TEXTURE);
g_lpDev->SetTexture
平台State(0, COLORARG2, D3DTA_DIFFUSE);

 

if ( the_texture_has_an_alpha_channel )
{
 g_lpDev->SetTexture平台
State(0, ALPHAOP, D3DTOP_SELECTARG1);
 g_lpDev->SetTexture平台
State(0, ALPHAARG1, D3DTA_TEXTURE);
}
else
{
 g_lpDev->SetTexture平台
State(0, ALPHAOP, D3DTOP_SELECTARG2);
 g_lpDev->SetTexture平台
State(0, ALPHAARG2, D3DTA_DIFFUSE);
}

 

D3DTBLEND_MODULATEALPHA
g_lpDev->SetTexture
平台State(0, COLOROP, D3DTOP_MODULATE);
g_lpDev->SetTexture
平台
State(0, COLORARG1, D3DTA_TEXTURE);
g_lpDev->SetTexture
平台
State(0, COLORARG2, D3DTA_DIFFUSE);
g_lpDev->SetTexture
平台
State(0, ALPHAOP, D3DTOP_MODULATE);
g_lpDev->SetTexture
平台
State(0, ALPHAARG1, D3DTA_TEXTURE);
g_lpDev->SetTexture
平台State(0, ALPHAARG2, D3DTA_DIFFUSE);

 

D3DTBLEND_DECALMASK and D3DTBLEND_MODULATEMASK
Not supported in DirectX 6.0.

 

 

6.4 纹理的光线映射

  对于实际渲染场景的程序,必须要考虑光源的影响。尽管平面明暗处理与

6.4 纹理的光线映射

  对于实际渲染场景的程序,必须要考虑光源的影响。尽管平面明暗处理与

Gouraud明暗处理已经时非常有用的工具了,但是对于我们所需要的还不够。Direct3D支持多通道和多纹理融合。这些技术的应用可以使场景看起来比只使用明暗处理方法时更加真实。通过使用光线映射,程序可以将光照区域与阴影效果添加到图元上。

  一个光线映射就是一个或一组纹理,它们包含了场景中的光线信息。我们可以将光线信息存储在光线映射的

alpha值中,也可以存储在颜色值中,当然也可以同时存储在它们之中。

  如果使用多通道纹理融合来执行光线映射,那么程序应该在第一个通道将光线映射渲染到图元上,使用第二个通道来渲染基本的纹理。但是在使用镜面光映射(

specular light mapping)时,不能按照这样的顺序,而要首先渲染基本纹理,然后在加入光线映射。

  多纹理融合可以使我们在一个通道内渲染光线映射和基本纹理。如果用户的硬件支持多纹理融合,那么在执行光线映射时,就因该充分利用硬件的能力,它会明显提高程序的性能。

  使用光线映射,

Direct3D程序可以在渲染一个图元时获得不同的光线效果。程序不能只在场景中映射单色和彩色光线,可以加入一些细节的东西,如镜面高光和漫射光线等。

  下面我们分几个部分进行详细的讨论:

  • 6.4.1
  • 单色光映射
  • 6.4.2
  • 彩色光映射
  • 6.4.3
  • 镜面光映射
  • 6.4.4
  • 漫射光映射

     

     

  • 漫射光映射

     

     

6.4.1 单色光映射

  一些早期的3-D加速板不支持使用目的像素的alpha值进行纹理融合。它们也不支持多纹理融合操作。如果你的程序要使用这样的硬件,那么就只能使用多通道纹理融合来执行单色光映射。

  要执行单色光映射,程序必须在光线映射纹理的alpha数据中存储光线信息。程序使用Direct3D的纹理过滤能力将图元图象的每个像素映射到光线映射中相应的纹理像素。它将源融合因子设置为相应纹理像素的alpha值。

  下面的代码展示了如何使用单色光映射:

 


// This example assumes that lpD3DDev is a valid pointer to an
// IDirect3DDevice3 interface and that lptexLightMap is a valid
// pointer to a texture that contains monochrome light map data.
// Set the light map texture as the current texture.

lpD3DDev->SetTexture(0,lptexLightMap);
// Set the color operation.
lpD3DDev->SetTexture
平台State(0,D3DTSS_COLOROP,D3DTOP_SELECTARG1);
// Set argument 1 to the color operation.
lpD3DDev->SetTexture
平台State(0,D3DTSS_COLORARG1,D3DTA_TEXTURE | D3DTA_ALPHAREPLICATE);


// This example assumes that lpD3DDev is a valid pointer to an
// IDirect3DDevice3 interface and that lptexLightMap is a valid
// pointer to a texture that contains monochrome light map data.
// Set the light map texture as the current texture.

lpD3DDev->SetTexture(0,lptexLightMap);
// Set the color operation.
lpD3DDev->SetTexture
平台State(0,D3DTSS_COLOROP,D3DTOP_SELECTARG1);
// Set argument 1 to the color operation.
lpD3DDev->SetTexture
平台State(0,D3DTSS_COLORARG1,D3DTA_TEXTURE | D3DTA_ALPHAREPLICATE);

 

  因为不支持目的alpha融合的显示适配器通常都不支持多纹理融合,因此,上面例程中将光线映射设置为第一个纹理,这对于所有的3-D加速卡都是适用的。例子中,纹理融合stage的颜色操作是将纹理数据与图元上的颜色相融合,然后选择第一个纹理和图元上已有的颜色作为输入数据。

6.4.2 彩色光映射

  使用彩色光映射可以使场景更加真实。彩色光映射使用光线映射的RGB数据作为它的光线信息。我们来看下面的例子:

 


// This example assumes that lpD3DDev is a valid pointer to an
// IDirect3DDevice3 interface and that lptexLightMap is a valid
// pointer to a texture that contains RGB light map data.
// Set the light map texture as the 1st texture.
lpD3DDev->SetTexture(0, lptexLightMap);
lpD3DDev->SetTexture
平台
State(0,D3DTSS_COLOROP, D3DTOP_MODULATE);
lpD3DDev->SetTexture
平台State(0,D3DTSS_COLORARG1, D3DTA_TEXTURE);
lpD3DDev->SetTexture
平台State(0,D3DTSS_COLORARG2,D3DTA_DIFFUSE);


// This example assumes that lpD3DDev is a valid pointer to an
// IDirect3DDevice3 interface and that lptexLightMap is a valid
// pointer to a texture that contains RGB light map data.
// Set the light map texture as the 1st texture.
lpD3DDev->SetTexture(0, lptexLightMap);
lpD3DDev->SetTexture
平台
State(0,D3DTSS_COLOROP, D3DTOP_MODULATE);
lpD3DDev->SetTexture
平台State(0,D3DTSS_COLORARG1, D3DTA_TEXTURE);
lpD3DDev->SetTexture
平台State(0,D3DTSS_COLORARG2,D3DTA_DIFFUSE);

 

  例子中将光线映射设置为第一个纹理,然后将第一融合stage的状态设置为对输入纹理数据进行调制(modulate)。它使用第一个纹理和图元的当前颜色作为调制操作的两个变元。

 

6.4.3 镜面光映射

  执行镜面光映射时,首先将镜面光映射与图元上已有的纹理进行调制,然后加入单色或RGB光线映射,下面的代码显示了这一过程:

 


// This example assumes that lpD3DDev is a valid pointer to an
// IDirect3DDevice3 interface.
// lptexBaseTexture is a valid pointer to a texture.
// lptexSpecLightMap is a valid pointer to a texture that contains RGB
// specular light map data.
// lptexLightMap is a valid pointer to a texture that contains RGB
// light map data.
// Set the base texture.
lpD3DDev->SetTexture(0,lptexBaseTexture );
// Set the base texture operation and args
lpD3DDev->SetTexture
平台State(0,D3DTSS_COLOROP,D3DTOP_MODULATE );
lpD3DDev->SetTexture
平台State(0,D3DTSS_COLORARG1, D3DTA_TEXTURE );
lpD3DDev->SetTexture
平台State(0,D3DTSS_COLORARG2, D3DTA_DIFFUSE );

 

// Set the specular light map.
lpD3DDev->SetTexture(1,lptexSpecLightMap );
// Set the specular light map operation and args
lpD3DDev->SetTexture
平台State(1,D3DTSS_COLOROP,D3DTOP_MODULATE );
lpD3DDev->SetTexture
平台State(1,D3DTSS_COLORARG1, D3DTA_TEXTURE );
lpD3DDev->SetTexture
平台State(1,D3DTSS_COLORARG2, D3DTA_CURRENT );

 

// Set the RGB light map.
lpD3DDev->SetTexture(2,lptexLightMap);
// Set the RGB light map operation and args
lpD3DDev->SetTexture
平台State(2,D3DTSS_COLOROP, D3DTOP_ADD);
lpD3DDev->SetTexture
平台State(2,D3DTSS_COLORARG1, D3DTA_TEXTURE );
lpD3DDev->SetTexture
平台State(2,D3DTSS_COLORARG2, D3DTA_CURRENT );

// Set the RGB light map.
lpD3DDev->SetTexture(2,lptexLightMap);
// Set the RGB light map operation and args
lpD3DDev->SetTexture
平台State(2,D3DTSS_COLOROP, D3DTOP_ADD);
lpD3DDev->SetTexture
平台State(2,D3DTSS_COLORARG1, D3DTA_TEXTURE );
lpD3DDev->SetTexture
平台State(2,D3DTSS_COLORARG2, D3DTA_CURRENT );

 

 

6.4.4 漫射光映射

  当我们使用点光源照射一个不光滑的表面时,就会显示出漫射光反射。漫射光的亮度与对象离光源的距离和表面法向量与光源方向向量的夹角有关。

  程序可以使用纹理光线映射来模拟漫射光的效果,将漫射光映射加入到基本纹理中,如下例所示:


// This example assumes that lpD3DDev is a valid pointer to an
// IDirect3DDevice3 interface.
// lptexBaseTexture is a valid pointer to a texture.
// lptexDiffuseLightMap is a valid pointer to a texture that contains
// RGB diffuse light map data.
// Set the base texture.
lpD3DDev->SetTexture(0,lptexBaseTexture );

 

// Set the base texture operation and args
lpD3DDev->SetTexture
平台
State(0,D3DTSS_COLOROP,D3DTOP_MODULATE );
lpD3DDev->SetTexture
平台
State(0,D3DTSS_COLORARG1, D3DTA_TEXTURE );
lpD3DDev->SetTexture
平台State(0,D3DTSS_COLORARG2, D3DTA_DIFFUSE );

// Set the diffuse light map.
lpD3DDev->SetTexture(1,lptexDiffuseLightMap );

 

// Set the blend
平台.
lpD3DDev->SetTexture
平台
State(1, D3DTSS_COLOROP, D3DTOP_ADD );
lpD3DDev->SetTexture
平台
State(1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
lpD3DDev->SetTexture
平台
State(1, D3DTSS_COLORARG2, D3DTA_CURRENT );

// Set the blend

平台.
lpD3DDev->SetTexture
平台
State(1, D3DTSS_COLOROP, D3DTOP_ADD );
lpD3DDev->SetTexture
平台
State(1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
lpD3DDev->SetTexture
平台
State(1, D3DTSS_COLORARG2, D3DTA_CURRENT );

平台.
lpD3DDev->SetTexture
平台
State(1, D3DTSS_COLOROP, D3DTOP_ADD );
lpD3DDev->SetTexture
平台
State(1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
lpD3DDev->SetTexture
平台
State(1, D3DTSS_COLORARG2, D3DTA_CURRENT );

 

 

7.  纹理压缩

 

  DirectDraw提供了压缩表面的功能用于对3-D模型贴赋纹理。有关详细内容请看DirectDraw文档中的相关内容。

  程序创建了一个渲染设备之后,就可以决定是否支持使用

IDirect3DDevice3::EnumTextureFormats方法从纹理压缩表面执行纹理操作。这个方法要调用D3DEnumPixelFormatsCallback回调函数,它是由程序提供给每个像素格式的。如果枚举像素格式使用了DXT1DXT2DXT3DXT4DXT5特征码(FOURCCs),那么设备就可以直接从使用这些格式的压缩表面来执行纹理操作。如果这样的话,就可以调用IDirect3DDevice3::SetTexture方法来直接使用压缩纹理表面了。如果设备不支持压缩纹理表面,我们仍然可以将纹理数据存储在一个压缩格式的表面,但是在使用时必须先将它转化成支持的格式。DirectDrawblit方法,IDirectDrawSurface4::BltIDirectDrawSurface4::BltFast,可以自动将压缩格式转化为标准的RGBA格式。为了尽量减少信息损失,应该为目的像素格式选取最适合的压缩格式,例如ARGB:1555就应该选择DXT1,而ARGB:4444应该选择DXT3,因为DXT3包含了四位的alpha信息。

 

 

8.  自动纹理管理

8.  自动纹理管理

  简单来说,纹理管理就是决定在给定时间哪些纹理需要渲染,并确保这些纹理被加载到显存中的过程。通常,纹理管理要包含以下一些主要的任务:

  • 跟踪可用纹理内存的数量。
  • 计算当前哪些纹理需要进行渲染,哪些不需要。
  • 决定现有的纹理表面中哪个能够再次加载另一幅纹理图象,以及哪个表面应该被销毁并被新的纹理表面所取代。

  以前,

Direct3D程序要自己管理纹理。现在,在DirectX 6.0中,立即模式开始支持自动管理纹理,它能够有效的管理纹理,使纹理加载能有最佳的性能。(由Direct3D管理的纹理表面通常称为“被管理的纹理(managed textures)”。)

  在创建纹理时,可以请求对它们进行自动管理。要得到一个被管理的纹理,只需要在创建纹理表面时在相应的

DDSCAPS2结构的dwCaps2成员中包含DDSCAPS2_TEXTUREMANAG标志。注意,在你想要创建纹理的地方不允许进行声明——当创建一个被管理的纹理时,不能使用DDSCAPS_SYSTEMMEMORYDDSCAPS_VIDEOMEMORY标志。创建了被管理纹理之后,可以调用IDirect3DDevice3::SetTexture方法将它设置到一个纹理stage中。

 

  Direct3D根据需要自动将纹理加载到显存中。(系统可能将被管理的纹理安排在本地或非本地显存中,这要看非本地显存是否可用或其他因素而定。被管理的纹理被安排在哪里不会通知给程序,并且这在使用自动纹理管理时也是不需要知道的。)如果程序使用的纹理比显存空间所能容纳的多,那么Direct3D就会将老的纹理逐出显存,为新纹理腾出空间。如果你要再次使用被逐出的纹理,系统会使用最初的系统内存表面重新将纹理加载到显存cache中。重新加载纹理对于性能只有很小的影响。

  我们可以对纹理表面进行

blitting或锁定(locking)操作,这样可以动态的修改纹理的原始系统内存拷贝。当系统检查到一个“脏的”表面——执行完一个blit操作,或者当表面解锁(unlock)后——纹理管理会自动刷新纹理的显存拷贝。这种方法对性能的损耗与重新加载被逐出的纹理一样。

  当游戏进入新的一关时,程序可能会将所有被管理的纹理都从显存中冲刷掉。这时可以调用

IDirect3D3::EvictManagedTextures方法逐出所有的被管理纹理。在调用这个方法时,Direct3D会将所有的本地与非本地显存纹理销毁掉,只留下原始系统内存拷贝。

注:调用IDirect3DTexture2::GetHandle方法不能得到一个被管理纹理的纹理句柄。

 

 

 

9.  对于纹理的硬件考虑

9.  对于纹理的硬件考虑

  我们使用的硬件没有必要执行所有的

Direct3D接口提供的功能。所以在程序中,我们要检查正在使用的硬件,并调整渲染方法。

  许多

3-D加速卡都不支持将漫射迭代值(diffuse iterated value)作为融合单元的变元。但是,在执行纹理融合时,程序却可以引入迭代的颜色数据。

  有些

3-D硬件没有纹理stage能与第一个纹理相联系。对于这些适配器来说,程序需要在当前纹理设置中的第二和第三纹理stage上来执行融合操作。

  由于许多硬件的限制,现在很少有硬件能够执行由

IDirect3DDevice3通过多纹理融合接口提供的三线性mipmap内插运算。也很少有硬件能将D3DTSS_MIPFILTER纹理stage状态设置为D3DTFP_LINEAR。当然,我们可以使用多通道纹理融合来得到同样的效果,或者退一步使用D3DTFP_POINT mipmap过滤模式。

你可能感兴趣的:(存储,interface,Blend,平台,Direct3D,textures)