初始化Direct3D(1)
Direct3D是一种低层图形API,它能让我们利用3D硬件加速来渲染3D世界。我们可以把Direct3D看作是应用程序和图形设备之间的中介。例如通知图形设备清空屏幕,应用程序将调用Direct3D的IDirect3DDevice9::Clear方法。图1.1显示了应用程序、Direct3D和图形设备之间的关系。
图1.1中Direct3D所表示的是Direct3D中已定义的,供程序员使用的Direct3D接口和函数的集合。这些接口和函数代表了当前版本的Direct3D所支持的全部特性。注意:仅仅因为Direct3D支持某种特性,并不意味着你所使用的图形硬件(显卡)也能支持它。
如图1.1所示,在Direct3D和图形设备之间有一层中介——叫做硬件抽象层(HAL,Hardware Abstraction Layer)。Direct3D不能直接作用于图形设备,因为现在市面上的显卡种类实在是太多了并且每种显卡都有不同的性能和处理事件的方式。例如,两种不同的显卡实现清屏的方式也可能是不同的。因此,Direct3D要求设备制造商实现HAL。HAL是一组指示设备执行某种操作的特殊设备代码的集合。用这种方法,Direct3D避免了必须去了解某个设备的特殊细节,使它能够独立于硬件设备。
设备制造商在HAL中实现他们的产品所支持的所有特性。HAL将不会实现那些Direct3D支持但硬件产品不支持的特性。调用一个HAL中没有实现的Direct3D的函数将会出错,除非它是顶点处理操作,因为这个功能可以由软件模拟来实现。因此当使用某些仅由市面上少数显卡所支持的高级特性时,必须检测一下设备是否支持。
1.1.1 REF设备
你也许想把一些你的设备不支持的Direct3D函数写入程序。为了达到这个目的,Direct3D提供了REF设备,它用软件模拟了所有的Direct3D API。这允许你写并测试那些你的显卡不支持的Direct3D特性的代码。懂得REF设备仅仅用于开发阶段,这是很重要的。它只会和DirectX SDK一起被装载,而不会发布给最终用户。另外,REF设备实在是太慢了,除了测试以外它没有任何利用价值。1.1.2 D3DDEVTYPE
在代码中,我们用D3DDEVTYPE_HAL来定义HAL设备,它是D3DDEVTYPE枚举类型的一个成员。同样的,REF设备则由D3DDEVTYPE_REF来定义,它也属于D3DDEVTYPE枚举类型。记住这些类型很重要,因为在创建设备的时候我们需要指定我们将要使用的类型。
Defines device types.
typedef enum D3DDEVTYPE
{
D3DDEVTYPE_HAL = 1,
D3DDEVTYPE_NULLREF = 4,
D3DDEVTYPE_REF = 2,
D3DDEVTYPE_SW = 3,
D3DDEVTYPE_FORCE_DWORD = 0xffffffff,
} D3DDEVTYPE, *LPD3DDEVTYPE;
Constants
- D3DDEVTYPE_HAL
- Hardware rasterization. Shading is done with software, hardware, or mixed transform and lighting.
- D3DDEVTYPE_NULLREF
- Initialize Direct3D on a computer that has neither hardware nor reference rasterization available, and enable resources for 3D content creation. See Remarks.
- D3DDEVTYPE_REF
- Direct3D features are implemented in software; however, the reference rasterizer does make use of special CPU instructions whenever it can.
- D3DDEVTYPE_SW
- A pluggable software device that has been registered with IDirect3D9::RegisterSoftwareDevice.
- D3DDEVTYPE_FORCE_DWORD
- Forces this enumeration to compile to 32 bits in size. Without this value, some compilers would allow this enumeration to compile to a size other than 32 bits. This value is not used.
Remarks
All methods of the IDirect3D9 interface that take a D3DDEVTYPE device type will fail if D3DDEVTYPE_NULLREF is specified. To use these methods, substitute D3DDEVTYPE_REF in the method call.
A D3DDEVTYPE_REF device should be created in D3DPOOL_SCRATCH memory, unless vertex and index buffers are required. To support vertex and index buffers, create the device in D3DPOOL_SYSTEMMEM memory.
If D3dref9.dll is installed, Direct3D will use the reference rasterizer to create a D3DDEVTYPE_REF device type, even if D3DDEVTYPE_NULLREF is specified. If D3dref9.dll is not available and D3DDEVTYPE_NULLREF is specified, Direct3D will neither render nor present the scene.
1.2 COM
组件对象模型(COM, Component Object Model)是一种能使DirectX独立于编程语言和具有向下兼容性的技术。我们通常把COM对象作为一个接口,你可以把它当作达到某种目的的C++类来使用它。当使用C++写DirectX程序的时候,COM的大部分细节对我们来说是透明。但是有一件事,我们必须知道,那就是我们通过某个特殊的COM接口的函数或指针获得了另一个COM接口指针,而不是通过C++的新关键字来创建它。当我们使用完某个接口后,调用它的Release方法比直接Delete它更好。COM对象具有它们自己的内存管理。
对COM来说还有很多细节可以了解,但是掌握这些细节对于我们有效的使用DirectX不是必须的。
注意:COM接口都具有前缀大写字母“I”,例如表示一个表面的COM接口叫做IDirect3DSurface9。
1.3 一些准备工作
Direct3D的初始化过程要求我们对图形学基础知识和Direct3D类型有一定了解。这里将介绍这些知识和类型,以确保以后能把焦点集中在讨论Direct3D的初始化上。
1.3.1 表面
表面是一个像素点阵,在Direct3D中主要用来存储2D图形数据。图1.2指明了表面的一些成分。由图可以看出表面数据就像一个矩阵,像素数据实际上存储在线性数组里面。
表面的Width和Height是按像素计算的。Pitch以字节为单位。而且Pitch有可能比Width大且依赖于低层硬件,所以不能单纯的认为Pitch = Width * sizeof (pixelFormat)。
在代码中,我们可以使用IDirect3DSurface9接口来描述表面。这个接口提供若干方法来直接读写表面数据并且还有一个方法用来返回表面息。IDirect3DSurface9中最重要的方法是:
l LockRect——使用这个方法,我们将获得一个指向表面内存的指针,然后,通过一系列指针运算,我们可以对表面上任一个像素点进行读、写操作。
Locks a rectangle on a surface.
HRESULT LockRect(
D3DLOCKED_RECT * pLockedRect,
CONST RECT * pRect,
DWORD Flags
);
Parameters
- pLockedRect
- [out] Pointer to a D3DLOCKED_RECT structure that describes the locked region.
- pRect
- [in] Pointer to a rectangle to lock. Specified by a pointer to a RECT structure. Specifying NULL for this parameter expands the dirty region to cover the entire surface.
- Flags
- [in] Combination of zero or more locking flags that describe the type of lock to perform. For this method, the valid flags are:
- D3DLOCK_DISCARD
- D3DLOCK_DONOTWAIT
- D3DLOCK_NO_DIRTY_UPDATE
- D3DLOCK_NOSYSLOCK
- D3DLOCK_READONLY
Return Values
If the method succeeds, the return value is D3D_OK.
If the method fails, the return value can be D3DERR_INVALIDCALL or D3DERR_WASSTILLDRAWING.
Remarks
If the D3DLOCK_DONOTWAIT flag is specified and the driver cannot lock the surface immediately, IDirect3DSurface9::LockRect will return D3DERR_WASSTILLDRAWING so that an application can use the CPU cycles while waiting for the driver to lock the surface.
The only lockable format for a depth-stencil surface is D3DFMT_D16_LOCKABLE. See D3DFORMAT.
For performance reasons, dirty regions are recorded only for level zero of a texture. Dirty regions are automatically recorded when IDirect3DSurface9::LockRect is called without D3DLOCK_NO_DIRTY_UPDATE or D3DLOCK_READONLY. See IDirect3DDevice9::UpdateTexture for more information.
A multisample back buffer cannot be locked.
This method cannot retrieve data from a surface that is is contained by a texture resource created with D3DUSAGE_RENDERTARGET because such a texture must be assigned to D3DPOOL_DEFAULT memory and is therefore not lockable. In this case, use instead IDirect3DDevice9::GetRenderTargetData to copy texture data from device memory to system memory.
l UnlockRect——当你调用了LockRect和完成了对表面内存的访问后,你必须调用这个方法给表面解锁。
Unlocks a rectangle on a surface.
HRESULT UnlockRect();
Parameters
None.
Return Values
If the method succeeds, the return value is D3D_OK. If the method fails, the return value can be D3DERR_INVALIDCALL.
l GetDesc——这个方法将通过填充D3DSURFACE_DESC结构来返回表面的描述信息。
D3DSURFACE_DESC
Describes a surface.
typedef struct D3DSURFACE_DESC {
D3DFORMAT Format;
D3DRESOURCETYPE Type;
DWORD Usage;
D3DPOOL Pool;
D3DMULTISAMPLE_TYPE MultiSampleType;
DWORD MultiSampleQuality;
UINT Width;
UINT Height;
} D3DSURFACE_DESC, *LPD3DSURFACE_DESC;
Members
- Format
- Member of the D3DFORMAT enumerated type, describing the surface format.
- Type
- Member of the D3DRESOURCETYPE enumerated type, identifying this resource as a surface.
- Usage
- Either the D3DUSAGE_DEPTHSTENCIL or D3DUSAGE_RENDERTARGET values. For more information, see D3DUSAGE.
- Pool
- Member of the D3DPOOL enumerated type, specifying the class of memory allocated for this surface.
- MultiSampleType
- Member of the D3DMULTISAMPLE_TYPE enumerated type, specifying the levels of full-scene multisampling supported by the surface.
- MultiSampleQuality
- Quality level. The valid range is between zero and one less than the level returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType. Passing a larger value returns the error, D3DERR_INVALIDCALL. The MultisampleQuality values of paired render targets, depth stencil surfaces and the MultiSample type must all match.
- Width
- Width of the surface, in pixels.
- Height
- Height of the surface, in pixels.
Retrieves a description of the surface.
HRESULT GetDesc(
D3DSURFACE_DESC * pDesc
);
Parameters
- pDesc
- [out] Pointer to a D3DSURFACE_DESC structure, describing the surface.
Return Values
If the method succeeds, the return value is D3D_OK.
D3DERR_INVALIDCALL is returned if the argument is invalid.
最初锁定表面和改写每一像素看来稍微有点迷茫。下面的代码表示锁定表面并将每一像素染成红色:
// Assume _surface is a pointer to an IDirect3DSurface9 interface.
// Assumes a 32-bit pixel format for each pixel.
// Get the surface description.
D3DSURFACE_DESC surfaceDesc;
_surface->GetDesc(&surfaceDesc);
// Get a pointer to the surface pixel data.
D3DLOCKED RECT lockedRect;
_surface->LockRect(
&lockedRect,// pointer to receive locked data
0, // lock entire surface
0); // no lock flags specified
// Iterate through each pixel in the surface and set it to red.
DWORD* imageData = (DWORD*)lockedRect.pBits;
for(int i = 0; i < surfaceDesc.Height; i++)
{
for(int j = 0; j < surfaceDesc.Width; j++)
{
// index into texture, note we use the pitch and divide by
// four since the pitch is given in bytes and there are 4 bytes per DWORD.
int index = i * lockedRect.Pitch / 4 + j;
imageData[index] = 0xffff0000; // red
}
}
_surface->UnlockRect();
程序中D3DLOCKED_RECT结构的定义如下:
typedef struct _D3DLOCKED RECT {
INT Pitch; // the surface pitch
void *pBits; // pointer to the start of the surface memory
} D3DLOCKED_RECT;
在这里有一些关于表面锁定代码的一些说明。32-bit像素格式这个设定很重要,我们把bits转换成DWORDs。这让我们能把每一个DWORD视为表示一个像素。