要使用 Direct3D,首先创建一个应用程序窗口,然后创建和初始化 Direct3D 对象。 您使用这些对象实现的组件对象模型 (COM) 接口来操作它们并创建渲染场景所需的其他对象。 本教程所基于的 CreateDevice 示例项目通过创建 Direct3D 设备并呈现蓝屏来说明这些任务。本教程使用以下步骤来初始化 Direct3D、渲染场景并最终关闭。
脚步
- 第 1 步 - 创建一个窗口
- 第 2 步 - 初始化 Direct3D
- 第 3 步 - 处理系统消息
- 第 4 步 - 渲染和显示场景
- 第 5 步 - 关机
笔记 |
---|
CreateDevice示例工程的路径是: (SDK 根目录)\Samples\C++\Direct3D\Tutorials\Tut01_CreateDevice |
第 1 步 - 创建一个窗口
任何 Windows 应用程序在运行时必须做的第一件事就是创建一个应用程序窗口以显示给用户。 为此,CreateDevice 示例项目从其 WinMain 函数开始执行。 以下示例代码执行窗口初始化。
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
{
// Register the window class.
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
"Direct3D Tutorial", NULL };
RegisterClassEx( &wc );
// Create the application's window.
HWND hWnd = CreateWindow( "Direct3D Tutorial", "Direct3D Tutorial 01: CreateDevice",
WS_OVERLAPPEDWINDOW, 100, 100, 300, 300,
GetDesktopWindow(), NULL, wc.hInstance, NULL );
}
前面的代码示例是标准的 Windows 编程。该示例首先定义和注册一个名为“Direct3D Tutorial”的窗口类。注册类后,示例代码创建一个使用注册类的基本顶级窗口,客户区为 300 像素宽 x 300 像素高。此窗口没有菜单或子窗口。该示例使用 WS_OVERLAPPEDWINDOW 窗口样式来创建一个窗口,该窗口包括窗口化应用程序常用的最小化、最大化和关闭按钮。 (如果示例在全屏模式下运行,首选的窗口样式是 WS_EX_TOPMOST,它指定创建的窗口应该放置在所有非最顶层窗口之上并且应该保持在它们之上,即使在窗口被停用时也是如此。) 当创建窗口后,代码示例调用标准 Win32 函数来显示和更新窗口。
准备好应用程序窗口后,您可以开始设置基本的 Direct3D 对象,如步骤 2 - 初始化 Direct3D 中所述。
第 2 步 - 初始化 Direct3D
CreateDevice 示例项目在创建窗口后从 WinMain 调用的 InitD3D 应用程序定义函数中执行 Direct3D 初始化。 创建应用程序窗口后,您就可以初始化用于渲染场景的 Direct3D 对象了。 这个过程包括创建对象、设置表示参数,最后创建 Direct3D 设备。
创建 Direct3D 对象后,使用 IDirect3D9::CreateDevice 方法创建设备,并枚举设备、类型、模式等。
if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
return E_FAIL;
传递给 Direct3DCreate9 的唯一参数应始终是 D3D_SDK_VERSION。 这会通知 Direct3D 正在使用正确的头文件。 每当标头或其他更改需要重新构建应用程序时,此值就会增加。 如果版本不匹配,Direct3DCreate9 将失败。
通过填写 D3DPRESENT_PARAMETERS 字段,您可以指定您希望 3D 应用程序的行为方式。 CreateDevice 示例项目将 Windowed 设置为 TRUE,将 SwapEffect 设置为 D3DSWAPEFFECT_DISCARD,并将 BackBufferFormat 设置为 D3DFMT_UNKNOWN。
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
最后一步是使用 IDirect3D9::CreateDevice 方法创建 Direct3D 设备,如以下代码示例所示。
if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_pd3dDevice ) ) )
前面的代码示例使用 D3DADAPTER_DEFAULT 标志创建具有默认适配器的设备。 在大多数情况下,系统将只有一个适配器,除非它安装了多个图形硬件卡。 通过为 DeviceType 参数指定 D3DDEVTYPE_HAL 来指示您更喜欢硬件设备而不是软件设备。 此代码示例使用 D3DCREATE_SOFTWARE_VERTEXPROCESSING 告诉系统使用软件顶点处理。 请注意,如果您通过指定 D3DCREATE_HARDWARE_VERTEXPROCESSING 告诉系统使用硬件顶点处理,您将在支持硬件顶点处理的视频卡上看到显着的性能提升。
现在 Direct3D 对象已初始化,下一步是确保您拥有处理系统消息的机制,如步骤 3 - 处理系统消息中所述。
第 3 步 - 处理系统消息
创建应用程序窗口并初始化 Direct3D 后,您就可以渲染场景了。 在大多数情况下,Windows 应用程序在其消息循环中监视系统消息,并在队列中没有消息时呈现帧。 但是,CreateDevice 示例项目一直等到队列中出现 WM_PAINT 消息,告诉应用程序它需要重绘全部或部分窗口。
// The message loop.
MSG msg;
while( GetMessage( &msg, NULL, 0, 0 ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
每次循环运行时,DispatchMessage 都会调用 MsgProc,后者处理队列中的消息。 当 WM_PAINT 排队时,应用程序调用 Render,这是应用程序定义的函数,将重绘窗口。 然后调用 Win32 函数 ValidateRect 来验证整个客户区。消息处理函数的示例代码如下所示。
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_DESTROY:
PostQuitMessage( 0 );
return 0;
case WM_PAINT:
Render();
ValidateRect( hWnd, NULL );
return 0;
}
return DefWindowProc( hWnd, msg, wParam, lParam );
}
现在应用程序处理了系统消息,下一步是渲染显示,如第 4 步 - 渲染和显示场景中所述。
第 4 步 - 渲染和显示场景
为了渲染和显示场景,这一步中的示例代码将后台缓冲区清除为蓝色,将后台缓冲区的内容传输到前台缓冲区,并将前台缓冲区呈现给屏幕。
要清除场景,请调用 IDirect3DDevice9::Clear 方法。
// Clear the back buffer to a blue color
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );
IDirect3DDevice9::Clear 接受的前两个参数通知 Direct3D 要清除的矩形数组的大小和地址。矩形数组描述了渲染目标表面上要清除的区域。
在大多数情况下,您使用一个覆盖整个渲染目标的矩形。您可以通过将第一个参数设置为零并将第二个参数设置为 NULL 来执行此操作。第三个参数确定方法的行为。您可以指定一个标志来清除渲染目标表面、关联的深度缓冲区、模板缓冲区或三者的任意组合。本教程不使用深度缓冲区,因此 D3DCLEAR_TARGET 是唯一使用的标志。最后三个参数设置为反映渲染目标、深度缓冲区和模板缓冲区的清除值。 CreateDevice 示例项目将渲染目标表面的透明颜色设置为蓝色 (D3DCOLOR_XRGB(0,0,255))。最后两个参数被 IDirect3DDevice9::Clear 方法忽略,因为相应的标志不存在。
清除视口后,CreateDevice 示例项目通知 Direct3D 渲染将开始,然后发出渲染完成的信号,如以下代码片段所示:
// Begin the scene
g_pd3dDevice->BeginScene();
// Rendering of scene objects happens here
// End the scene
g_pd3dDevice->EndScene();
IDirect3DDevice9::BeginScene 和 ID3DXRenderToSurface::EndScene 方法在渲染开始或完成时向系统发出信号。 您只能在调用这些方法之间调用渲染方法。 即使渲染方法失败,您也应该在再次调用 IDirect3DDevice9::BeginScene 之前调用 ID3DXRenderToSurface::EndScene。
渲染场景后,使用 IDirect3DDevice9::Present 方法显示它。
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
前两个参数是源矩形和目标矩形。 此步骤中的示例代码通过将这两个参数设置为 NULL,将整个后缓冲区呈现给前缓冲区。 第三个参数设置此演示文稿的目标窗口。 因为此参数设置为 NULL,所以使用 D3DPRESENT_PARAMETERS 的 hWndDeviceWindow 成员。 第四个参数是 DirtyRegion 参数,在大多数情况下应设置为 NULL。
本教程的最后一步是关闭应用程序,如第 5 步 - 关闭中所述。
第 5 步 - 程序结束
在执行期间的某个时刻,您的应用程序必须关闭。 关闭 DirectX 应用程序不仅意味着您破坏了应用程序窗口,而且还取消了应用程序使用的任何 DirectX 对象的分配,并使指向它们的指针无效。 CreateDevice 示例项目调用 Cleanup,这是一个应用程序定义的函数,用于在收到 WM_DESTROY 消息时处理此问题。
VOID Cleanup()
{
if( g_pd3dDevice != NULL)
g_pd3dDevice->Release();
if( g_pD3D != NULL)
g_pD3D->Release();
}
前面的函数通过为每个对象调用 IUnknown 方法来解除分配它使用的 Direct3D 对象。 因为本教程遵循 COM 规则,所以大多数对象的引用计数应该为零,并且应该自动从内存中删除。
除了关机之外,在正常执行期间,有时您可能需要销毁并重新创建正在使用的 Microsoft Direct3D 对象,例如当用户更改桌面分辨率或颜色深度时。 因此,最好将应用程序的清理代码保存在一个地方,以便在需要时调用。
本教程向您展示了如何创建设备。 教程 2:渲染顶点向您展示如何使用顶点绘制几何形状。
运行效果: