这篇是关于Directx 3D 的。
什么是DX、D3D?
DX(DirectX)是一组微软开发的API。旨在服务以windows为平台的游戏或多媒体程序。这是一组较为底层的API。它将形色各异的硬件底层(不同品牌的显卡、声卡、键盘鼠标等)吸纳进来,代以统一的开发接口暴露开放给开发者。这样开发者在开发游戏或者多媒体程序时就不必担心硬件差异,也不用理会底层细节。当然,微软做到这一点不是靠自己的DX去适应不同的硬件,而是由支持DX的硬件厂商(被微软拉拢过去的)负责提供一套HAL(Hardware Abstraction Layer)驱动程序供DX使用。这就使得同一个DX命令在不同品牌的硬件上能够产生的一致的结果。
厂商用自己的方式实现了对某一种标准的支持,反过来令用户几乎注意不到“厂商实现”这一环节,这种现象在计算机行业乃至整个工业,非常普遍。不同的水管厂商会对同一型号的水管口径设计一致的大小;不同的浏览器厂商也会对HTML语言提供一致的解析(尽管像MS这样的往往不屑一顾)、不同的C++编译器厂商会对C++标准提供一致的支持(MS依然例外…)。我们往往关注的是C++、HTML是什么,怎么写。同理,现在我们学习的是DX是什么,怎么写。但脑子我们一定要有一个概念,DX和硬件本身,一定有这样一层HAL的。推而广之对于整个硬件层来说,这层HAL就是驱动程序。
DX中的D,即Direct,意为“直的,直接的”;X比喻为“丰富多彩的,功能多样的”。“用户可以直来直去很方便地实现丰富多样的功能”,这就是DX所表达的涵义。
DX不是一个单独的图形API。它包含有Direct Graphics(Direct 3D+Direct Draw)、Direct Input、Direct Play、Direct Sound、Direct Show、Direct Setup、Direct Media Objects等多个组件,它提供了一整套的多媒体接口方案。只是由于其中的Direct 3D过于优秀,使其它方面显得暗淡无光。
最新DX版本为11,发布于MS的潜力股Windows 7 Beta版本中。
Note:我的学习版本依然使用DX9.
D3D(DirectX 3D)上面提到过,它是DX的一个子组件API。也是DX团队中最抢眼的主力队员,也因此最重要和最复杂。它负责处理图形方面的工作。在版本9之前,它只负责3D图形,2D图形由Direct Draw组件负责;自9开始,D3D全面接管了Direct Draw的工作,统一负责2D图形和3D图形。
D3D在windows平台上几乎是游戏开发者选用的圣经。缺点是跨平台性不够(DX就是为巩固windows的地位设计的)。也因此,它最大的竞争对手是openGL(open Graphic Library)。openGL也是一组图形API。最初由SGI公司开发。它可以在linux、mac OS等多个平台上使用(当然也可以在windows上跑)。8卦一句,openGL一开始还是很猛的(俺之前就是GL这方阵营地…),只是后来不敌MS的“卑劣”商业行径,慢慢失去了市场主导地位。起码现在D3D的用户是越来越多了,相衬下GL就带了那么点悲壮的凉意。
从哪里开始DX?
到官网下载最新DirectX SDK包。我提供的这个链接依然是版本9的。当然这是SDK嘛,没有开发环境的话也就失去了意义。我用的开发环境是VS.NET 2003。DX下载后安装,之后就可以使用了。你会在“开始”->“程序”菜单中找到Microsoft DirectX 9.0 SDK Update (August 2005) (版本号因人而异,我这个很老了)的选项。内有DX各种工具、CHM帮助文档、以及演示Samples。CHM涵盖的资料非常丰富:编程指导、工具介绍、参考手册、教程示例等等,应有尽有(翔实的资料同时也是一种考验耐力的挑战)。教程不光step-by-step,也提供了现成的源码路径,你可以找到源码后在vs环境下直接编译体验。
第一个DX程序?
首先建立一个空的win32工程。添加新c++文件。项目->属性->链接器->输入->附加依赖项 中填入“d3d9.lib”。
接着粘贴以下代码。编译、链接,之后第一个DX程序就出炉了。尽管它除了一个蓝色的窗口外什么都没有。
(NOTE:你也可以从$(DXSDK_DIR)\Samples\C++\Direct3D\Tutorials\Tut01_CreateDevice)中找到该代码。)
2// File: CreateDevice.cpp
3//
4// Desc: This is the first tutorial for using Direct3D. In this tutorial, all
5// we are doing is creating a Direct3D device and using it to clear the
6// window.
7//
8// Copyright (c) Microsoft Corporation. All rights reserved.
9//-----------------------------------------------------------------------------
10#include <d3d9.h>
11#pragma warning( disable : 4996 ) // disable deprecated warning
12#include <strsafe.h>
13#pragma warning( default : 4996 )
14
15
16
17
18//-----------------------------------------------------------------------------
19// Global variables
20//-----------------------------------------------------------------------------
21LPDIRECT3D9 g_pD3D = NULL; // Used to create the D3DDevice
22LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; // Our rendering device
23
24
25
26
27//-----------------------------------------------------------------------------
28// Name: InitD3D()
29// Desc: Initializes Direct3D
30//-----------------------------------------------------------------------------
31HRESULT InitD3D( HWND hWnd )
32{
33 // Create the D3D object, which is needed to create the D3DDevice.
34 if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
35 return E_FAIL;
36
37 // Set up the structure used to create the D3DDevice. Most parameters are
38 // zeroed out. We set Windowed to TRUE, since we want to do D3D in a
39 // window, and then set the SwapEffect to "discard", which is the most
40 // efficient method of presenting the back buffer to the display. And
41 // we request a back buffer format that matches the current desktop display
42 // format.
43 D3DPRESENT_PARAMETERS d3dpp;
44 ZeroMemory( &d3dpp, sizeof( d3dpp ) );
45 d3dpp.Windowed = TRUE;
46 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
47 d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
48
49 // Create the Direct3D device. Here we are using the default adapter (most
50 // systems only have one, unless they have multiple graphics hardware cards
51 // installed) and requesting the HAL (which is saying we want the hardware
52 // device rather than a software one). Software vertex processing is
53 // specified since we know it will work on all cards. On cards that support
54 // hardware vertex processing, though, we would see a big performance gain
55 // by specifying hardware vertex processing.
56 if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
57 D3DCREATE_SOFTWARE_VERTEXPROCESSING,
58 &d3dpp, &g_pd3dDevice ) ) )
59 {
60 return E_FAIL;
61 }
62
63 // Device state would normally be set here
64
65 return S_OK;
66}
67
68
69
70
71//-----------------------------------------------------------------------------
72// Name: Cleanup()
73// Desc: Releases all previously initialized objects
74//-----------------------------------------------------------------------------
75VOID Cleanup()
76{
77 if( g_pd3dDevice != NULL )
78 g_pd3dDevice->Release();
79
80 if( g_pD3D != NULL )
81 g_pD3D->Release();
82}
83
84
85
86
87//-----------------------------------------------------------------------------
88// Name: Render()
89// Desc: Draws the scene
90//-----------------------------------------------------------------------------
91VOID Render()
92{
93 if( NULL == g_pd3dDevice )
94 return;
95
96 // Clear the backbuffer to a blue color
97 g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB( 0, 0, 255 ), 1.0f, 0 );
98
99 // Begin the scene
100 if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
101 {
102 // Rendering of scene objects can happen here
103
104 // End the scene
105 g_pd3dDevice->EndScene();
106 }
107
108 // Present the backbuffer contents to the display
109 g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
110}
111
112
113
114
115//-----------------------------------------------------------------------------
116// Name: MsgProc()
117// Desc: The window's message handler
118//-----------------------------------------------------------------------------
119LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
120{
121 switch( msg )
122 {
123 case WM_DESTROY:
124 Cleanup();
125 PostQuitMessage( 0 );
126 return 0;
127
128 case WM_PAINT:
129 Render();
130 ValidateRect( hWnd, NULL );
131 return 0;
132 }
133
134 return DefWindowProc( hWnd, msg, wParam, lParam );
135}
136
137
138
139
140//-----------------------------------------------------------------------------
141// Name: wWinMain()
142// Desc: The application's entry point
143//-----------------------------------------------------------------------------
144INT WINAPI wWinMain( HINSTANCE hInst, HINSTANCE, LPWSTR, INT )
145{
146 // Register the window class
147 WNDCLASSEX wc =
148 {
149 sizeof( WNDCLASSEX ), CS_CLASSDC, MsgProc, 0L, 0L,
150 GetModuleHandle( NULL ), NULL, NULL, NULL, NULL,
151 L"D3D Tutorial", NULL
152 };
153 RegisterClassEx( &wc );
154
155 // Create the application's window
156 HWND hWnd = CreateWindow( L"D3D Tutorial", L"D3D Tutorial 01: CreateDevice",
157 WS_OVERLAPPEDWINDOW, 100, 100, 300, 300,
158 NULL, NULL, wc.hInstance, NULL );
159
160 // Initialize Direct3D
161 if( SUCCEEDED( InitD3D( hWnd ) ) )
162 {
163 // Show the window
164 ShowWindow( hWnd, SW_SHOWDEFAULT );
165 UpdateWindow( hWnd );
166
167 // Enter the message loop
168 MSG msg;
169 while( GetMessage( &msg, NULL, 0, 0 ) )
170 {
171 TranslateMessage( &msg );
172 DispatchMessage( &msg );
173 }
174 }
175
176 UnregisterClass( L"D3D Tutorial", wc.hInstance );
177 return 0;
178}
179
180
181
182
在这里强调的是,需要包含头文件d3d9.h。
WinMain函数和MsgProc函数,熟悉win32编程的人都很熟悉这两个函数。因为任何一个win32程序都必须有它们俩。前者是入口函数,在这个函数里必须定义窗口类、建立窗口、建立消息循环等等;而后者是消息处理函数,程序运行时接收到各类消息时该怎么反馈,就在这里定义。
还剩下三个函数。其中最关键是InitD3D和Render这两个函数。InitD3D负责D3D环境的初始化,Rnder负责实际的渲染工作。Cleanup的作用是扫尾。不论申请了什么资源使用完毕后应该释放,这个思路对于程序开发而言是非常自然的。
对于实时渲染,无论是用D3D还是openGL,一般都会分为两个阶段。第一个阶段负责环境的初始化,这个阶段只在程序运行开始时运行一次;第二阶段负责实时渲染绘制,这个阶段会在程序中不停循环反复运行。每运行一次,我们就可以看作是绘制了一帧。我们平时说的FPS(帧率)就是指一秒中这第二个阶段循环了多少次。当程序要结束时,触发退出事件跳出循环。然后回收资源,退出程序。我喜欢称第一个阶段为离线阶段,第二个阶段为在线阶段。在我们这个例子里,InitD3D是离线阶段,Render是在线阶段。
(未完待续)
参考资料:
http://baike.baidu.com/view/15762.htm