DX程序第一件事是创建DX对象,相当于初始化DirectX。
LPDIRECT3D9X g_pD3D = Direct3DCreate9( D3D_SDK_VERSION);
if(NULL == g_pD3D) return E_FAILE;
每个程序都是由此开始的,而且写法都一样,参数必须是D3D_SDK_VERSION。
创建设备
DirectX是位于硬件抽象层上的设备,程序员通过访问DX提供的接口来间接操作设备。设备大致分为
1. HAL设备。硬件抽象层的主要设备,硬件加速即在此处理。
2. 软件设备。当某种特效硬件不支持,那么可以用软件的方法,让CPU来计算,因此这称为软件设备。
3. 参考设备。无论有无硬件,都使用CPU来计算。
了解了设备的种类后,接下来就是创建设备了。
CreateDevice( UINT Adapter,
D3DDEVTYPE DeviceType,
HWND hFocusWindow,
DWORD BehaviorFlags,
D3DPRESENT_PARAMETERS *pPresentationParameters,
IDirect3DDevice9** ppReturnedDeviceInterface
);
Adapter 指定显示适配器序列号,用于指示哪块显卡创建Direct3D对象,显然,当有多块显卡时或显卡上有多个接口时,这个参数能起来区分作用。我没有找到如何获取此值的API,只看文档上提到“先取得显卡设备,再枚举Adpater”。通常这个参数D3DADAPTER_DEFAULT(这是一个宏,其值是当前适配器的序列号)。
DeviceType 这便是上面提到的3种设备。D3DDEVTYPE是个枚举,D3DDEVTYPE_HAL代表HAL设备,通常也是取这个值。
hFocusWindow 指出那个窗口取得焦点。
BehaviorFlags 设备的工作方式。是一些细节问题,通常用D3DCREATE_SOFTWARE_VERTEXPROCESSING,表示顶点由软件运算。
D3DPRESENT_PARAMETERS 本结构很复杂,也很重要。
typedef struct _D3DPRESENT_PARAMETERS_ {
UINT BackBufferWidth, BackBufferHeight;
D3DFORMAT BackBufferFormat;
UINT BackBufferCount;
D3DMULTISAMPLE_TYPE MultiSampleType;
DWORD MultiSampleQuality;
D3DSWAPEFFECT SwapEffect;
HWND hDeviceWindow;
BOOL Windowed;
BOOL EnableAutoDepthStencil;
D3DFORMAT AutoDepthStencilFormat;
DWORD Flags;
UINT FullScreen_RefreshRateInHz;
UINT PresentationInterval;
} D3DPRESENT_PARAMETERS;
●BackBufferWidth, BackBufferHeight 指定后台缓冲窗口的宽度和高度。当程序在非全屏模式下,如果它们为0,即是默认窗口的大小。
●BackBufferFormat 指定后台缓冲区像素格式。像素格式就不多说了。
●BackBufferCount 后台缓冲区的数量。可取0,1,2和3。取0时与到1一样,表示1个缓冲区。缓冲区的数量与交换链有关,这个稍后讨论。
●MultiSampleType 指定多重采样数量。采样越多,反锯齿效果越好。
●MultiSampleQuality 多重采样的质量。取值范围是0到1,并且小于CheckDeviceMultiSampleType返值。因为反锯齿效果需要一定资源,如果采样数量过多或质量过高,可能系统达不到要求。所以如果需要反锯齿,那么最好用这个API检测是否合适。
●SwapEffect 设置后台缓存复制到前台的方式。注意的是,如果设置不是D3DSWAPEFFECT_DISCARD(复制到前台后清除后台缓存内容)时,多重采样必须是0( D3DMULTISAMPLE_NONE)。
●hDeviceWindow 指定图形绘制窗口。默认时为当前被激活的窗口。
●Windowed 如果为TRUE,则以窗口方式显示,反之以全屏方式显示。
●EnableAutoDepthStencil,AutoDepthStencilFormat,Flags, FullScreen_RefreshRateInHz?
CreateDevice的参数差不多就讲完了。最复杂的要数D3DPRESENT_PARAMETERS参数了,不过很多时候用默认值0就可以了,所以常见的CreateDevice是这样写的
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = TRUE; //窗口模式
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
//表示像素模式与适配器的相同
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;
if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_pd3dDevice ) ) )
return E_FAIL;
Direct3D应用程序的基本结构
Direct3D应用程序的基本结构分为:
1. 初始化Direct3D
2. 渲染图形
3. 如果程序不退出,GOTO 2
3. 结束Direct3D
上面CreateDevice部分大致就是Direct3D初始化了,接下来是渲染图形
VOID Render( )
{
//清空后台缓冲区
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );
if(SUCCEEDED(g_pd3dDevice->BeginScene()))
{
//后台缓冲区绘制图形
……
//线束后台缓冲区渲染
g_pd3dDevice->EndScene();
}
g_pd3dDevice->Present(NULL, NULL, NULL, NULL);
}
从这段代码可以看出,DX图形绘制是在后台缓冲区进行的,而且代码位于BeginScene和EndScene之间。
清空后台缓冲区也是有意思函数,第一、二参数代表清空的区域,当设置为0和NULL时代表清空整个窗口。第三个参数是D3DCLEAR枚举组合,它有三个值D3DCLEAR_TARGET,D3DCLEAR_ZBUFFER, D3DCLEAR_STENCIL。TARGET即表面象素的颜色,ZBUFFER即是深度缓冲区,STENCIL代表蒙板,打个比方,赛车游戏中,车子窗外的景色的变,而车内的一般不变,所以可以设个蒙板,使每次刷新只改变窗外的区域。第四、五、六个参数就是分别对应上面三个枚举值了。
提到渲染,一个重要的概念就是表面及表面管理。表面就像是存放在内存(显存)中的一张位图;前台缓冲区,是由显卡传送到显示器的一块内存,它是不能被DX写入的;后台缓冲区,是DX真正绘图的地方;表面翻转(flipping surfaces),将后台提交到前台的过程称之为表面翻转;交换链,后台与前台表面指针所组成的循环链表,以便快速、有序地提交后台表面到前台,而且不必再分配新内存(原来的前台表面指针放到后台缓冲表面链表的后面,相当于把前台表面用于后台表面)