Lookof 's Wild

Last of the Wild

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

这篇是关于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)中找到该代码。)

 

 

  1//-----------------------------------------------------------------------------
  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( 00255 ), 1.0f0 );
 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, 0L0L,
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, 100100300300,
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, 00 ) )
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


posted on 2009-08-21 11:21  lookof  阅读(1432)  评论(0编辑  收藏  举报