水波模拟 这种用数据缓冲区对图像进行处理的方法的最大的好处就是:程序运算和显示的速度与水波的复杂程度无关,用类似的方法完全可以对其他一些物理和自然现象,如烟雾、云彩、阳光等,进行逼真的模拟。
加速显示 由于动画对处理速度要求比较严格,所以要竭尽所能来提高数据的处理速度,不仅在算法上如此,在显示上更是如此。普通的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不保证资料的完整性。
2/2 首页 上一页 1 2 |