7

Unity で浅瀬の方程式を実装しようとしてきましたが、奇妙なバグが発生しました。私は私の水にこれらの奇妙な振動波紋を取得します. スクリーンショットを作成しました:

ここに画像の説明を入力 ここに画像の説明を入力

そして、あなたがここで見つけることができるビデオ: https://www.youtube.com/watch?v=crXLrvETdjA

私のコードは、Xing MeiによるGPU での Fast Hydraulic Erosion Simulation and Visualizationという論文に基づいています。ソルバー コード全体は、http: //pastebin.com/JktpizHW (または以下を参照)で見つけることができます。論文の数式を使用するたびに、その番号をコメントとして追加しました。

0.02 を使用したビデオでは、さまざまなタイムステップを試しましたが、それを下げると振動が遅くなりました。より大きなグリッドも試しました (ビデオでは 100 を使用していますが、200 を使用しましたが、波紋が小さくなりました)。すべての式を数回確認しましたが、エラーは見つかりませんでした。

何がうまくいかないのか理解できる人はいますか?

追加情報:

ペーストビンからわかるように、C# でプログラムしました。視覚化のエンジンとして Unity を使用し、水を視覚化するためにグリッド メッシュを使用しているだけです。メッシュの頂点 y コンポーネントを変更して、計算した高さに一致させます。

DoUpdate メソッドはfloat[][] lowerLayersHeightパラメータを取得します。これは基本的に、水中の地形の高さです。ビデオでは、それだけ0です。

public override void DoUpdate(float dt, float dx, float[][] lowerLayersHeight) {
        int x, y;
        float totalHeight, dhL, dhR, dhT, dhB;
        float dt_A_g_l = dt * _A * g / dx; //all constants for equation 2
        float K; // scaling factor for the outflow flux
        float dV;

        for (x=1 ; x <= N ; x++ ) {
                for (y=1 ; y <= N ; y++ ) {
                        //
                        // 3.2.1 Outflow Flux Computation
                        // --------------------------------------------------------------
                        totalHeight = lowerLayersHeight[x][y] + _height[x][y];
                        dhL = totalHeight - lowerLayersHeight[x-1][y] - _height[x-1][y]; //(3)
                        dhR = totalHeight - lowerLayersHeight[x+1][y] - _height[x+1][y];
                        dhT = totalHeight - lowerLayersHeight[x][y+1] - _height[x][y+1];
                        dhB = totalHeight - lowerLayersHeight[x][y-1] - _height[x][y-1];

                        _tempFlux[x][y].left =   Mathf.Max(0.0f, _flux[x][y].left        + dt_A_g_l * dhL ); //(2)
                        _tempFlux[x][y].right =  Mathf.Max(0.0f, _flux[x][y].right       + dt_A_g_l * dhR );
                        _tempFlux[x][y].top =    Mathf.Max(0.0f, _flux[x][y].top         + dt_A_g_l * dhT );
                        _tempFlux[x][y].bottom = Mathf.Max(0.0f, _flux[x][y].bottom      + dt_A_g_l * dhB );

                        float totalFlux = _tempFlux[x][y].left + _tempFlux[x][y].right + _tempFlux[x][y].top + _tempFlux[x][y].bottom;
                        if (totalFlux > 0) {
                                K = Mathf.Min(1.0f, _height[x][y] * dx * dx / totalFlux / dt);  //(4)

                                _tempFlux[x][y].left =   K * _tempFlux[x][y].left;  //(5)
                                _tempFlux[x][y].right =  K * _tempFlux[x][y].right;
                                _tempFlux[x][y].top =    K * _tempFlux[x][y].top;
                                _tempFlux[x][y].bottom = K * _tempFlux[x][y].bottom;
                        }
                        //swap temp and the real one after the for-loops

                        //
                        // 3.2.2 Water Surface
                        // ----------------------------------------------------------------------------------------
                        dV = dt * (
                                //sum in
                                _tempFlux[x-1][y].right + _tempFlux[x][y-1].top + _tempFlux[x+1][y].left + _tempFlux[x][y+1].bottom
                                //minus sum out
                                - _tempFlux[x][y].right - _tempFlux[x][y].top - _tempFlux[x][y].left - _tempFlux[x][y].bottom
                                ); //(6)
                        _tempHeight[x][y] = _height[x][y] + dV / (dx*dx); //(7)
                        //swap temp and the real one after the for-loops
                }
        }
        Helpers.Swap(ref _tempFlux, ref _flux);
        Helpers.Swap(ref _tempHeight, ref _height);
}
4

1 に答える 1

6

自分で直しました!とはいえ、友人のところへ車で向かっている間。問題は非常に単純です。バグのあるコードで行っていることは、各セル (またはグリッド ポイント) に対してフラックスを計算し、次に高さを計算してから、次のセルに移動することです。私がすべきことは、最初にすべてのセルのフラックスを計算し、次にすべてのセルに対して 2 回目の繰り返しを行い、それらの高さを計算することです。したがって、コードは次のようになります。

for (x=1 ; x <= N ; x++ ) {
    for (y=1 ; y <= N ; y++ ) {
        //
        // 3.2.1 Outflow Flux Computation
        // --------------------------------------------------------------
        ***
    }
}

for (x=1 ; x <= N ; x++ ) {
    for (y=1 ; y <= N ; y++ ) {
        //
        // 3.2.2 Water Surface
        // ---------------------------------------------------------------------------
        ***
    }
}
Helpers.Swap(ref _tempFlux, ref _flux);
Helpers.Swap(ref _tempHeight, ref _height);

(もちろん***上の質問から対応コードになります。)

これで、作業水のシミュレーションができました。

于 2014-07-02T20:09:44.050 に答える