这些是DX6的一些知识,不过还有些学习的价值。原文地址:http://17de.com/library/d3d_6im/d3dim6_8.htm
这一部分内容是关于Direct3D设备用途及使用的一些概述,包括以下内容:
-
- 1. 什么是Direct3D设备
- 2. Direc3D设备类型
- 3. 设备接口
- 4. 使用设备
- 5. 仿真模式
- 6. AGP表面与Direct3D设备
- 7. 执行缓冲
Direct3D设备是Direct3D渲染的组成部分。它用来封装(encapsulate)和存储(store)渲染状态。另外,一个Direct3D设备还执行变换和灯光操作,以及将一幅图象光栅处理(rasterize)到一个DirectDraw表面。在结构上,Direct3D设备包含了一个变换模块(transformation module),一个灯光模块(lighting module),和一个光栅模块(rasterizing module),如下图所示:
Direct3D允许程序使用定制变换和灯光模块来忽略Direct3D设备的变换和灯光模块。详细内容见“顶点格式”。
Direct3D立即模式设备支持三种接口:IDirect3Ddevice,IDirect3DDevice2,和IDirect3DDevice3。IDirect3Ddevice接口提供使用执行缓冲进行编程的方法。IDirect3DDevice2接口提出DrawPrimitive方法。IDirect3DDevice3扩展了DrawPrimitive的功能。DrawPrimitive方法提供了首选的渲染途径。这三个接口有一些公共的方法用于各种程序类型,并且这些方法使三个接口都提供的。有关这两种渲染途径的详细内容见“渲染”部分。
在DirectX 5.0中的IDirect3DDevice2接口介绍之前,Direct3D设备是DirectDrawSurface对象的接口。IDirect3DDevice2接口实现了一个设备对象模型(device-object model),在这个模型中,Direct3Ddevice对象与DirectDraw表面是完全分离的。IDirect3DDevice3接口使用并扩展了这一设备对象模型。因为它们独立于DirectDraw表面并且有独立的生存期,Direct3D 设备对象在不同的时间可以使用不同的DirectDraw表面来作为渲染目标。有关渲染目标的详细内容见IDirect3DDevice3::SetRenderTarget。
这一部分介绍Direct3D设备和它的每一种类型。
注:D3d.h头文件为参考光栅(reference rasterizer)定义了一个第五设备标识符(IID_IDirect3DrefDevice)。这个参考光栅不是为正式程序设计的,它只被用于参考或特征演示时使用。它不能用通常的方法来列举,你必须在HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Direct3D/Drivers注册键(registry key)中设置一个名为EnumReference的值,这样才能被列举。
Direct3D支持四种类型的设备。程序创建的Direct3D设备必须与所使用的硬件相匹配。Direct3D提供两种渲染能力,一种是通过3-D硬件,另一种是对3-D硬件功能的软件方针。因此,Direct3D提供的设备对于硬件访问和软件仿真都予以支持。
硬件加速设备比软件仿真设备有更好的性能。
除了参考光栅(reference rasterizer)之外,软件设备并不支持硬件设备的所具有的特性。例如,软件设备就不支持同时将一个纹理分派到两个以上的纹理stage(texture 平台)。程序应该对设备能力经常进行查询以确定支持哪些特性。
如果程序运行的计算机的显示适配器支持Direct3D,那么程序就可以用它来进行3-D操作。Direct3D兼容加速卡在硬件中实现了所有或部分的变换、灯光和光栅模块。
应用程序不能直接访问3-D加速卡。他们要调用Direct3D的函数和方法。Direct3D通过HAL来访问硬件。如果程序运行的计算机支持HAL,那么使用HAL设备就能获得最好的性能。
为了创建一个HAL设备,程序要调用IDirect3D3::CreateDevice,并且将IID_IDirect3DHALDevice作为它的低一个参数。详细内容见“创建一个Direct3D设备”。
注:与软件仿真设备(MMX, RGB,参考光栅和传统的ramp设备)不同的是,硬件设备不能在8-bit渲染目标表面上进行渲染。
MMX是一套特殊的指令集,一些微处理器提供对它的支持,并由此而获得了更好的多媒体和三维处理性能。如果安装了MMX,那么Direct3D会使用MMX来提高渲染速度。
MMX设备不象HAL设备那样,它并不是硬件加速设备。变换、灯光和光栅模块都是由软件来执行的。但是,MMX设备提供了比其它的软件仿真设备更好的性能。
如果程序使用的是Direct3D2接口,那么它就必须明确的创建一个MMX设备。但是,从IDirect3D3接口开始,MMX和RGB设备将执行同样的特性设置。如果程序需要创建一个RGB设备并且微处理器支持MMX技术的话,那么Direct3D将自动创建一个MMX设备。
引用IDirect3D3::CreateDevice方法,将IID_IDirect3DMMXDevice作为第一个参数,这样就可以创建一个MMX设备。有关创建Direct3D设备的详细内容见“创建一个Direct3D设备”。如果程序要求创建一个MMX设备,然而计算机并不支持MMX技术,那么CreateDevice方法就会失败。
如果计算机不提供对三维操作的硬件加速,那么程序可以使用软件来对三维硬件进行仿真。如果你的计算机不支持MMX技术,但却有足够的处理能力,那么程序就可以使用RGB设备。RGB设备通过软件来仿真3-D硬件的色彩处理功能。因为RGB设备要通过软件来进行仿真,所以它的速度就要比HAL设备慢,也要比MMX设备慢。详细内容见“仿真模式”。
如果你所使用的机器支持MMX技术,那么当程序创建一个RGB设备时,IDirect3D3接口会自动创建一个MMX设备。
程序使用IDirect3D3::CreateDevice函数来创建一个RGB设备,同时要将IID_IDirect3DRGBDevice作为它的第一个参数。
注:ramp软件仿真驱动器在DirectX中已经被废除了,DirectX 6.0以及后续版本对它均不再提供支持。使用IDirect3D3不能创建一个Direct3D ramp设备,也不能使用IDirect3DDevice3接口来查询一个已经存在的ramp设备。简单来说,ramp设备不支持任何的多纹理融合操作。要想实现对这些特性的方针,就必须使用MMX或RGB软件仿真设备。
一个ramp设备是一个软件仿真设备,它可以提供单色光。如果你的计算机没有足够的处理能力来使用其它的Direct3D设备,那么你可以选择使用ramp设备。详细内容见“仿真模式”。
Ramp设备主要是为了为传统的DirectX程序提供支持。一般而言,没有足够的处理能力来支持RGB设备的计算机也是不适于3-D程序的。
程序通过调用IDirect3D2::CreateDevice方法来创建ramp设备,同时要将IID_IDirect3DrampDevice作为第一个参数。
使用设备接口,主要是用来操作一个Direct3Ddevice对象的渲染状态、灯光状态以及执行渲染操作。尽管设备支持三个设备接口(IDirect3DDevice, IDirect3DDevice2,和IDirect3DDevice3),但是你的程序中并不需要使用多个设备接口。使用那种接口,要有所使用的渲染方法来决定,即DrawPrimitive方法或执行缓冲方法。下面我们来讨论一下这三种接口以及它们所代表的渲染方法:
IDirect3Ddevice支持使用执行缓冲来进行渲染,它是Direct3D程序最初使用的方法。这个接口在后来的DirecX版本中是兼容的,但是DrawPrimitive渲染结构更容易使用。我们推荐使用IDirect3DDevice3接口来编制新的应用程序。
所有Direct3D设备类型都支持IDirect3Ddevice接口。
最新的两个设备接口是IDirect3DDevice3和IDirect3DDevice2,它们都支持DrawPrimitive 渲染方法和执行缓冲。DrawPrimitive方法大大简化了准备和渲染顶点的过程,并被认为是首选的渲染方法。
如果你的程序使用DrawPrimitive方法,那么最好使用最新版本的设备接口。符合COM 标准的向后兼容性的Direct3D支持所有的接口版本,但我们还是推荐使用最新的版本,这样就可以利用到一些新的特性,并且能提高程序的性能。
DirectX 5.0中创建的IDirect3DDevice2接口首次提出了DrawPrimitive渲染结构。基于DrawPrimitive的渲染方法比执行缓冲更容易使用,并且提供了用于Direct3D编程的更直接的形式。详细内容见“渲染”部分。所有的Direct3D设备类型都支持IDirect3DDevice2接口。
象IDirect3DDevice2接口一样,IDirect3DDevice3接口也支持DrawPrimitive方法。相应于IDirect3D3接口,IDirect3DDevice2接口提供了增强的特性集,它包括多纹理融合、顶点缓冲以及增强的3-D几何渲染管道。IDirect3DDevice3接口也提供了IDirect3DDevice2接口中的同样的方法。同时它也为IDirect3DDevice3::SetRenderState方法增加了一些新的渲染状态以支持多纹理融合。
所有的Direct3D设备类型都支持IDirect3DDevice3接口。
这一部分我们将讨论如何在立即模式中使用Direct3D设备。
这一部分我们来讨论列举Direct3D设备时的两个主要的任务。
程序可以对所使用的硬件进行查询,这样就可以确定它支持哪种Direct3D设备。完成这一任务最重要的API函数是IDirect3D3::EnumDevices,它用来枚举所有硬件可能支持的Direct3D设备。它使用D3DenumDevicesCallback函数来选择要使用的设备。D3DenumDevicesCallback函数由你在程序中来提供。注意:因为这个回调函数是由程序提供的,因此它的名字可以任意来取。
下面的代码展示了枚举和选择Direct3D设备的过程。在这个例子中,设备枚举回调函数被命名为EnumDeviceCallback。一个指向EnumDeviceCallback的指针被传递给IDirect3D3::EnumDevices方法,它为每个正在被枚举的设备调用EnumDeviceCallback函数。
// In this code fragment, the variable lpd3d contains a valid if (!fDeviceFound) |
D3DenumDevicesCallback函数被每一个安装在系统中的Direct3D设备所引用。当它被调用时,它的第一个参数将作为正在被枚举的设备的全局统一标识符(GUID)。GUID的值将是IID_IDirect3DHALDevice,IID_IDirect3DMMXDevice,IID_IDirect3DRGBDevice或IID_IDirect3DrampDevice。D3DenumDevicesCallback函数最适合你的程序的那个设备。
D3DenumDevicesCallback函数的第二和第三个参数为字符串,它包含了设备的名称和用户友好的描述。
第四个参数指向一个D3DDEVICEDESC结构体,它包含了设备的硬件性能的有关信息。即使被列举的设备是一个HAL设备,具体的硬件也不一定支持所有的Direct3D API所提供的性能。
D3DenumDevicesCallback的第五个参数包含了一个指向D3DDEVICEDESC结构体的指针,它用来描述你所使用的机器的软件仿真性能。这一信息与你要使用的软件仿真设备(MMX, RGB,或RAMP设备)有关。
最后一个参数是一个程序定义的值。你的程序将这个参数传递给IDirect3D3::EnumDevices方法。它于此将这个值传递给D3DenumDevicesCallback函数。
下面的代码描述了如何创建一个D3DenumDevicesCallback函数。在这个例子中,程序提供的回调函数名为EnumDeviceCallback。EnumDeviceCallback函数使用下面的算法来选择一个适合的Direct3D设备:
- 放弃所有不适合当前显示深度的设备。
- 放弃所有不能处理Gouraud-明暗处理三角形的设备。
- 如果一个硬件设备符合第一和第二点,那么就使用这个设备。但是如果程序正处于debug模式,那么它不会使用硬件设备。
- 另外,尽量使用Mono/Ramp模式的软件渲染设备,而不要使用RGB设备;如果不使用MMX设备,那么Mono会更快。
EnumDeviceCallback函数的代码如下所示:
// This function is written with the assumption that the following // |
创建一个设备时,必须要选择Direct3D程序使用执行缓冲还是DrawPrimitive方法。这一选择将决定在创建一个设备时程序需要获得哪种类型的接口指针。如果选择使用执行缓冲,那么程序就必须得到一个指向IDirect3Ddevice接口的指针。如果选择DrawPrimitive方法,程序必须得到一个指向IDirect3DDevice3接口的指针。
下面的讨论将向我们展示如何来创建一个设备:
注:一些通用的硬件设备要求渲染目标与深度缓冲表面使用相同的颜色深度。在这些硬件上,如果程序在渲染目标表面使用16-bit色,那么相应的深度缓存也必须使用16-bit色。如果使用32-bit的渲染目标表面,那么深度缓存也必须是32-bits,如果需要的话,也可以使用8-bits的模板缓冲。
如果程序运行的硬件有这样的要求,而你的程序又不能满足这一要求,那么,任何想要使用这样不相适应的表面来创建一个渲染设备的尝试都将失败。你可以使用DirectDraw的IDirectDraw4::GetDeviceIdentifier方法来追踪有这一限制的硬件。
要使用执行缓冲方法,程序必须先在常规方式下初始化DirectDraw,并得到一个指向IDirect3D3接口的指针。详细内容见“得到(retrive)一个IDirect3D3接口”。程序还应创建一个包含DDSCAPS_3DDEVICE能力的表面。关于创建表面的内容见“创建表面”部分。然后,对这个表面调用IUnknown::QueryInterface方法,得到一个指向IDirect3Ddevice接口的指针。使用IDirect3DDevice::CreateExecuteBuffer来创建一个执行缓冲,并得到一个指向IDirect3DexecuteBuffer接口的指针。下面左图描述了这一过程:
使用DrawPrimitive方法,程序也必须先在常规方式下初始化DirectDraw对象,并得到一个指向IDirect3D3接口。然后,调用IDirect3D3::CreateDevice方法创建一个Direct3D设备。这一方法传递给程序一个指向IDirect3DDevice3接口的指针。
上面右图描述了这一过程:
代码如下:
LPDIRECTDRAW lpDD; // DirectDraw Interface hResult = DirectDrawCreate (NULL, &lpDD, NULL); // Get an IDirect3D3 interface hResult = lpD3D->CreateDevice (IID_IDirect3DHALDevice, |
上面的例子中引用了IDirect3D3::CreateDevice方法来创建一个Direct3D设备。在这个例子中,如果调用成功的话,就创建了一个Direct3D HAL设备。
要注意的时,程序中创建的DirectDraw渲染表面不允许作为一个Direct3D的渲染目标来创建。要这样做,就必须向IDirectDraw4::CreateSurface方法传递一个DDSURFACEDESC2结构体。DDSURFACEDESC2结构体由一个名为ddsCaps的成员,它是一个DDSCAPS类型的结构体。DDSCAPS结构体又包含了一个名为dwCaps的成员,在使用IDirectDraw4::CreateSurface方法时,它必须被设置为DDSCAPS_3DDEVICE。
当使用硬件加速渲染设备时,我们所使用的渲染目标表面必须在显存中来创建(使用DDSCAPS_VIDEOMEMORY标志),否则,在系统内存中来创建(使用DDSCAPS_SYSTEMMEMORY标志)。
使用IDirect3DDevice3::SetTransform 方法来应用变换。例如,你可以使用如下的代码来设置视变换:
HRESULT hr |
调用IDirect3DDevice3::SetTransform方法时,它的第一个参数有三种可能的设置:D3DTRANSFORMSTATE_WORLD, D3DTRANSFORMSTATE_VIEW,和D3DTRANSFORMSTATE_PROJECTION。这三种变换状态在D3DTRANSFORMSTATETYPE枚举类型中进行定义。
4.4.6 渲染状态
这一部分我们将介绍有关纹理状态的内容,并将它与纹理stage(texture 平台)状态进行比较。
- 关于渲染状态
- 当前纹理
- 反走样状态 Antialiasing States
- 纹理寻址状态 Texture Addressing State
- 纹理Wrapping状态 Texture Wrapping State
- 纹理边界 Texture Borders
- 纹理透视状态 Texture Perspective State
- 纹理过滤状态 Texture Filtering State
- 轮廓和填充状态 Outline and Fill States
- 明暗处理状态 Shading State
- 雾化状态 Fog State
- Alpha状态
- 纹理融合状态 Texture Blending State
- Culling状态 Culling State
- 深度缓冲状态 Depth Buffering State
- 平滑状态 Ramp State
- 子像素修正状态 Subpixel Correction State
- 平面掩模状态 Plane Masking State
- 颜色码状态 Color Keying State
- 渲染指令批处理状态 Render Command Batching State
- 模板缓冲状态 Stencil Buffer State
注意,我们这里所列出的内容是在使用IDirect3DDevice3接口时,对渲染状态的控制。使用IDirect3Ddevice接口的执行缓冲时,渲染状态用D3DOP_STATERENDER操作码来进行控制。
设备渲染状态控制着Direct3D设备的光栅模块(rasterization module)的行为。通过对渲染状态的改变,我们可以得到诸如明暗处理的应用,雾化效果的使用等等光栅操作。
程序通过引用IDirect3DDevice3::SetRenderState方法来控制渲染状态的其他特性。D3DRENDERSTATETYPE枚举类型用来声明所有可能的渲染状态。程序将D3DRENDERSTATETYPE的第一个参数传递给IDirect3DDevice3::SetRenderState方法。
渲染状态同时控制纹理的类型和纹理过滤器如何工作。对于DirectX 6.0和以后的版本,所有与纹理相关的渲染状态都被IDirect3DDevice3::SetTexture平台State方法提供的相应特性所取代了。被替换的渲染方法仍然起作用,但是被用于影响satge 0中相应的状态。为了提高性能,我们应该尽量使用SetTexture平台State 方法中的特性。下面列出了被替换的渲染状态,并列出了相应的新的纹理模块提供的状态:
D3DRENDERSTATE_TEXTUREADDRESS
被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纹理寻址状态(由D3DRENDERSTATE_TEXTUREADDRESS, D3DRENDERSTATE_TEXTUREADDRESSU和D3DRENDERSTATE_TEXTUREADDRESSV渲染状态设置)已经被IDirect3DDevice3接口提供的纹理寻址特性所取代。但是,使用IDirect3DDevice2接口的程序仍然可以使用先前的纹理寻址模式。
这两种纹理寻址模式的讨论见“设置和恢复纹理寻址模式”。
U、V纹理Wrapping渲染状态D3DRENDERSTATE_WRAPU和D3DRENDERSTATE_WRAPV被D3DRENDERSTATE_WRAP0到D3DRENDERSTATE_WRAP7渲染状态所取代。
这些新的渲染状态,在进行设备的多纹理层叠操作时,可以用来控制不同的纹理是否执行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);对于IDirect3DDevice3接口,缺省情况下为TRUE,使透视修正纹理映射有效。对于先前版本的接口,缺省值为FALSE。要注意的是,许多的3-D适配器对于纹理透视修正会无条件的执行。透视修正必须使用基于w的雾化和w-buffer才会有效。详细内容见“雾化“部分的“Eye-relative vs. Z-Based Depth”,以及“深度缓冲”部分的“使深度缓冲有效”。
程序如何来设置纹理过滤状态主要要看使用何种版本的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。
-
Direct3D支持平面明暗处理和Gouraud明暗处理两种模式。缺省时使用Gouraud模式。程序可以使用D3DSHADEMODE枚举类型来控制当前的明暗处理模式。见D3DRENDERSTATE_SHADEMODE。
下面的代码中将明暗处理模式设置为平面处理模式:
// 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.
lpD3DDevice3->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCCOLOR);经过上面的代码调用,Direct3D在源颜色(要在当前位置上渲染的图元的颜色)与目的颜色(帧缓存中的当前位置的颜色)之间执行了一次线性融合。这样得到的效果就好像是一个彩色的玻璃。目的对象上的一些颜色看起来就象是被传递给了源对象,而另外的颜色则象是被吸收掉了。
通过改变源和目的融合状态,可以在一个有雾的或布满灰尘的环境中得到一个具有放射性的物体的表面。例如,如果程序需要在一个雾化的环境中模拟火焰、作战掩体、离子束或是看起来具有辐射性的物体,那么可以将源和目的融合状态设置为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.
// The only drawback is no performance gain.并非所有的硬件都支持所有的alpha测试特性。通过调用IDirect3DDevice3::GetCaps方法可以例检查硬件的能力。得到硬件能力之后,在对想要得到的比较函数检查D3DPRIMCAPS(包含于相应的D3DDEVICEDESC结构中)结构的dwAlphaCmpCaps成员。如果dwAlphaCmpCaps成员只包含D3DPCMPCAPS_ALWAYS能力或是只包含D3DPCMPCAPS_NEVER能力,那么就表示设备不支持alpha测试。
程序可以控制用来进行纹理融合的方式。使用纹理句柄的程序通过调用IDirect3DDevice3::SetRenderState方法来设置纹理融合状态,同时要将D3DRENDERSTATE_TEXTUREMAPBLEND作为它的第一个参数,将D3DTEXTUREBLEND枚举类型中的一个值作为第二个参数。
使用纹理接口指针的程序,在与当前纹理设置相关的纹理stage中来设置纹理融合状态。详细内容见“多纹理融合”。
Direct3D渲染图元时,会对图元的表面进行Culling操作。HAL和MMX设备的Culling模式可以使用D3DCULL枚举类型进行设置。见D3DRENDERSTATE_CULLMODE。缺省情况下,Direct3D把具有反时针顶点顺序的方面Culling掉。
下面程序中设置了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程序也可以使用D3DCMPFUNC枚举类型的成员来选择Direct3D在执行深度缓冲时使用的比较函数,见D3DRENDERSTATE_ZFUNC。
当两个表面的深度值相同时,z偏移量(z-biasing)可以用来显示位于一个表面前面的那面。使用这一技术可以得到不同的效果。比如我们要绘制墙上的阴影。这时,阴影和墙具有相同的深度值。如果程序想要将阴影显示在墙上面,那么就可以给阴影一个z-bias,使Direct3D能够将它们正确的显示出来(见D3DRENDERSTATE_ZBIAS)。
D3DRENDERSTATE_MONOENABLE渲染状态现在已经不再使用了。当程序使用一个ramp设备时,ramp灯光会自动有效。
D3DRENDERSTATE_SUBPIXEL渲染状态不再使用,系统会忽略掉它。
在颜色通道(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枚举类型的成员作为第二个参数。