科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件VC中借助DirectDraw实现水波的模拟

VC中借助DirectDraw实现水波的模拟

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

本文介绍了一种对水面波纹的扩散、衰减以及交叠的过程进行计算机模拟的一种实现算法。

作者:青岛郎锐 来源:天极网 2007年10月19日

关键字:

  • 评论
  • 分享微博
  • 分享邮件
三、 利用DirectDraw完成对图形的加速

  从前面可以看出,我们一直在处理速度上比较严格。竭尽所能来提高数据的处理速度,不仅在算法上如此,在显示上更是如此。普通的GDI函数的处理速度在这里是无法容忍的,对此采用了DirectX系列技术中的DirectDraw技术来对图形进行加速处理。

  DirectDraw是DirectX SDK系列中的一员,也是其中最主要的一个部件。它允许程序员直接的操作显存、硬件位图映射以及硬件覆盖和换页技术。它在提供直接访问显示设备的同时,与GDI相兼容,它只是一个软件接口,提供了一种与设备无关的途径,以获得访问特定的显示设备的某些高级特性的能力。大体上DirectDraw可以提供了以下几个功能,而这些功能以前只有那些专为特定显示设备所写的软件中才能使用:

  ·支持双缓冲和换页图形

  ·访问、控制显示卡的位图映射

  ·支持3D z-buffers (z缓存)

  ·支持z方向(z-ordering)硬件辅助覆盖。

  ·访问图形缩放硬件

  ·仿真访问标准的和增强的显示设备内存空间

  下面就对DirectDraw的在图形加速方面中的具体应用结合本程序的具体实例来进行介绍,为方便起见,本工程采用Microsoft SDK编码,先要对DirectDraw环境进行初始化,完成设置并在其中对主页面和各离屏页面进行创建并初始化之:

BOOL InitDDraw(void)
{
 DDSURFACEDESC ddsd;
 HRESULT ddrval;
 ……
 //创建DirectDraw对象
 ddrval = DirectDrawCreate( NULL, &lpDD, NULL );
 ……
 //取得全屏独占模式
 ddrval = lpDD->SetCooperativeLevel(hwndful, DDSCL_EXCLUSIVE | DSCL_FULLSCREEN );
 ……
 //设置显示器显示模式
 ddrval = lpDD->SetDisplayMode( DISPLAYMODEWIDTH,DISPLAYMODEHEIGHT, 24);
 ……
 //填充主页面信息
 ddsd.dwSize = sizeof( ddsd );
 ddsd.dwFlags = DDSD_CAPS ;
 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
 //创建主页面对象
 ddrval = lpDD->CreateSurface( &ddsd, &lpDDSPrimary, NULL );
 ……
 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT |DDSD_WIDTH;
 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN |DDSCAPS_SYSTEMMEMORY ;
 ……
 lpDD->CreateSurface(&ddsd, &lpDDSPic1, NULL) ;
 ……
 lpDD->CreateSurface(&ddsd, &lpDDSPic2, NULL);
 ……
 lpDD->CreateClipper(0, &lpClipper, NULL);
 lpClipper->SetHWnd(0, hwndful);
 lpDDSPrimary->SetClipper(lpClipper);
 ……
 //初始化页面图像
 DDReLoadBitmap(lpDDSPic1, MAKEINTRESOURCE(IDB_BITMAP1));
 DDReLoadBitmap(lpDDSPrimary,MAKEINTRESOURCE(IDB_BITMAP2));
 ……
 ZeroMemory(buf1, BACKWIDTH*BACKHEIGHT*sizeof(short));
 ZeroMemory(buf2, BACKWIDTH*BACKHEIGHT*sizeof(short));
 ……
 return TRUE;
}

  另外,必须在应用程序活跃时不断的进行更新,方可完成对整个过程的模拟,在更新帧的函数中负责完成对数据的实时处理及对页面的渲染,最重要的环节--将离屏页面2装载到主页面的工作也将在这里完成:

……
DropStone((int)(BACKWIDTH*((short)rand()/32767.0)),
(int)(BACKHEIGHT*((short)rand()/32767.0)),
2,64);//激励点为随机产生,模拟雨点落在水面的情形
Spread();//计算振幅数据缓冲区
Render();//页面渲染
//在window内显示页面2
lpDDSPrimary->Blt(&Window, lpDDSPic2, NULL, DDBLT_WAIT, NULL);
……

  在前面的处理光的折射的Rander()函数中也应增添对页面的渲染部分的编码,可以用一个页面来装载原始的图象,用另外一个页面来进行渲染。先用Lock函数锁定两个页面,取得指向页面内存区的指针,然后根据偏移量将原始图象上的每一个象素复制到渲染页面上:

……
//锁定两个离屏页面
DDSURFACEDESC ddsd1, ddsd2;
ddsd1.dwSize = sizeof (DDSURFACEDESC);
ddsd2.dwSize = sizeof(DDSURFACEDESC);
lpDDSPic1->Lock(NULL, &ddsd1, DDLOCK_WAIT, NULL);
lpDDSPic2->Lock(NULL, &ddsd2, DDLOCK_WAIT, NULL);
//取得页面象素位深度,和页面内存指针
int depth=ddsd1.ddpfPixelFormat.dwRGBBitCount/8;
BYTE *Bitmap1 = (BYTE*)ddsd1.lpSurface;
BYTE *Bitmap2 = (BYTE*)ddsd2.lpSurface;
……
//中间为对光的折射模拟过程的代码
……
//解锁页面
lpDDSPic1->Unlock(&ddsd1);
lpDDSPic2->Unlock(&ddsd2);

  最后,为了养成良好的编程习惯,应在程序退出之前释放掉所使用过的资源,在这里主要为对各个页面的释放以及对DirectDraw对象lpDD的释放:

……
lpDDSPrimary->Release();
lpDDSPic1->Release();
lpDDSPic2->Release();
lpClipper->Release();
lpDD->Release();
……

  经过上述几步,已基本完成了对水波的模拟工作。通过对DirectDraw技术的应用,在取得了对图形的硬件加速支持后可以在计算机上很流畅地完成对水波自产生、扩散到消失的全部过程的仿真模拟。

  小结

  通过本文所述的对自然事物的计算机模拟的实现过程,可以对仿真模拟类程序的一般实现过程有基本的认识,在理解本程序的设计思路与方法的前提下也可以用类似的方法设计出对其他事物的模拟算法。本程序结合具体程序设计要求合理和有效的利用DirectDraw的图形硬件加速等特性很好的实现了对水波模拟的过程显示,对于其他仿真程序的设计也可以根据实际灵活的选用诸如OpenGL、Direct3D等不同的软件接口。本文所述程序在Windows 2000下,在DirectX 9.0的支持下,由Microsoft Visual C++ 6.0编译调试通过。

查看本文来源

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章