Lookof 's Wild

Last of the Wild

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

Note:这是(I)的下篇,并不是一篇独立的主题。它的上篇和中篇分别在这里这里

Render()函数做了些什么

在消息处理函数中,针对WM_PAINT消息,会有Render函数的调用。该函数负责D3D实体的绘制。让我们分析下它的代码。

Code

 

这段代码很简单,总共做了三件事。第一,清空后台缓冲区的数据;第二,绘制场景;第三,将绘制好的场景搬到前台缓冲区,以便显示在屏幕上。

“清空后台缓冲区数据”是通过调用D3D设备对象的方法Clear方法起作用的。这个函数有6个参数,查找SDK,会发现它的原型如下:

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

下面依旧说说我的理解。

Count and pRects这两个参数合起来约束了一件事情,即指定一堆需要清空的矩形。也就是说,我们可以指定清空屏幕上指定位置和大小的矩形范围的数据,而且这个矩形范围还可以不止一个(当然一个也可以)。你会猜到,这么“一堆”的矩形最好存放的地方就是在一个数组里。Count表示矩形的数量,而PRects是一个指向这个矩形数组的指针。一般情况下,这两个都是0,表示要清空“整屏”的数据。注意当pRects是0时Count一定要为0,反之当PRects不为0(代表至少指定了一个矩形)时Count也一定不能为0。

Flags: 这个旗位的值是一组宏,代表了要清空的目标缓冲区是什么。我们知道后台缓冲区有多个类型(模板缓存、深度缓存、颜色缓存等等),因此需要明确清空的是哪个缓冲区。它的值有:D3DCLEAR_STENCIL, D3DCLEAR_TARGET, D3DCLEAR_ZBUFFER三种。分别表示模板缓冲区、目标缓冲区和深度缓冲区。一般选择D3DCLEAR_TARGET。模板缓冲区和深度缓冲区可以被清除的前提是它们首先是存在的,否则调用这个函数时就会返回一个错误。

Color: 这是一个D3DCOLOR类型的数据,表示要以什么颜色清空(“填充”)该缓冲区。设定为什么颜色,被清空的区域的背景就会显示为什么颜色。关于D3DCOLOR的结构请自行查阅。这里这个值是D3DCOLOR_XRGB( 0, 0, 255 )。

Z:用这个值填充指定区域的深度缓冲区数据。范围在0到1之间。如果关闭深度缓存,则不会被改写。

Stencil:用这个值填充指定区域的模板缓冲区数据。范围在0到2n–1之间。这里的n是模板缓冲区一个像素单位的比特数。

我们这里的代码仅仅指定了要清空整个目标缓冲区,颜色是蓝色。z为1和stencil为0不会发生作用,因为我们并没有指定要清空这两个区域。需要补充一句的是,Flags的值在实际应用中一般是D3DCLEAR_TARGET 和 D3DCLEAR_ZBUFFER的组合。

 

接下来是绘制场景。这是通过D3D设备对象的一对方法共用来实现的。这一对方法是:

D3DDeviceObj->BeginScene()
     //…具体绘制命令
D3DDeviceObj->EndScene()

如果你学过openGL,会发现它们在这一点的机制上有很大雷同之处。具体的图元绘制命令必须写在这一对命令之间才会起作用。我们这里的例子是空的,因为我们的目的仅仅是搭一个框架而已。

 

再接下来我们把绘制好的后台缓冲区交换到前台缓冲区去。这里用到了D3D设备对象的Prensent方法。还是看看SDK上它的函数原型。

HRESULT Present(CONST RECT *pSourceRect,
                        CONST RECT *pDestRect,   
                        HWND hDestWindowOverride,   
                        CONST RGNDATA *pDirtyRegion );

它有四个参数。我对此的理解是:

pSourceRect: 指向一个矩形结构,它表示源缓冲区(即后台缓冲区)中的一个矩形范围。如果为NULL的话,则表示整个缓冲区。注意,还记得我们一开始创建D3D设备对象时所指定的“参数”结构体(pPresentationParameters)吗?它里面指定了一个SwapEffect值,只有当这个值是D3DSWAPEFFECT_COPY时,这里的PSourceRect才可以不为NULL(至于为什么,我也不清楚)。所以一般来说,这个值设为NULL即可。

pDestRect:和pSourceRect一样,只不过这里换成了目标缓冲区(前台缓冲区)中的矩形。

hDestWindowOverride:指向一个窗口句柄,表示将把前台缓冲区绘制在哪个窗口里。如果设为NULL,则采用“参数”结构体(pPresentationParameters)里hDeviceWindow成员所指定的窗口。一般就是指当前窗口。

pDirtyRegion:指向一个“脏矩形”的指针。有关“脏矩形”的话题我们以后单独再说。现在设为NULL即可。

因此这个函数实际写起来会是一个很壮观的样子:g_pd3dDevice->Present( NULL, NULL, NULL, NULL )

这个函数到这里就写完了。总结一下:当D3D设备对象创建好后,就可以进入帧循环中进行图形的绘制了。在每一次循环中,又包含了三步:清除缓冲区,绘制缓冲区和交换缓冲区。

 

Cleanup()函数做了些什么

当退出程序的时候,要执行Cleanup()函数。

1 VOID Cleanup()
2 {
3     if( g_pd3dDevice != NULL) 
4         g_pd3dDevice->Release();
5 
6     if( g_pD3D != NULL)
7         g_pD3D->Release();
8 }
9 

 

这个步骤很简单,首先检测有无D3D设备对象,有的话予以释放;接着检测有无D3D对象,有的话予以释放。

 

总结

总算讲完了。回顾看一下,我们发现搭建一个D3D应用程序框架的步骤其实仅仅几步:创建D3D对象->创建D3D设备对象->进入帧循环(清空缓冲区->绘制缓冲区->交换缓冲区)->释放对象和资源->结束。 但是在每一步进行时,要设置比较多的参数,因此就成了一件比较费力的事情(windows的每一个API无不充满了非常多的参数…汗)。因此倘若打算实用,则用一个框架类来封装这些基本设置是一个不错的主意。框架类是另一个我想记录的主题,以后会单独成章来写,这里就不提了。

posted on 2009-09-10 19:10  lookof  阅读(1498)  评论(0编辑  收藏  举报