AutoCAD 3DMAX C语言 Pro/E UG JAVA编程 PHP编程 Maya动画 Matlab应用 Android
Photoshop Word Excel flash VB编程 VC编程 Coreldraw SolidWorks A Designer Unity3D
 首页 > VC编程

借助DirectDraw技术实现对水波的计算机模拟

51自学网 2015-08-30 http://www.wanshiok.com

 

水波模拟
 这种用数据缓冲区对图像进行处理的方法的最大的好处就是:程序运算和显示的速度与水波的复杂程度无关,用类似的方法完全可以对其他一些物理和自然现象,如烟雾、云彩、阳光等,进行逼真的模拟。

加速显示
 由于动画对处理速度要求比较严格,所以要竭尽所能来提高数据的处理速度,不仅在算法上如此,在显示上更是如此。普通的GDI函数的处理速度在此类计算中是无法容忍的,为此,笔者采用了DirectX中的DirectDraw技术来对图形进行加速处理。DirectDraw是DirectX SDK中的一员,也是其中最主要的一个部件。它允许程序员直接操作显存、硬件位图映射以及硬件覆盖和换页技术。它在提供直接访问显示设备的同时,与GDI相兼容,提供了一种与设备无关的途径,以访问特定的显示设备的某些高级特性。


本文例子采用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的图形硬件加速等特性很好地实现了对水波模拟的过程显示,对于其他仿真程序的设计也可以根据实际灵活地选用诸如OpenGL、Direct3D等不同的软件接口。

 
 
说明
:本教程来源互联网或网友上传或出版商,仅为学习研究或媒体推广,wanshiok.com不保证资料的完整性。

上一篇:VC 和 MFC 的一些常见问题  下一篇:VC编程制作系统托盘程序