引言 对于火源的温度高低可用其所在点的亮度来描述;对于火焰扩散的模拟,为尽量减少运算量,在此简单地用某火源点(x,y)及其前后左右邻近四点的均值来近似,即Pixel(x,y)=(Pixel(x,y)+Pixel(x,y-1)+Pixel(x,y+1)+Pixel(x-1,y)+Pixel(x+1,y))/5,虽然该近似算法没有采取正余弦的方法精确,但运算速度极快,而且在后续的实验效果上同采用正余弦的方法几乎没有任何差别;由于在仿真过程中对火焰的温度是通过改变其亮度值来实现的,因此对于扩散过程的冷却可对像素点降低一个固定的亮度值来实现。衰减值的大小需要视所希望火焰冷却速度的快慢而定;对流对火焰产生的直接影响就是使火焰始终保持向上燃烧,因此可通过将当前火焰上滚一至两个像素来加以实现。根据前面描述的仿真运算法则,可将火焰的扩散和对流融合在一起实现,这将在一定程度上减少运算量,使产生的火焰在视觉上更加真实。实现上述近似模型的伪代码可大致设计如下:
|
火焰非均匀冷却的改进模型
由于火焰在进行冷却衰减的同时也在进行着火焰的扩散与对流因此必须使这几种效果保持同步,这需要以同对流速度相同的速度向上滚动冷却位图来实现。为减少不必要的操作,滚动是在内存中通过改变冷却位图的垂直偏移量来加以实现: #p#分页标题#e#
经过以上几步处理虽有一定程度的改善,但仍存在一些缺陷,比如生存期、火焰上升速度恒定、在整个空间燃烧等。为使仿真效果更加逼真,可通过设置种子点来对上述缺陷加以改进。同样出于处理速度的考虑,最好将种子点也以位图的形式预先设定,在仿真时直接在内存中通过移动指针来完成对种子点的访问,其主要代码大致如下:
|
//创建DirectDraw对象(为突出程序流程,以下均对错误检测进行了省略) DirectDrawCreate( NULL, &lpDD, NULL ); //取得全屏独占模式 lpDD->SetCooperativeLevel(hwnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN ); //设置显示器显示模式 lpDD->SetDisplayMode( 640,480, 16 ); //填充主页面信息 ddsd.dwSize = sizeof( ddsd ); ddsd.dwFlags = DDSD_CAPS|DDSD_BACKBUFFERCOUNT; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |DDSCAPS_FLIP | DDSCAPS_COMPLEX; ddsd.dwBackBufferCount = 1; //一个后台页面 //创建主页面 lpDD->CreateSurface( &ddsd, &lpDDSPrimary, NULL ); ddscaps.dwCaps = DDSCAPS_BACKBUFFER; lpDDSPrimary->GetAttachedSurface(&ddscaps,&lpDDSBack); DDPIXELFORMAT pixelFormat; pixelFormat.dwSize = sizeof(DDPIXELFORMAT); lpDDSPrimary->GetPixelFormat(&pixelFormat); …… |
lpDDSBack->Blt(NULL,NULL,NULL,DDBLT_COLORFILL|DDBLT_WAIT, &ddbltfx); ddrval = lpDDSBack->Lock(NULL, &ddsd, 0, NULL) //锁定后台页面 while (ddrval== DDERR_WASSTILLDRAWING); if( ddrval == DD_OK ){ fire.render((WORD*)ddsd.lpSurface); //完成对一帧火焰的渲染 lpDDSBack->Unlock(NULL); //解锁后台页面 } while( 1 ) { ddrval = lpDDSPrimary->Flip( NULL, 0 ); //换页 if( ddrval == DD_OK ) break; if( ddrval == DDERR_SURFACELOST ){ ddrval = lpDDSPrimary->Restore(); //恢复主页面 if( ddrval != DD_OK ) break; } if( ddrval != DDERR_WASSTILLDRAWING ) break; } |
评论 {{userinfo.comments}}
{{child.content}}
{{question.question}}
提交