这一部分我们将介绍有关纹理状态的内容,并将它与纹理stage(texture 平台)状态进行比较。
注意,我们这里所列出的内容是在使用
IDirect3DDevice3接口时,对渲染状态的控制。使用IDirect3Ddevice接口的执行缓冲时,渲染状态用D3DOP_STATERENDER操作码来进行控制。D3DRENDERSTATE_TEXTUREADDRESS设备渲染状态控制着Direct3D设备的光栅模块(rasterization module)的行为。通过对渲染状态的改变,我们可以得到诸如明暗处理的应用,雾化效果的使用等等光栅操作。
程序通过引用IDirect3DDevice3::SetRenderState方法来控制渲染状态的其他特性。D3DRENDERSTATETYPE枚举类型用来声明所有可能的渲染状态。程序将D3DRENDERSTATETYPE的第一个参数传递给IDirect3DDevice3::SetRenderState方法。
渲染状态同时控制纹理的类型和纹理过滤器如何工作。对于DirectX 6.0和以后的版本,所有与纹理相关的渲染状态都被IDirect3DDevice3::SetTexture平台State方法提供的相应特性所取代了。被替换的渲染方法仍然起作用,但是被用于影响satge 0中相应的状态。为了提高性能,我们应该尽量使用SetTexture平台State 方法中的特性。下面列出了被替换的渲染状态,并列出了相应的新的纹理模块提供的状态:
被D3DTSS_ADDRESS,
D3DTSS_ADDRESSU, D3DTSS_ADDRESSV纹理stage状态所取代。D3DRENDERSTATE_BORDERCOLOR
被D3DTSS_BORDERCOLOR纹理stage状态取代。
D3DRENDERSTATE_TEXTUREMAG
被D3DTSS_MAGFILTER纹理stage状态取代。
D3DRENDERSTATE_TEXTUREMIN
被D3DTSS_MINFILTER纹理stage状态取代。MIPMAP缩小过滤(Mipmap minification filtering)被D3DTSS_MIPFILTER取代。
D3DRENDERSTATE_TEXTUREMAPBLEND
被D3DTSS_COLOROP and D3DTSS_ALPHAOP纹理stage状态取代。
缺省情况下,Direct3D不对图元使用任何纹理。当程序选择了一个纹理作为当前纹理时,它通知Direct3D设备将这个纹理应用到所有从此时起要渲染的图元上。如果要求场景中的每个图元都有自己的纹理,那么就要在每个图元被渲染之前对纹理进行设置。
IDirect3D2接口需要使用纹理句柄。在IDirect3D3接口中,纹理被作为独立的对象进行创建。程序通过IDirect3DTexture2接口来访问纹理的功能。如何获得指向IDirect3DTexture2接口的指针的有关内容见“获得一个纹理接口指针”部分。程序可以使用纹理指针来指派8个当前使用的纹理。详细内容见“分配当前纹理”如果程序使用纹理句柄,它必须将
D3DRENDERSTATE_TEXTUREHANDLE作为第一个参数传递给IDirect3DDevice3::SetRenderState。第二个参数就是纹理句柄。程序如果将
NULL作为第二个参数传递给IDirect3DDevice3::SetRenderState方法,将使纹理操作无效。反走样是一种使屏幕上的直线和边缘看起来更加平滑的方法。
Direct3D支持两种反走样方法,即边缘反走样(edge antialiasing)和全场景反走样(full-scene antialiasing)。详细内容见“通用技术与特殊效果”中的“反走样”部分。缺省情况下,
Direct3D不适用反走样。D3DRENDERSTATE_ANTIALIAS渲染状态可以被设置为 D3DANTIALIASMODE中的一个成员,它可以使全场景反走样有效。(缺省情况下的D3DANTIALIAS_NONE使全场景反走样无效。)要使边缘反走样有效(它需要进行第二次渲染遍历),需要将
D3DRENDERSTATE_EDGEANTIALIAS设置为TRUE。要使它无效,要将D3DRENDERSTATE_EDGEANTIALIAS设置为FALSE。这两种纹理寻址模式的讨论见“设置和恢复纹理寻址模式”。
这些新的渲染状态,在进行设备的多纹理层叠操作时,可以用来控制不同的纹理是否执行
U、V纹理Wrapping。将这些渲染状态设置为D3DWRAP_U和D3DWRAP_V联合标志 ,可以使Wrapping操作在对应的方向上有效;或者省略使用0值,使Wrapping操作无效。缺省情况下,Wrapping操作对于纹理stage上的所有方向都是无效的。要了解有关概念,请看“纹理Wrapping”部分。注:尽管D3DRENDERSTATE_WRAPU和D3DRENDERSTATE_WRAPV被替换了,IDirect3DDevice3接口仍然承认它们。当把这些老的渲染状态传递给IDirect3DDevice3::SetRenderState时,它们会在stage 0上影响U、V纹理Wrapping。
纹理边界颜色状态已经被由
IDirect3DDevice3::SetTexture平台State方法支持的 D3DTSS_BORDERCOLOR纹理stage状态所取代。如果程序使用IDirect3DDevice3接口,你可以通过设置SetTexture平台State来改变每一个纹理stage的边缘颜色。仍然使用
IDirect3DDevice2接口的程序也可以前面那样使用纹理边缘颜色,在这种情况下,可以通过把D3DRENDERSTATE_BORDERCOLOR枚举值作为第一个参数传递给IDirect3DDevice2::SetRenderState方法来设置或得到纹理边界颜色纹理。第二个参数是RGBA边缘颜色。详细内容见“关于边界颜色纹理寻址模式”。
程序可以对纹理进行透视修正,这样当图元由于远离观察者而变小时,可以使纹理更好的与图元相匹配。见
D3DRENDERSTATE_TEXTUREPERSPECTIVE。下面的代码展示了纹理透视修正的过程:
// This code fragment assumes that lpD3DDevice3 is a valid
pointer to // a Direct3DDevice3. // Enable texture perspective. lpD3DDevice3->SetRenderState(D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE); |
程序如何来设置纹理过滤状态主要要看使用何种版本的
Direct3D设备接口。如果程序使用IDirect3DDevice3接口,那么这里讨论的渲染状态就会被IDirect3DDevice3::SetTexture平台State方法提供的纹理过滤选项所取代。详细内容见“纹理过滤”部分。注:尽管这里讨论的渲染状态被纹理stage状态替换了,但是,如果你仍要使用它们的话,IDirect3DDevice3::SetRenderState(与IDirect3DDevice2版本相对应)方法仍然有效。系统会将这些渲染状态的效果映射到多纹理层叠的stage 0上。程序不能将老的渲染状态与相应的纹理stage状态相混淆,否则将出现无法预料的结果。
如果程序使用
IDirect3DDevice2接口,可以通过IDirect3DDevice2::SetRenderState方法来设置纹理过滤状态。Direct3D支持最近点取样(nearest point sampling),双线性过滤(bilinear filtering),各向异性纹理过滤(anisotropic texture filtering),以及mipmap过滤(mipmap filtering)。使用D3DTEXTUREFILTER枚举类型来选择过滤类型。当程序放大一个纹理时,可以使用
Direct3D设备来选择一种纹理过滤方法,将IDirect3DDevice2::SetRenderState方法的第一个参数设置为D3DRENDERSTATE_TEXTUREMAG枚举值,还必须将D3DTEXTUREFILTER中的一个枚举值作为第二个参数。 要将一个纹理缩小时,将IDirect3DDevice2::SetRenderState的第一个参数设置为D3DRENDERSTATE_TEXTUREMIN,将第二个参数设置为D3DTEXTUREFILTER中的一个枚举值。如果程序使用软件仿真设备,它们必须是对D3DRENDERSTATE_TEXTUREMAG和D3DRENDERSTATE_TEXTUREMIN使用相同的过滤方法。如果使用的过滤方法不同,会导致程序性能的降低。Direct3D硬件设备(HAL和MMX)没有这样的性能限制。当
D3DRENDERSTATE_TEXTUREMAG状态被设置为D3DFILTER_NEAREST时,各向异性过滤处于无效状态。只有当D3DRENDERSTATE_TEXTUREMAG被设置为D3DFILTER_LINEAR时,各向异性过滤才有效。对于D3DRENDERSTATE_TEXTUREMIN控制下的过滤,只有当它被设置为D3DFILTER_LINEAR、D3DFILTER_MIPLINEAR或D3DFILTER_LINEARMIPLINEAR时,各向异性过滤才有效。使用各向异性纹理例过滤的程序应该将过滤程度设置为一个我们需要的值。当它被设为
1时,各向异性过滤是无效的,而被设置为大于1时,则是有效的。见“各向异性纹理过滤”和D3DRENDERSTATE_ANISOTROPY。当我们使用
MIPMAP过滤时,程序可以选择近点取样(near-point sampling)、mipmap或是线性mipmap过滤。临近点取样MIPMAP按照是否与最终输出的纹理具有最接近的分辨率这一规则来选择MIPMAP纹理,然后使用最近点取样来获得颜色信息。线性mipmap过滤则从两个最近的mipmap中选择一个颜色,然后在它们之间进行颜色的线性内插运算。见“用Mipmap进行纹理过滤”和D3DTEXTUREFILTER。程序可以通过控制
mipmap LOD(level of detail)的偏移得到一种特殊的过滤效果。mipmap纹理上的正偏移可以产生一个锐度更高的混淆了的(aliased)图象。负偏移量会使纹理图象看起来比较模糊。详细内容见D3DRENDERSTATE_MIPMAPLODBIAS。没有纹理的图元使用材质的颜色进行渲染,也可以使用顶点的颜色来渲染。可以使用D3DFILLMODE枚举类型来选择填充的方法。见D3DRENDERSTATE_FILLMODE。
在填充一个图元时,Direct3D使用标准的Windows ROP2二进制光栅操作。缺省的值为R2_COPYPEN,它将像素设置为当前画笔的颜色。详细内容见SDK文档中的GetROP2和SetROP2。尽管大部分的程序不需要改变这个缺省值,但是程序仍然可以使用D3DRENDERSTATE_ROP2枚举值来改变光栅填充操作。
如果程序想要使抖动有效,那么就必须将IDirect3DDevice3::SetRenderState的第一个参数设置为D3DRENDERSTATE_DITHERENABLE,将第二个参数设置为TRUE;要使抖动无效,就要将第二个参数设置为FALSE。
程序也可以使用点画填充图案模式。见D3DRENDERSTATE_STIPPLEENABLE。使用D3DRENDERSTATE_STIPPLEPATTERN00到D3DRENDERSTATE_STIPPLEPATTERN31的枚举值可以声明一个32x32的点画模式。这些枚举值中的每一个都对应于点画模式中的一行。举例来说,要设置点画模式中的第一行,就要将D3DRENDERSTATE_STIPPLEPATTERN00作为第一个参数传递给IDirect3DDevice3::SetRenderState。同时将点画模式的16进制值作为第二个参数。
有时,绘制一行的最后一个像素时,可能会造成与周围图元的重叠。这是可以使用D3DRENDERSTATE_LASTPIXEL枚举值来进行控制。但是,如果我们没有很好的预先计划的话,最好不要使用这一设置。某些情况下,禁止对最后一个像素的渲染可能会造成在图元之间出现缝隙。
缺省情况下,Direct3D设备对图元采用实轮廓(solid outline)。轮廓模式可以使用D3DLINEPATTERN结构来改变。见D3DRENDERSTATE_LINEPATTERN。
下面的代码中将明暗处理模式设置为平面处理模式:
// This code fragment assumes that lpD3DDevice3 is a valid
pointer to // a Direct3DDevice3. // Set the shading state. lpD3DDevice3->SetRenderState(D3DRENDERSTATE_SHADEMODE, D3DSHADE_FLAT); |
雾化效果可以使一个三维场景更加真实可信。除了模仿雾之外,它还有许多其他的用途。例如可以用来随着距离的增加不断减小场景的清晰度,使得物体远离观察者时,它的细节能逐渐变得模糊。详细内容见“雾化”部分。
当前的
Direct3D设备允许进行雾化融合(fog blending),控制雾的颜色,操纵其他的雾化参数。通过将D3DRENDERSTATE_FOGENABLE渲染状态设置为TRUE,可以使雾化有效。雾的颜色可以通过D3DCOLOR值来设置(雾的颜色中的alpha成分会被忽略)。见D3DRENDERSTATE_FOGCOLOR。有关雾的详细内容见“雾化”部分。
颜色的alpha值用来控制它的(不)透明度。Alpha融合有效将会使一个表面上的颜色、材质和纹理与另一个表面透明的进行混合。要进一步了解有关内容,见“Alpha纹理融合”与“多纹理融合”。
Alpha融合渲染状态:程序要使用D3DRENDERSTATE_ALPHABLENDENABLE枚举值使alpha透明融合有效。Direct3D API允许多种类型的alpha融合,但要看用户的3-D硬件是否支持这些融合类型。
Alpha融合的类型由D3DRENDERSTATE_SRCBLEND和D3DRENDERSTATE_DESTBLEND渲染状态来决定。源与目的融合状态总是被成对的使用。下面的代码展示了如何将源融合状态设置为D3DBLEND_SRCCOLOR,以及如何目的融合状态设置为D3DBLEND_INVSRCCOLOR。// This code fragment assumes that lpD3DDevice3 is a valid
pointer to // an IDirect3DDevice3 interface. // Set the source blend state. lpD3DDevice3->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCCOLOR); // Set the destination blend state. |
通过改变源和目的融合状态,可以在一个有雾的或布满灰尘的环境中得到一个具有放射性的物体的表面。例如,如果程序需要在一个雾化的环境中模拟火焰、作战掩体、离子束或是看起来具有辐射性的物体,那么可以将源和目的融合状态设置为
D3DBLEND_ONE。 Alpha融合另一个用途是控制3-D场景中的光线,也被称为光线映射(light mapping)。根据源alpha信息,将源融合状态设置为D3DBLEND_ZERO,将目的融合状态设置为D3DBLEND_SRCALPHA,这样可以使一个场景变暗。源图元被当作一个光线映射来调节帧缓存中的内容,使得场景变暗,直到我们需要的状态为止。这样就会产生一种单色光的映射。彩色光线映射可以通过将源
alpha融合状态设置为D3DBLEND_ZERO,将目的融合状态设置为D3DBLEND_SRCCOLOR来得到。 Direct3D设备提供alpha值点画(stippling)功能,如果硬件支持的话。见D3DRENDERSTATE_STIPPLEDALPHA。如程序创建一个RGB或平滑(ramp)软件仿真设备,Direct3D会忽视这一枚举值。 Alpha测试(Alpha-test)渲染状态:程序可以使用alpha测试来控制何时将像素绘制到目标表面。通过使用D3DRENDERSTATE_ALPHATESTENABLE枚举值,程序可以对当前Direct3D设备进行设置,从而能够根据一个alpha测试函数来检测每一个像素。如果测试成功,那么像素就被绘制到目标表面。如果失败,Direct3D就会忽略它。使用D3DRENDERSTATE_ALPHAFUNC枚举值来选择这个alpha测试函数。程序可以使用D3DRENDERSTATE_ALPHAREF渲染状态,为所有的像素设置一个参考alpha值。
Alpha测试最通常的用途是在光栅近似于透明的对象时,能够提高程序的性能。如果正在进行光栅处理的像素的颜色数据比一个给定的像素(D3DPCMPCAPS_GREATEREQUAL)的颜色更加不透明,那么这个像素就会被绘制,否则光栅会完全忽略这个像素,除了必须的融合这两种颜色的过程之外。下面的程序中,如果一个给定的比较函数被支持的话,程序就会设置所需的用来提高性能的比较函数的参数。// This example assumes that pd3dDeviceDesc is a // D3DDEVICEDESC structure that was filled with a // previous call to IDirect3DDevice3::GetCaps. if (pd3dDeviceDesc->dpcTriCaps.dwAlphaCmpCaps & D3DPCMPCAPS_GREATEREQUAL) { dev->SetRenderState( D3DRENDERSTATE_ALPHAREF, (DWORD)0x00000001); dev->SetRenderState( D3dRENDERSTATE_ALPHATESTENABLE, TRUE ); dev->SetRenderState( D3DRS_ALPHACMP, D3DCMP_GREATEREQUAL ); } // If the comparison isn't supported, render
anyway. |
程序可以控制用来进行纹理融合的方式。使用纹理句柄的程序通过调用
IDirect3DDevice3::SetRenderState方法来设置纹理融合状态,同时要将D3DRENDERSTATE_TEXTUREMAPBLEND作为它的第一个参数,将D3DTEXTUREBLEND枚举类型中的一个值作为第二个参数。使用纹理接口指针的程序,在与当前纹理设置相关的纹理
stage中来设置纹理融合状态。详细内容见“多纹理融合”。下面程序中设置了
Culling状态,并将反面Culling掉。// This code fragment assumes that lpD3DDevice3 is a valid
pointer to // an IDirect3DDevice3 interface. // Set the culling state. lpD3DDevice3->SetRenderState(D3DRENDERSTATE_CULLMODE,
D3DCULL_CW); |
深度缓冲是一种用来去除隐藏的线段和表面的方法。要了解有关概念,请看“什么是深度缓冲”部分。缺省情况下,
Direct3D不使用深度缓冲。通过使用D3DZBUFFERTYPE中的一个成员来声明一个新的状态值,程序可以将深度缓冲更新为D3DRENDERSTATE_ZENABLE渲染状态。如果程序需要阻止
Direct3D写深度缓冲,那么可以使用D3DRENDERSTATE_ZWRITEENABLE枚举值,调用IDirect3DDevice3::SetRenderState方法,并将第二个参数声明为FALSE。下面的例子显示了如何将深度缓冲状态设置为
z-buffering有效:// This code fragment assumes that lpD3DDevice3 is a valid
pointer to // a Direct3DDevice3. // Enable z-buffering. lpD3DDevice3->SetRenderState(D3DRENDERSTATE_ZENABLE, D3DZB_TRUE); // D3DZB_TRUE is the same as TRUE |
当两个表面的深度值相同时,
z偏移量(z-biasing)可以用来显示位于一个表面前面的那面。使用这一技术可以得到不同的效果。比如我们要绘制墙上的阴影。这时,阴影和墙具有相同的深度值。如果程序想要将阴影显示在墙上面,那么就可以给阴影一个z-bias,使Direct3D能够将它们正确的显示出来(见D3DRENDERSTATE_ZBIAS)。在颜色通道(
color channel)上使用位掩模(bit mask)可以得到特殊的效果。例如,我们要得到一个具有强烈红色闪光的场景,这时,我们可以对蓝色和绿色通道进行遮蔽(掩模),使它们变暗,那么红色通道就相应的增强了,这样就得到了我们所需要的场景。程序还可以控制这一效果的间断性的关闭,从而产生闪烁感。调用
IDirect3DDevice3::SetRenderState方法可以来设置平面掩模,同时要将第一个参数设置为D3DRENDERSTATE_PLANEMASK,第二个参数就是需要的平面掩模。注:软件光栅不支持D3DRENDERSTATE_PLANEMASK渲染状态,并且硬件驱动器也经常忽略这种渲染状态。通过使用alpha融合可以使写颜色缓冲器无效,同时要将D3DRENDERSTATE_SRCBLEND设置为D3DBLEND_ZERO,D3DRENDERSTATE_DESTBLEND设置为D3DBLEND_ONE。
通过设置颜色码,可以使Direct3D将码值代表的颜色处理为透明。当Direct3D将DDSD_CKSRCBLT标志创建的纹理应用于一个图元时,所有符合颜色码的图元上的像素都将不被渲染。要注意的是,不是由DDSD_CKSRCBLT标志创建的纹理不会显示出颜色码的效果。
使用IDirectDrawSurface4::SetColorKey方法来设置颜色码。我们可以通过IDirect3DDevice3::SetRenderState方法来对颜色码进行开/关切换。要将第一个参数设置为D3DRENDERSTATE_COLORKEYENABLE。如果程序将第二个参数设置为TRUE,那么颜色码有效,设置为FALSE则无效,缺省时为FALSE。
// This code fragment assumes that lpD3DDevice3 is a valid
pointer to // a Direct3DDevice3. // Disable color keying. lpD3DDevice3->SetRenderState(D3DRENDERSTATE_COLORKEYENABLE, FALSE); |
缺省情况下,在一个场景中对
IDirect3DDevice2::DrawPrimitive和IDirect3DDevice2::DrawIndexedPrimitive的调用是成批处理的。也就是说,它们被分配在同一缓冲区内,并且经过一次调用一起传递给Direct3D设备驱动器。场景中渲染状态的变化也被置于同一缓冲区中。当缓冲区被充满时,或者当引用了IDirect3DDevice2::EndScene方法时,缓冲区的内容被传递给设备驱动器。这一技术可以用来提高性能。但是,如果程序改变的是场景而不是场景的渲染状态,那么这些变化有可能会出现次序上的颠倒。例如,如果在
IDirect3DDevice2::DrawPrimitive或IDirect3DDevice2::DrawIndexedPrimitive调用之间,一个纹理的内容被替换了,那么两种情况下的图元都可能使用新的纹理来绘制。要解决这一问题,程序可以在场景变化之前将批处理缓冲区进行刷新。调用
IDirect3DDevice2::SetRenderState方法可以将批处理缓冲区刷新,同时要将D3DRENDERSTATE_FLUSHBATCH作为第一个参数,第二个参数应该是0。注:这一渲染状态值对使用纹理句柄(使用IDirect3DDevice2接口)的程序有效。当使用IDirect3DDevice3接口进行渲染时(也包括使用执行缓冲时),使用批处理的图元被隐含的刷新了。
程序使用模板缓冲来决定一个像素是否被写到渲染目标表面。详细内容见“模板缓冲”部分。
通过调用IDirect3DDevice3::SetRenderState方法可以决定模板是否有效,同时要将D3DRENDERSTATE_STENCILENABLE作为第一个参数。第二个参数设置为TRUE或FALSE,决定它是否有效。
调用IDirect3DDevice3::SetRenderState方法可以来设置一个比较函数,Direct3D用这个比较函数来执行模板测试(stencil test)。同时要将第一个参数设置为D3DRENDERSTATE_STENCILFUNC,将D3DCMPFUNC枚举类型的一个成员设置为第二个参数。
模板参考值(stencil reference value)使一个在模板缓冲中模板函数用来进行测试的值。缺省时,模板参考值为0。程序可以用IDirect3DDevice3::SetRenderState对它进行设置。将D3DRENDERSTATE_STENCILREF作为第一个参数,将新的参考值作为第二个参数。
Direct3D对每个像素执行模板测试之前,它会对模板参考值和模板掩模值进行一个逐位的AND运算。得到的结果再用模板比较函数与模板缓冲的内容进行比较。程序可以设置模板掩模。使用IDirect3DDevice3::SetRenderState方法,并将第一个参数设置为D3DRENDERSTATE_STENCILMASK,将第二个参数设置为新的模板掩模。
为了设置模板测试失败时Direct3D采取的行动,可以引用IDirect3DDevice3::SetRenderState方法,并将第一个参数设置为D3DRENDERSTATE_STENCILFAIL,第二个参数必须是D3DSTENCILOP枚举类型的一个成员。
程序还可以设置当模板测试通过而z-buffer测试失败时Direct3D的响应。这时可以调用IDirect3DDevice3::SetRenderState方法,并将D3DRENDERSTATE_STENCILZFAIL作为第一个参数,将一个D3DSTENCILOP枚举类型的成员作为第二个参数。
另外,程序也可以设置当模板测试和z-buffer测试都通过时的Direct3D的响应。我们可以使用IDirect3DDevice3::SetRenderState方法,将D3DRENDERSTATE_STENCILPASS作为第一个参数,将一个D3DSTENCILOP枚举类型的成员作为第二个参数。