【DirectX 3D游戏开发】DirectX 3D 窗口的创建

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/shangdi712/article/details/48327437

            3D窗口创建工程下载链接:点击打开链接

            我前面在我DirectX 2D 游戏的开发的博客里写过关于DirectX 2D游戏窗口的创建,当然那个2D并不是DirectX Draw 的2D,而是运用DirectX Sprite组件,实现2D效果,而3D 游戏需要的窗口创建方法,跟2D基本差不多,不一样的地方有,但是很少,但是,为了帮助一下新手,我还是尽可能 的说一下,当然,不会比我前一篇,DirectX 2D 窗口创建详细         

1.创建IDirect3D接口
           为了使用D3D中的函数,我们得先定义一个指向IDirect3D9这个接口的指针,顺便说明一下为什么要定义这个指针。 首先,我们要知道接口的内容就是一些纯虚拟函数,所以接口是不能被实例化的,但是我们可以定义一个指向接口的指针。
            其次,我们要知道利用多态性我们可以使用一个基类指针来访问派生类中的方法。既然接口是不能被实例化的,那么我们肯定是使用从接口派生出来的类(或结构)的方法。怎么获到这个派生类的指针呢?就是通过之前定义的接口指针(也即是基类指针)来获得。所以我们所需做的就是把一个接口指针的地址传给某个函数,让这个函数来帮我们获到正确的派生类指针,这样我们就可以使用接口指针来做一些实际的东西了。实际上,我们只需要知道接口里面有什么方法以及它能完成什么工作就行了,至于这些方法是怎么实现的我们不必去关心。
            我们要做的就是定义一个接口指针,把它传给某个函数,函数使我们的接口指针有意义,接着我们使用接口,就这么简单。定义完这个接口指针后,使用Direct3DCreate9这个函数来创建一个D3D接口
g_pD3D = Direct3DCreate9( D3D_SDK_VERSION );
            Direct3DCreate9这个函数只有一个参数,它表明要创建接口的版本。如果你想创建一个老的接口版本当然也可以,不过没有人会那样做吧。
2.检测硬件能力(可选)
            代码如下:
        D3DCAPS9 caps;
	ZeroMemory(&caps,sizeof(caps));
	g_pD3D->GetDeviceCaps(
		D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,&caps);
            这个东西怎么理解呢,就理解成一张表,然后通过GetDeviceCaps()这个函数,填起这张表,这张表就是通过caps这个结构体产生的,这张表哪来的呢,找到DX SDK的文件夹,里面有个Utilites文件夹,点开它,然后点开bin文件夹,然后点开x86文件夹,里面有个DXCapViewer.exe,双击打开它,点开你那个显卡型号所对应的选项卡,然后点开D3D Device Types,然后再点开HAL选项卡,里面有个Caps,双击它,然后右面有一张表,这就是那张表,那个函数就是把那张表填起来。
3.创建D3D 显示模式结构体,获取当前显卡模式
             这个说白了,就是获取显卡模式,就跟那个caps差不多一个意思
        D3DDISPLAYMODE d3ddm;
	ZeroMemory(&d3ddm,sizeof(d3ddm));
	g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,
		&d3ddm);
4.创建D3D设备
创建接口后就可以创建D3D设备了,什么是D3D设备?你可以想象为你机上的那块显卡!什么?你有几块显卡!!没关系,那就创建多几个D3D设备接口吧。创建D3D设备需要的参数很多,如果把那些参数都挤在一个函数里面,那就太长了,所以就把一些参数放进结构体里面,只要先设定好这些结构体,再把这些结构体当作参数传给创建D3D设备的函数,那就清晰多了。首先要讲的就是D3DPRESENT_PARAMETERS这个结构。下面是它的定义:
struct D3DPRESENT_PARAMETERS{ 
 UINT BackBufferWidth; 
 UINT BackBufferHeight; 
 D3DFORMAT BackBufferFormat; 
 UINT BackBufferCount; 
 D3DMULTISAMPLE_TYPE MultiSampleType; 
 DWORD MultiSampleQuality; 
 D3DSWAPEFFECT SwapEffect; 
 HWND hDeviceWindow; 
 BOOL Windowed; 
 BOOL EnableAutoDepthStencil; 
 D3DFORMAT AutoDepthStencilFormat; 
 DWORD Flags; 
 UINT FullScreen_RefreshRateInHz; 
 UINT PresentationInterval; 
}; 

真正的带有赋予实参的代码为

D3DPRESENT_PARAMETERS d3dpp;
	ZeroMemory(&d3dpp,sizeof(d3dpp));
	
	d3dpp.Windowed = true;	//窗口模式
	
	////-------全屏模式的写法:---------
	//d3dpp.Windowed = false;
	//d3dpp.BackBufferWidth = d3ddm.Width;
	//d3dpp.BackBufferHeight = d3ddm.Height;
	
	d3dpp.BackBufferFormat = d3ddm.Format;
	d3dpp.BackBufferCount = 1;

	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;

	//是否开启自动深度模板缓冲
	d3dpp.EnableAutoDepthStencil = true;
	//当前自动深度模板缓冲的格式
	d3dpp.AutoDepthStencilFormat = D3DFMT_D16;


BackBufferWidth和BackBufferHeight:后备缓冲的宽度和高度。在全屏模式下,这两者的值必需符合显卡所支持的分辨率。例如(800,600),(640,480)。


BackBufferFormat:后备缓冲的格式。这个参数是一个D3DFORMAT枚举类型,它的值有很多种,例如D3DFMT_R5G6B5,这说明后备缓冲的格式是每个像素16位,其实红色(R)占5位,绿色(G)占6位,蓝色(B)占5位,为什么绿色会多一位呢?据说是因为人的眼睛对绿色比较敏感。DX9只支持16位和32位的后备缓冲格式,24位并不支持。如果对这D3DFORMAT不熟悉的话,可以把它设为D3DFMT_UNKNOWN,这时候它将使用桌面的格式。


扫描二维码关注公众号,回复: 3779344 查看本文章

BackBufferCount:后备缓冲的数目,范围是从0到3,如果为0,那就当成1来处理。大多数情况我们只使用一个后备缓冲。使用多个后备缓冲可以使画面很流畅,但是却会造成输入设备响应过慢,还会消耗很多内存。


MultiSampleType和MultiSampleQuality:前者指的是全屏抗锯齿的类型,后者指的是全屏抗锯齿的质量等级。这两个参数可以使你的渲染场景变得更好看,但是却消耗你很多内存资源,而且,并不是所有的显卡都支持这两者的所设定的功能的。在这里我们分别把它们设为D3DMULTISAMPLE_NONE和0。


SwapEffect:交换缓冲支持的效果类型,指定表面在交换链中是如何被交换的。它是D3DSWAPEFFECT枚举类型,可以设定为以下三者之一:D3DSWAPEFFECT_DISCARD,D3DSWAPEFFECT_FLIP,D3DSWAPEFFECT_COPY。如果设定为D3DSWAPEFFECT_DISCARD,则后备缓冲区的东西被复制到屏幕上后,后备缓冲区的东西就没有什么用了,可以丢弃(discard)了。如果设定为D3DSWAPEFFECT_FLIP,则表示在显示和后备缓冲之间进行周期循环。设定D3DSWAPEFFECT_COPY的话,我也不太清楚有什么作用*^_^*。一般我们是把这个参数设为D3DSWAPEFFECT_DISCARD。


hDeviceWindow:显示设备输出窗口的句柄


Windowed:如果为FALSE,表示要渲染全屏。如果为TRUE,表示要渲染窗口。渲染全屏的时候,
BackBufferWidth和BackBufferHeight的值就得符合显示模式中所设定的值。


EnableAutoDepthStencil:如果要使用Z缓冲或模板缓冲,则把它设为TRUE。


AutoDepthStencilFormat:如果不使用深度缓冲,那么这个参数将没有用。如果启动了深度缓冲,那么这个参数将为深度缓冲设定缓冲格式(和设定后备缓冲的格式差不多)


Flags:可以设置为0或D3DPRESENTFLAG_LOCKABLE_BACKBUFFER。不太清楚是用来做什么的,看字面好像是一个能否锁定后备缓冲区的标记。


FullScreen_RefreshRateInHz:显示器的刷新率,单位是HZ,如果设定了一个显示器不支持的刷新率,将会不能创建设备或发出警告信息。为了方便,一般设为D3DPRESENT_RATE_DEFAULT就行了。


PresentationInterval:如果设置为D3DPRENSENT_INTERVAL_DEFAULT,则说明在显示一个渲染画面的时候必要等候显示器刷新完一次屏幕。例如你的显示器刷新率设为80HZ的话,则一秒内你最多可以显示80个渲染画面。另外你也可以设置在显示器刷新一次屏幕的时间内显示1到4个画面。如果设置为D3DPRENSENT_INTERVAL_IMMEDIATE,则表示可以以实时的方式来显示渲染画面,虽然这样可以提高帧速(FPS),但是却会产生图像撕裂的情况。


当你把D3DPRESENT_PARAMETERS的参数都设置好后,就可以创建一个D3D设备了,和创建D3D接口一样,先定义一个接口指针IDirect3DDevice9 * g_pD3DDevice;然后使用D3D接口里面的CreateDevice函数来创建设备。CreateDevice的声明为:
HRESULT CreatDevice( 
 UINT Adapter, 
 D3DDEVTYPE DeviceType, 
 HWND hFocusWindow, 
 DWORD BehaviorFlags, 
 D3DPRESENT_PARAMETERS *pPresentationParameters, 
 IDirect3DDevice9** ppReturnedDeviceInterface 
}; 

实际调用的代码为
g_pD3D->CreateDevice(
		D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,
		g_hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING,
		&d3dpp,&g_pDevice);



  第一个参数说明要为哪个设备创建设备指标,我之前说过一台机可以有好几个显卡,这个参数就是要指明为哪块显卡创建可以代表它的设备指标。但是我怎么知道显卡的编号呢?可以使用D3D接口里面的函数来获得,例如GetAdapterCounter可以知道系统有几块显卡;GetAdapterIdentifier可以知道显卡的具体属性。一般我们设这个参数为D3DADAPTER_DEFAULT。

  第二个参数指明正在使用设备类型。一般设为D3DEVTYPE_HAL。

  第三个参数指明要渲染的窗口。如果为全屏模式,则一定要设为主窗口。

  第四个参数是一些标记,可以指定用什么方式来处理顶点。

  第五个参数就要用到上面所讲的D3DPRESENT_PARAMETERS。

  第六个参数是返回的界面指针。
5.设置渲染状态:设置启用深度值,记住,3D 游戏一定要设置深度值
	g_pDevice->SetRenderState(D3DRS_ZENABLE,true);

6.开始渲染

  有了设备接口指针,就可以开始渲染画面了。渲染是一个连续不断的过程,所以必定要在一个循环中完成,没错,就是第一章讲的那个消息循环。在渲染开始之前我们要用IDirect3DDevice9::Clear函数来清除后备缓冲区。

HRESULT Clear( 
 DWORD Count, 
 const D3DRECT *pRects, 
 DWORD Flags, 
 D3DCOLOR Color, 
 float Z, 
 DWORD Stencil 
); 



Count:说明你要清空的矩形数目。如果要清空的是整个客户区窗口,则设为0;

pRects:这是一个D3DRECT结构体的一个数组,如果count中设为5,则这个数组中就得有5个元素。它可以使我们只清除屏幕中的某一部分。

Flags:一些标记组合,它指定我们要清除的目标缓冲区。只有三种标记:D3DCLEAR_STENCIL , D3DCLEAR_TARGET , D3DCLEAR_ZBUFFER。 分别为清除模板缓冲区、清除目标缓冲区(通常为后备缓冲区)、清除深度缓冲区。

Color:清除目标区域所使用的颜色。

float:设置Z缓冲的Z初始值。小于或等于这个Z初始值的Z值才会被改写,但它的值只能取0到1之间。如果还不清楚什么是Z缓冲的话,可以自己找相关数据看一下,这里不介绍了

Stencil:设置范本缓冲的初始值。它的取值范围是0到2的n次方减1。其中n是范本缓冲的深度。

清除后备缓冲区后,就可以对它进行渲染了。渲染完毕,使用Present函数来把后备缓冲区的内容显示到屏幕上。
HRESULT Present( 
 const RECT *pSourceRect, 
 const RECT *pDestRect, 
 HWND hDestWindowOverride, 
 const RGNDATA *pDirtyRegion 
); 



pSourceRect:你想要显示的后备缓冲区的一个矩形区域。设为NULL则表示要把整个后备缓冲区的内容都显示。

pDestRect:表示一个显示区域。设为NULL表示整个客户显示区。

hDestWindowOverride:你可以通过它来把显示的内容显示到不同的窗口去。设为NULL则表示显示到主窗口。

pDirtyRegion:高级使用。一般设为NULL。

然后再在之间加入BegineScene()和EndScene()即可

实例代码如下:

	g_pDevice->Clear(
		0,			//清空矩形的数量
		nullptr,	//清空矩形的临接信息
		D3DCLEAR_TARGET,	//要清空颜色缓冲区
		D3DCOLOR_XRGB(123,123,234),	//清成什么颜色
		1.0f,	//深度缓冲区的初始值
		0		//模板缓冲区的初始值
		);
	g_pDevice->BeginScene();		//获取绘制权限
	//---------------------------------------
	//		渲染代码
	//---------------------------------------
	g_pDevice->EndScene();		//结束绘制
	//前后台缓冲区交换的"源动力"
	g_pDevice->Present(nullptr, nullptr, 0, nullptr);
}

总而言之,这个3D环境和2D 环境的区别在哪呢,

1.  d3dpp 多设置两个属性,分别是开启深度模板缓冲,和设置深度模板缓冲

2.多了使用SetRanderStates()函数设置渲染状态

3.多了检测硬件代码能力这一步,虽然这一步不是必须的,

4.没了,其它和3D 环境搭建一模一样


猜你喜欢

转载自blog.csdn.net/shangdi712/article/details/48327437