




已阅读5页,还剩8页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
基于Visual Studio.Net(7.0)环境结合Direct3D 9.0与MFC的应用程序开发创作于2003年3月16日,发表在美Frank Luna著石立兴 翻译Tuesday, August 31, 2010(注:原著的Direct3D 8.1版本创作于2002年4月8日,在网页/reference/articles/article1778.asp上可以查看)1.1 简介在结合DirectX API(API:Application Programming Interface应用程序编程接口)和MFC(MFC:Microsoft Foundation Classes微软基础类库)的应用程序开发中常常会遇到一些麻烦。虽然DirectX SDK(SDK:Software Development Kit API软件开发包)提供了一些在MFC架构上实现DirectX运用的例子,然而其中没有一个是使用document/view结构或者应用程序向导的方式实现的。这篇文章将一步一步地向读者展现,在Visual Studio .Net中,如何使用MFC的程序设计向导以及document/view结构,在MFC架构上创建一个Direct3D 9.0的应用程序。当然,我们假设读者已经有一些Direct3D和MFC的编程经验了,只不过尚未尝试如何将它们结合起来使用。我们将创建的这个项目是一个简单的例子;它将向一个网格数据结构中载入一个茶壶,并且使它绕着Y轴旋转。最终绘制的结果将如下图所示,当然,程序中的茶壶是运动的。图1:本文中所创建的应用程序运行时的截图1.2 创建项目为了让您能看清楚每一个步骤,本文将以较慢的速度展开论述。首先,我们将在Visual Studio .Net(VS7)中创建一个新项目。在下图所示的对话框中选择MFC Application(MFC应用程序)的图标,键入项目名称,如“Direct3D9MFC”,然后点击“OK”按钮。图2:为该项目选择一个MFC应用程序模板在接下来的对话框中,MFC应用程序设计向导允许您配置将要创建的应用程序。选择左侧的Application Type 标签,如图3所示。然后选择程序类型为Single document,确保Document/View architecture support选项已勾选。剩下的设置保留其默认值,最后点击“Finish”按钮,完成应用程序的创建。图3:设置并创建应用程序。通过该对话框指定您将创建的程序的基本属性。在本例程中,我们需要一个单文档接口并且将使用文档/视图结构在单击“Finish”按钮后,程序模板就被成功创建了。当然,为了确保万无一失,在继续下一步之前还是建议您编译,生成,执行一下您的项目。下面,在我们将Direct3D结合到MFC之前,应该先将Direct3D函数库“d3d9.lib”和“d3dx9.lib”链接到我们的项目中。此外,为了使用计时函数,我们还需要将“winmm.lib”链接进来。在VS7中,您可以用如下方式链接函数库:点击菜单项ProjectPropertiesLinkerInput Folder,然后在如图4所示的输入框中键入函数库的名称:图4:将“d3d9.lib”、“d3dx9.lib”及“winmm.lib”链接到项目中1.3 结合Direct3D与MFC为了将Direct3D结合到MFC中,我们让CDirect3D9MFCView(派生于CView)包含Direct3D相关的一些接口。之所以这样,是因为CDirect3D9MFCView是负责绘制数据的,它需要直接访问Direct3D的功能函数来绘制3D模型。1.3.1 为CDirect3D9MFCView 添加成员变量首先,我们将以下变量添加到CDirect3D9MFCView 类中:#include class CDirect3D9MFCView : public CView.private:IDirect3DDevice9* _device;D3DPRESENT_PARAMETERS _d3dpp;ID3DXMesh* _teapot;对于刚添加的前两个变量类型,_device 和 _d3dpp,您应该是不陌生了。作为Direct3D的基本数据类型,在准备阅读这篇文章前,您对它们的作用和用法应该都有所认识。为此,我就不再对它们作更细致的说明了。第三个变量,_teapot,是一个网格数据结构,用于存储该示例程序所要绘制的茶壶的几何信息。注意:记得在定义CDirect3D9MFCView 类的文件的开头包含“d3dx9.h”头文件。注意CDirect3D9MFCView 类的构造函数和析构函数如下:CDirect3D9MFCView:CDirect3D9MFCView(): _device(0), _teapot(0):ZeroMemory(&_d3dpp, sizeof(_d3dpp);CDirect3D9MFCView:CDirect3D9MFCView()if( _teapot )_teapot-Release();if( _device )_device-Release();1.3.2 为CDirect3D9MFCView 添加成员函数下面,将下列函数添加到CDirect3D9MFCView类中:class CDirect3D9MFCView : public CView.private:HRESULT initD3D(HWND hwnd,int width,int height,bool windowed,D3DDEVTYPE deviceType);HRESULT setup(int width, int height);HRESULT cleanup();public:HRESULT update(float timeDelta);HRESULT render(); 函数initD3D负责Direct3D的初始化,即,获取一个指向IDirect3DDevice9接口的指针。该IDirect3DDevice9接口基于输入的各个参数配置。为简明起见,在初始化Direct3D时,本示例程序的代码忽略了设备枚举,并选择了“安全配置”。本文相应的示例程序有关Direct3D初始化的函数实现如下:HRESULT CDirect3D9MFCView:initD3D(HWND hwnd,int width,int height,bool windowed,D3DDEVTYPE deviceType)HRESULT hr = 0;/ Step 1: Create the IDirect3D9 object.IDirect3D9* d3d9 = 0;d3d9 = Direct3DCreate9(D3D_SDK_VERSION);if( !d3d9 ):MessageBox(0, Direct3DCreate9() - FAILED, 0, 0);return E_FAIL;/ Step 2: Check for hardware vp.D3DCAPS9 caps;d3d9-GetDeviceCaps(D3DADAPTER_DEFAULT, deviceType, &caps);int vp = 0;if( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT )vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;elsevp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;/ Step 3: Fill out the D3DPRESENT_PARAMETERS structure._d3dpp.BackBufferWidth = width;_d3dpp.BackBufferHeight = height;_d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;_d3dpp.BackBufferCount = 1;_d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;_d3dpp.MultiSampleQuality = 0;_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;_d3dpp.hDeviceWindow = hwnd;_d3dpp.Windowed = windowed;_d3dpp.EnableAutoDepthStencil = true;_d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;_d3dpp.Flags = 0;_d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;_d3dpp.PresentationInterval =D3DPRESENT_INTERVAL_IMMEDIATE;/ Step 4: Create the device.hr = d3d9-CreateDevice(D3DADAPTER_DEFAULT, / primary adapterdeviceType, / device typehwnd, / window associated with devicevp, / vertex processing&_d3dpp, / present parameters&_device); / return created deviceif( FAILED(hr) )/ try again using a safer configuration._d3dpp.AutoDepthStencilFormat = D3DFMT_D16;hr = d3d9-CreateDevice(D3DADAPTER_DEFAULT,deviceType,hwnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING,&_d3dpp,&_device);if( FAILED(hr) )d3d9-Release(); / done with d3d9 object:MessageBox(0, CreateDevice() - FAILED, 0, 0);return hr;d3d9-Release(); / done with d3d9 objectreturn S_OK; setup函数负责处理程序中仅与Direct3D相关的代码。其中包括:分配Direct3D资源、确认设备性能以及设置设备状态。本文相应的示例程序中setup函数实现如下:HRESULT CDirect3D9MFCView:setup(int width, int height)if( _device )/ Set view matrix.D3DXMATRIX V;D3DXVECTOR3 pos (0.0f, 0.0f, -6.0f);D3DXVECTOR3 target (0.0f, 0.0f, 0.0f);D3DXVECTOR3 up (0.0f, 1.0f, 0.0f);D3DXMatrixLookAtLH(&V, &pos, &target, &up);_device-SetTransform(D3DTS_VIEW, &V);/ Create the teapot.if( !_teapot)D3DXCreateTeapot(_device, &_teapot, 0);/ Use wireframe mode and turn off lighting._device-SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);_device-SetRenderState(D3DRS_LIGHTING, false);/ Size the viewport based on window dimensions.D3DVIEWPORT9 vp = 0, 0, width, height, 0.0f, 1.0f;_device-SetViewport( &vp );/ Set the projection matrix based on the/ window dimensions.D3DXMATRIX P;D3DXMatrixPerspectiveFovLH(&P,D3DX_PI * 0.25f,/45-degree field of view(float)width / (float)height,1.0f,1000.0f);_device-SetTransform(D3DTS_PROJECTION, &P);return S_OK; cleanup函数用于清除在调用IDirect3DDevice9:Reset函数前需要释放的所有资源。由于本程序在调用IDirect3DDevice9:Reset函数前没有需要释放的资源,故而本文相应的示例程序中cleanup函数的定义为空。当然,值得注意的是,在调用IDirect3DDevice9:Reset函数前只有一些特定的资源是需要释放的,比如在D3DPOOL_DEFAULT内存池中的那些资源。HRESULT CDirect3D9MFCView:cleanup()/ Nothing to Destroy.return S_OK; 在update函数中,您将运行一些用于帧的更迭过程中处理信息的操作,例如,动画,碰撞检测,测试用户输入等。需要注意的是,帧与帧之间的时间差将作为函数的参数引入到函数中去。这样您就可以让各个操作基于时间同步起来。本文相应的示例程序中update函数实现如下:HRESULT CDirect3D9MFCView:update(float timeDelta)if( _device )/ Spin the teapot around the y-axis./static float angle = 0.0f;D3DXMATRIX yRotationMatrix;D3DXMatrixRotationY(&yRotationMatrix, angle);_device-SetTransform(D3DTS_WORLD, &yRotationMatrix);angle += timeDelta;if(angle = D3DX_PI * 2.0f)angle = 0.0f;return S_OK; 在render函数,您运行与绘制相关的操作,这也是基于帧的更迭的。本文相应的示例程序中render函数实现如下:HRESULT CDirect3D9MFCView:render()if( _device )/ Draw the scene./_device-Clear(0, 0,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,0x00000000, 1.0f, 0);_device-BeginScene();/ Draw the teapot._teapot-DrawSubset(0);_device-EndScene();_device-Present(0, 0, 0, 0);return S_OK;1.3.3 创建Direct3D接口下面,我们要弄清楚在哪个位置来创建我们的Direct3D接口,也就是说在什么地方调用initD3D函数。其实在哪儿创建Direct3D接口并不重要,只要是在我们得到一个有效地窗口句柄之后,而使用这个接口之前就可以了。我采用重载CView:OnInitialUpdate函数的方式来实现它。为了重载该函数,在VS7环境下,选择右下角CDirect3D9MFCView属性页上的重载按钮,如图5所示。找到列表中的OnInitialUpdate函数,然后点击其右侧向下的箭头,在弹出的列表中点击Add(添加)。图5:选择重载按钮,从列表中找到并选择“OnInitialUpdate”选项,然后点击向下箭头,选择“Add”在示例程序中,OnInitialUpdate函数的实现如下:void CDirect3D9MFCView:OnInitialUpdate()CView:OnInitialUpdate();CRect rect;GetClientRect(&rect);/ Initialize Direct3D (e.g. acquire a IDirect3DDevice9 poniter).HRESULT hr = initD3D(GetSafeHwnd(),rect.right,rect.bottom,true,D3DDEVTYPE_HAL);if(FAILED(hr)MessageBox(initD3D() - Failed, Error);:PostQuitMessage(0);/ Setup the application.hr = setup(rect.right, rect.bottom);if(FAILED(hr)MessageBox(setup() - Failed, Error);:PostQuitMessage(0);1.3.4 处理WM_SIZE消息由于很多Direct3D的成员与窗口的尺寸紧密相关,比如缓存、视口、投影矩阵等,因而在窗口的尺寸变化时,我们应该重设这些成员的属性值。这也是为什么我们要确定当窗口被重新设置尺寸时应该做哪些相应的调整。我们通过处理WM_SIZE消息来达到更新参数的目的。在VS7环境下,找到右下角CDirect3D9MFCView属性页上重载按钮旁边的的Message按钮,如图5所示。选择列表中的WM_SIZE消息,然后点击右侧向下的箭头,在弹出的列表中选择“Add OnSize”选项。在示例程序中,OnSize函数的实现如下:void CDirect3D9MFCView:OnSize(UINT nType, int cx, int cy)CView:OnSize(nType, cx, cy);if( _device )HRESULT hr = 0;/ On a resize we must change the dimensions of the/ back buffers to match the new window size._d3dpp.BackBufferWidth = cx;_d3dpp.BackBufferHeight = cy;/ We are about to call Reset, free any resources/ that need to be freed prior to a Reset.hr = cleanup();if(FAILED(hr)MessageBox(destroy() - Failed, Error);:PostQuitMessage(0);/ Reset the flipping chain with the new window dimensions./ Note that all device states are reset to the default/ after this call.hr = _device-Reset(&_d3dpp);if(FAILED(hr)MessageBox(Reset() - Failed, Error);:PostQuitMessage(0);/ Reinitialize resource and device states since we/ Reset everything.hr = setup(cx, cy);if(FAILED(hr)MessageBox(setup() - Failed, Error);:PostQuitMessage(0);1.3.5 处理WM_ERASEBKGND消息 现在我们一直在涉及消息处理这个主题,同样的,我们应该为WM_ERASEBKGND消息编写一个处理函数。其实很简单,我们只需要让相应的处理函数什么都不做就可以了。这样每次我们绘制的时候就可以防止MFC擦除背景了。之所以要阻止MFC擦除背景,是因为我们有Direct3D来管理绘制的图形,也就是说,我们用Direct3D来擦除背景而不是让Direct3D和MFC争着抢着来干这件事情。更何况,使用MFC来擦除背景会带来一系列的闪屏。您可以像重载处理WM_SIZE消息的函数那样重载处理WM_ERASEBKGND消息的函数,只是此时您选择的应该是WM_ERASEBKGND消息。BOOL CDirect3D9MFCView:OnEraseBkgnd(CDC* pDC)return FALSE;1.3.6 更新与绘制下面,我们把注意力转向如何把update(更新)和render(绘制)嵌入到MFC架构当中去。在标准的Win32应用程序中,我们通常在程序的空闲时间来更新和绘制。在这里我们也采用相同的办法,重载CWinApp:OnIdle函数。您可以像重载CView:OnInitialUpdate函数那样重载CWinApp:OnIdle函数,不过,此时您应该在应用程序类中(比如CDirect3D9MFCApp)去找这个要重载的函数而不是在视图类中,因为OnIdle是CWinApp中的函数。在示例程序中,我们这样来实现CDirect3D9MFCApp:OnIdle函数:BOOL CDirect3D9MFCApp:OnIdle(LONG lCount)CWinApp:OnIdle(lCount);CWnd* mainFrame = AfxGetMainWnd();CDirect3D9MFCView* cview =(CDirect3D9MFCView*)mainFrame-GetWindow(GW_CHILD);/ Save last time.static float lastTime = (float)timeGetTime();/ Compute time now.float currentTime = (float)timeGetTime();/ Compute the difference: time elapsed in seconds.float de
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 分行业绩考核规定
- 家电维修管理体系规范
- 在党旗下擦亮人民教师的精神名片教师节专题党课
- 2025浙江温州瑞安市司法局编外人员招聘1人笔试参考题库附答案解析
- 动物遗传多样性研究总结
- 2025云南省昭通市建飞中学招聘教师笔试备考试题及答案解析
- 考研英语听力:如何迅速提高水平
- 农村新型社会组织发展模式分析
- 2025西北工业学校教师招聘笔试含答案
- 榨汁机贷款量维修规定
- 临床常用他评量表
- 2025学年度第一学期政史地教研组工作计划
- 马龙课件简短
- 2024-2025学年广东省清远市高三(上)质检数学试卷(一)(含答案)
- 2025年高考作文素材积累之刘擎《西方现代思想讲义》大纲梳理
- 《中小学德育工作指南》全文
- (新版)海事集装箱装箱检查员考试题库及答案
- 车位租赁协议
- 云南省工程质量安全手册实施细则(试行)安全管理行为分册
- 2024 体育生规章制度
- 幼教培训课件:《幼儿园科学核心经验与活动指导》
评论
0/150
提交评论