第五节
Direct3D立即模式的要素 Direct3D立即模式由一些相互联系的API成员组成,通过它们可以来创建对象,给对象填充数据,和将对象组织在一起。这些API是基于COM模型的。立即模式API是在Direct3D驱动器之上的一个很薄的层次。这一部分给出了一些立即模式组成部分的技术资料。这些资料分一些几个部分来讨论:
这一部分讨论Direct3D和DirectDraw之间的联系,分以下几个部分:
1. DirectDraw, Direct3D, 和Direct3D接口
Direct3D通过COM对象和接口来实现其功能。Direct3D接口是DirectDraw对象的接口。DirectDraw提供给程序员一个单独的、统一的对象,这个对象封装了DirectDraw和Direct3D的各种状态。DirectDraw是程序要创建的第一个对象(调用DirectDrawCreate),也是最后一个释放的对象。通常DirectDraw对象表示显示设备,并且通过显示设备来执行Direct3D的大多数特性,这样就使得Direct3D的功能与DirecrDraw结合在一起。
这一点也就意味着Direct3D驱动器状态的生存期(ligetime)与DirectDraw对象的生存期是相同的。释放Direct3D接口并不会破坏Direct3D驱动器的状态。只有当所有有关这一对象的引用(不论是Direct3D还是DirectDraw)都被释放之后,这一状态才会被销毁。因此,如果你释放了一个Direct3D接口,并同时保留了一个DirectDraw驱动器接口的引用,然后再一次查询这个Direc3D接口,那么这个Direct3D状态就会被保留下来。
DirectDraw对象包括了三个Direct3D接口:IDirect3D, IDirect3D2, 和IDirect3D3。IDirect3D和IDirect3D2接口是老的接口。它们具有向后的兼容性。新程序应该使用IDirect3D3接口来创建其它的Direct3D对象,例如视口、灯光、纹理和材质等。详细内容见“Direct3D接口”。
Direct3D对象的功能通过IDirect3D, IDirect3D2和IDirect3D3接口来访问。这一部分我们来讨论这三个接口的有关内容。
如果你的程序使用了执行缓冲,那它必须通过DirectDraw对象的QueryInterface方法来得到一个指向IDirect3D接口的指针。
2.2 IDirect3D2接口 IDirect3D2接口提供了Direct3D程序的一种更简单的结构。这种程序结构通过简单的调用来实现对图元的渲染,它不使用执行缓冲。设备支持两种方法来实现这种新的渲染方式, IDirect3DDevice2::DrawPrimitive和IDirect3DDevice2::DrawIndexedPrimitive方法;这两种方法在当前的设备接口IDirect3DDevice3中都提供支持。通过DirectDraw对象调用QueryInterface方法,程序能够得到一个指向IDirect3D2接口的指针。
IDirect3D2接口是创建其它Direct3D立即模式接口的起点。使用它,你的程序可以找到和列举一个特殊的DirectDraw对象所支持的Direct3D设备的类型。它还包括了创建其它立即模式对象所需的一些方法。 IDirect3D2和IDirect3D之间一个最大的区别就是IDirect3D2实现了IDirect3D2::CreateDevice方法。这个方法用来创建一个支持DrawPrimitive方法的Direct3D设备。有关使用IDirect3D2::CreateDevice方法创建设备的详细内容见“Direct3D设备”。还要注意的是,我们无法使用IDirect3DDevice2提供的有关IDirect3Ddevice接口指针的一些新的特性。如果你的程序在一个DirectDraw表面上调用QueryInterface方法并得到了一个IDirect3Ddevice,那么他见不能访问后来的设备接口序所支持的一些特性。另外,它也不能调用以这种方式创建的设备对象的QueryInterface方法来得到一个IDirect3DDevice2接口。
2.3 IDirect3D3接口和IDirect3D2接口一样,IDirect3D3接口也支持DrawPrimitive方法。另外,IDirect3D3接口扩展了IDirect3DDevice3接口介绍的DrawPrimitive-结构程序的一些功能。新接口支持可塑(flexible)顶点格式、顶点缓冲和新的纹理处理能力。详细内容见“顶点格式”,“纹理”,“顶点缓冲”和“渲染”。
通过一个DirectDraw对象使用QueryInterface方法,程序可以得到一个指向IDirect3D3接口的指针。详细内容见“得到一个IDirect3D3接口”。
3. 得到一个IDirect3D3接口一个Direct3D程序开始的时候,必须要得到一个指向IDirect3D3接口的指针,这样才能访问Direct3D的各种功能。用以下的步骤可以获得一个这样的指针:
(1) 调用DirectDrawCreate创建一个DirectDraw设备。
(2) 调用IUnknown::QueryInterface方法得到一个指向IDirect3D3接口的指针。
下面的插图展示了这一步骤:
下面的代码说明了如何来查询一个
IDirect3D3接口:LPDIRECTDRAW lpDD; // IDirectDraw Interface LPDIRECT3D3 lpD3D; // IDirect3D3 Interface // Get an IDirectDraw interface. // Use the current display driver. hResult = DirectDrawCreate (NULL, &lpDD, NULL); if (FAILED (hResult)) { // Code to handle an error goes here. } // Get D3D interface hResult = lpDD->QueryInterface (IID_IDirect3D3, (void **)&lpD3D); if (FAILED (hResult)) { // Code to handle the error goes here. } |
应用程序使用
IDirect3D3接口来创建Direct3D设备、视口、灯光和材质。同时还要创建纹理。IDirect3D2接口下的纹理使用纹理句柄来进行操作。IDirect3D3接口对纹理处理能力进行了扩展。为了适应这些变化,IDirect3D3接口不再使用纹理句柄,取而代之的是纹理接口。详细内容见“纹理”部分。 Direct3D通过调用IDirect3D3::CreateDevice方法来创建设备。详细内容见“Direct3D设备”部分。在创建视口时,使用
IDirect3D3::CreateViewport方法。详细内容见“视口与裁剪”部分。灯光和材质的创建通过调用
IDirect3D3::CreateLight和IDirect3D3::CreateMaterial方法来实现。详细内容见“灯光与材质”。 5. DirectDraw合作级和FPU精度Direct3D使用单精度浮点运算来提高场景渲染的性能。缺省情况下,Direct3D检查FPU的精度(通常被设为双精度),并将它设置为单精度,完成必要的操作之后,再返回到应用程序调用之前将FPU改回到双精度。这一过程通过渲染循环不断的进行重复。
在设置
DirectDraw合作级时,可以通过包含DDSCL_FPUSETUP合作级标志来提高Direct3D的性能。这个标志主要是通知系统,程序不再依靠FPU设置来为双精度运算。当你使用DDSCL_FPUSETUP时,Direct3D就会将FPU设置为单精度,只有当Direct3D关闭时才将FPU恢复为双进度运算,这样就能减少每一个渲染循环对FPU的设置与恢复,从而提高了程序的性能。有一点很明显,那就是当我们使用了
DDSCL_FPUSETUP,那么程序就被限制在只能使用单精度值。这样,就要求我们只能在程序接受单精度浮点值的情况下才能使用这个合作级的设置。如果需要一些双精度浮点运算,那么我们只能在需要的时候人工设置FPU的精度模式,但在使用Direct3D之前必须将FPU重新设置成单精度。如果没有将FPU恢复为单精度,那么程序的性能就会受到影响。浮点精度对于每一个线程都是特定的,因此在多线程的程序中,必须对每个线程的
FPU设置进行仔细的检查。下面是一个控制台应用程序(
console application)的源代码,它用来检查和设置FPU精度模式,它使用了内嵌的汇编语言:#include <windows.h> #include <math.h> // This function evaluates whether the floating-point // control word is set to single precision/round to nearest/ // exceptions disabled. If these conditions don't hold, the // function changes the control word to set them and returns // TRUE, putting the old control word value in the passback // location pointed to by pwOldCW. BOOL MungeFPCW( WORD *pwOldCW ) { BOOL ret = FALSE; WORD wTemp, wSave; __asm fstcw wSave if (wSave & 0x300 || // Not single mode 0x3f != (wSave & 0x3f) || // Exceptions enabled wSave & 0xC00) // Not round to nearest mode { __asm{ mov ax, wSave and ax, not 300h ;; single mode or ax, 3fh ;; disable all exceptions and ax, not 0xC00 ;; round to nearest mode mov wTemp, ax fldcw wTemp } ret = TRUE; } *pwOldCW = wSave; return ret; } void RestoreFPCW(WORD wSave) { __asm fldcw wSave } void __cdecl main() { WORD wOldCW; BOOL bChangedFPCW = MungeFPCW( &wOldCW ); // Do something with control word as set by MungeFPCW. if ( bChangedFPCW ) RestoreFPCW( wOldCW ); } |