首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

水波模擬算法實現:基於正弦波位移查找表的高效渲染

     編輯:關於C++

物理模型:正弦波位移場

單一波源在二維平面產生的水波位移:


disp = sin(dist) * force + disp_center
// 推廣到任意點(離散化波長 wave_length)
disp = sin(dist % wave_length) * force + disp_center

其中 dist 為點到波源中心的歐氏距離,force 為振幅,disp_center 為中心位移。

優化策略:預計算位移查找表

由於 dist % wave_length 取值有限(0 ~ wave_length-1),可預計算所有可能位移值,渲染時直接查表,避免實時 sin/sqrt 運算。

核心數據結構


int disp[12];                 // 波長 12 的位移查找表
int dist[SCREEN_HEIGHT][SCREEN_WIDTH]; // 每像素到波源的距離模波長

初始化階段


inline void Build_Disp_Matrix() {
    for (int i = 0; i < 12; ++i)
        disp[i] = static_cast<int>(sin((double)i * 30 * DXPI / 360) * PRECISION);
}

void Create_Ripple(int center_x, int center_y, int force, int damp, int wave_length) {
    // 縮放位移表
    for (int i = 0; i < wave_length; ++i)
        disp[i] = force * disp[i] / PRECISION;

    // 計算每像素距離模波長
    for (int i = 0; i < SCREEN_HEIGHT; ++i) {
        for (int j = 0; j < SCREEN_WIDTH; ++j) {
            int dist_x = j - center_x;
            int dist_y = i - center_y;
            dist[i][j] = static_cast<int>(sqrt(dist_x*dist_x + dist_y*dist_y) + 0.5) % wave_length;
        }
    }
}

渲染階段:折射映射采樣

利用鄰域位移差計算折射偏移,從後台緩衝區采樣:


void Render_Ripple(LPDIRECTDRAWSURFACE7 lpdds) {
    DDSURFACEDESC2 ddsd = { sizeof(ddsd) };
    if (disp_index < 0) disp_index = 12;
    --disp_index; // 時間動畫索引

    lpdds->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR, NULL);
    short* lpSrcBuffer = static_cast<short*>(pBmpBack->GetBitmapBuffer());
    int pitch = ddsd.lPitch >> 1;
    short* lpBuffer = static_cast<short*>(ddsd.lpSurface);

    for (int i = 1; i < SCREEN_HEIGHT - 2; ++i) {
        for (int j = 1; j < SCREEN_WIDTH - 2; ++j) {
            // 四鄰域位移差
            int left = (disp_index + dist[i][j-1]) % 12;
            int right = (disp_index + dist[i][j+1]) % 12;
            int top = (disp_index + dist[i-1][j]) % 12;
            int bottom = (disp_index + dist[i+1][j]) % 12;

            int x_off = disp[left] - disp[right];
            int y_off = disp[top] - disp[bottom];

            int index_x = j + x_off;
            int index_y = i + y_off;
            int pos1 = i * pitch + j;
            int pos2 = index_y * 800 + index_x; // 假設後台寬 800

            if (pos2 >= 0 && pos2 < 480000)
                lpBuffer[pos1] = lpSrcBuffer[pos2];
        }
    }
    pBmpBack->ReleaseBuffer();
    lpdds->Unlock(NULL);
}

關鍵點總結

  • 查找表法:將超越函數運算移至初始化,渲染循環僅含整數加減、查表、內存拷貝
  • 折射近似:用水平/垂直鄰域位移差模擬法線方向,避免向量運算
  • 雙緩衝:後台位圖 pBmpBack 保存原始圖像,前台 Surface 渲染扭曲後幀
  • 邊界保護:循環範圍縮減 2 像素,采樣前檢查 pos2 有效性

此算法在 90 年代 PC 上即可實時運行,展示了「預計算 + 查表 + 定點數」在圖形模擬中的經典威力。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved