最近想要把由CUDA计算生成的图像直接做显示,所以开始学一下D3D,把我自己学习记录整理,既可以与同道分享交流,又是对自己的鞭策吧!开篇我还是比较喜欢把要学的东西整理结构理解下,所以从D3D的简述开始写吧!
一、D3D简述
由微软公司开发的DirectX,并不是一个单纯的图形API,它包含有Direct Graphics(Direct 3D+Direct Draw)、Direct Input、Direct Play、Direct Sound、Direct Show、Direct Setup、Direct Media Objects等多个组件,它提供了一整套的多媒体接口方案。
D3D即Direct3D是DirectX的三维部分,集成了开发DirectX程序三维图形部分的所有API程序,同时它支持与CUDA的互操作,这样经CUDA并行计算后图像数据可以直接供D3D做显示,这非常适合图形图像系统的研发。
二、D3D程序基本结构
一个D3D程序除去Windows窗口生成和消息传递(这属于MFC的工作),主要包含3个步骤:初始化D3D设备资源,图形显示设置和D3D资源设备释放。
1、初始化D3D设备资源
这个步骤的目的就是完成Direct3D对象的创建,D3D初始化的几个主要函数和结构体说明:
因为D3D是基于COM机制的,而COM对象是对实际模型的抽象定义,只有通过接口才能访问操作COM对象,所以首先需要创建一个D3D接口,方法如下:
LPDIRECT3D9 g_pD3D = NULL;
g_pD3D=Direct3DCreate9(D3D_SDK_VERSION);
LPDIRECT3D9的对象是D3D程序的最顶层对象,其它对象都必须通过它的接口函数调用得到。
Direct3DCreate9(D3D_SDK_VERSION)函数就是创建一个当前版本的一个D3D对象并返回接口。
然后就是创建D3D设备对象,由LPDIRECT3D9的对象调用HRESULT IDirect3D9:: CreateDevice()函数完成,参数说明可以参考下面代码和说明文档
D3DPRESENT_PARAMETERS结构体包含了D3D设备的相关信息,这些信息会影响D3D设备的显示方法。
下面是初始化D3D设备资源比较通用的一个代码示例
IDirect3DDevice9* g_pd3dDevice; //Direct3D 设备指针
void Cdig_D3DDlg::InitD3D(UINT hWnd)//函数的入口参数为窗口句柄
{
m_hwndRender =GetDlgItem(hWnd)->GetSafeHwnd();//当前显示窗口
LPDIRECT3D9 g_pD3D = NULL; //Direct3D对象指针(不是设备指针)
g_pD3D=Direct3DCreate9(D3D_SDK_VERSION); //D3D_SDK_VERSION是版本的检查
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp,sizeof(d3dpp));
d3dpp.Windowed=TRUE;//window or full screen
d3dpp.BackBufferFormat=D3DFMT_UNKNOWN;//Surface format is unknown
d3dpp.SwapEffect=D3DSWAPEFFECT_DISCARD;
//The handle of the Windows window attached to
//this CWnd. The m_hWnd data member is a public variable of type HWND.
d3dpp.hDeviceWindow= m_hwndRender;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
//显卡序号:D3DADAPTER_DEFAULT
//D3D设备类型:D3DDEVTYPE_HAL,D3DDEVTYPE_REF和D3DDEVTYPE_SW
//所属窗口:m_hwndRender
//运算方式:D3DCREATE_SOFTWARE_VERTEXPROCESSING
//D3D相关参数:d3dpp
//Direct3D 设备指针:g_pd3dDevice
g_pD3D->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL, m_hwndRender,D3DCREATE_SOFTWARE_VERTEXPROCESSING,&d3dpp,&g_pd3dDevice);
g_pD3D->Release();
}
2、图形显示
D3D的程序习惯将这一步骤用Render函数,当然可以随便取名。这一步骤最核心的四个函数。
HRESULT IDirect3DDevice9::Clear函数的作用是在绘制函数前,重置viewport的缓冲区,这是在绘制3D图形前必须调用的。用法可以参见说明文档
BeginScene()和EndScene()分别为开始和结束渲染,两者必须成对出现,并且不允许嵌套和交错。注意图形渲染的结果是存储在后台缓冲区的。
HRESULT IDirect3DDevice9:: Present()函数是将图形渲染的结果由后台缓冲区复制到前台缓冲区予以显示。
下面就是一个完整的图形渲染显示程序框架,可以得到一个没有任何图元的背景图像:
HRESULT Cdig_D3DDlg::render()
{
if( g_pd3dDevice )
{
//
// Draw the scene.
//
g_pd3dDevice->Clear(0, 0,
D3DCLEAR_TARGET ,
D3DCOLOR_XRGB(125,0,255), 1.0f,0);
g_pd3dDevice->BeginScene();
//添加纹理渲染,图元绘制等函数
g_pd3dDevice->EndScene();
//将渲染的结果存储到后台缓冲区
//0表示更新所有的缓冲区
g_pd3dDevice->Present(0, 0, 0, 0);
}
return S_OK;
}
3、D3D设备资源释放
释放D3D设备资源的方法如下:
if( g_pd3dDevice )
g_pd3dDevice->Release();
Release()函数会将调用这个设备的DirectX对象的引用计数减1,当DirectX对象的引用计数为0时,它就会释放它所占有的资源。虽然这个步骤很简单,但却不能忽略。
好了,到此为止,一个最基本的D3D程序结构就有了,想一想觉得其实蛮简单的,后面边学边写吧!
对了,附上一个编译配置的说明:
第一步:安装DirectX SDK(June 2008)和Microsoft Visual Studio 2005
第二步:设置DirectX和Visual Studio 2005关联:
<1> 打开Visual Studio 2005,将D3D需要的Lib 文件目录在链接器中指定路径。具体步骤是:工具->选项->项目和解决方案->VC++目录,在右边“显示以下内容的目录”中选择“包含文件”,加入directx中的Include目录,我电脑上的该目录为D:/program files/directx9/Include。添加完Include头文件后,再选择库文件,加入lib文件,我电脑上的该目录为D:/program files/directx9/Lib/x86
<2> 打开sdk的sample里面的一个例子,打开时打开.sln文件,引用几个相关的lib文件,具体步骤是:项目->属性->配置属性->链接器->输入,在附加依赖项里面加入下面几个lib文件:
d3dxof.lib
dxguid.lib
d3dx9d.lib
d3d9.lib
winmm.lib
第三步:设置好后,就可以执行D3D程序了。