火焰本質為高溫氣體對流擴散系統。為達即時效能,採簡化近似模型:
(P(x,y)+P(x,y-1)+P(x,y+1)+P(x-1,y)+P(x+1,y))/5。c,或使用預計算冷卻貼圖 CoolingMap 實現非均勻冷卻。
BYTE buffer1[W*H], buffer2[W*H];
while (true) {
for y=1 to H-2:
for x=1 to W-2:
n1=buffer1[x+1,y]; n2=buffer1[x-1,y];
n3=buffer1[x,y+1]; n4=buffer1[x,y-1];
p = (n1+n2+n3+n4+buffer1[x,y]) / 5; // 四鄰域平均
p = p - c; // 固定冷卻
if (p < 0) p = 0;
buffer2[x,y-1] = p; // 向上捲動一像素(對流)
Copy buffer2 to screen;
Copy buffer2 to buffer1;
}
CoolingMap。Pixel = Pixel - CoolingMap[x,y]。memcpy(lightBuf1, lightBuf1+W*3, W*(H-3)) 向上捲動冷卻貼圖。SeedMap 標記潛在火源位置。rand() < RAND_MAX/5 在種子點生成高亮火源(255)。
// 1. 建立 DirectDraw 物件
DirectDrawCreate(NULL, &lpDD, NULL);
// 2. 獨占全螢幕模式
lpDD->SetCooperativeLevel(hwnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
// 3. 設定顯示模式 640x480x16bit
lpDD->SetDisplayMode(640, 480, 16);
// 4. 建立主介面(複雜介面,含後台緩衝)
DDSURFACEDESC ddsd = { 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);
// 5. 取得後台緩衝區
DDSCAPS ddscaps = { DDSCAPS_BACKBUFFER };
lpDDSPrimary->GetAttachedSurface(&ddscaps, &lpDDSBack);
// 1. 清除後台緩衝
lpDDSBack->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);
// 2. 鎖定後台緩衝存取記憶體
ddrval = lpDDSBack->Lock(NULL, &ddsd, 0, NULL);
while (ddrval == DDERR_WASSTILLDRAWING);
if (ddrval == DD_OK) {
fire.render((WORD*)ddsd.lpSurface); // 將火焰像素寫入顯存
lpDDSBack->Unlock(NULL);
}
// 3. 換頁顯示
while (1) {
ddrval = lpDDSPrimary->Flip(NULL, 0);
if (ddrval == DD_OK) break;
if (ddrval == DDERR_SURFACELOST) {
lpDDSPrimary->Restore();
if (ddrval != DD_OK) break;
}
if (ddrval != DDERR_WASSTILLDRAWING) break;
}
WORD* 直接操作 16-bit 顯存(565 格式),避免色彩轉換開銷。buffer1/buffer2 完成,僅最終結果寫入顯存。Flip 硬體換頁近乎零成本,實現流暢 60+ FPS。在 Windows 98 + VC++ 6.0 + DirectX 5.0 環境測試,火焰燃燒效果逼真流暢。關鍵洞見:
同架構可延伸至水波、煙霧、爆炸等自然現象模擬,並可移植至 OpenGL/Direct3D 現代圖形 API。