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.
組件對象模型(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
You may not specify a subrect when using D3DLOCK_DISCARD. For a description
of the flags, see D3DLOCK.
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轉換成DWORD
s。這讓我們能把每一個DWORD視為表示一個像素。