Aqoole_Hateenaの技術日記

vulkan+raytraceで色々描いてます

水の表現の挑戦 波の表現について2

youtu.be


後ろからの図
youtu.be


横からの図
youtu.be


波の表現、といいますか波の高さの計算について考察・改良しました。
最初はGerstner waveについて調べていたのですが、上記例はそれを参考にしつつ計算式自体は少し変形させたものを使用しています。

今までの式

波の高さの計算は色々なブログや記事を見ているとheight mapとよんでいるようです。今まで使っていたheight mapは(x, z)の点に対して定まるyをsinやcosなどで計算していましたが、Gerstner波の計算はこの手法とは異なります。

Gerstner Wave

オリジナルの式はこちらの4.1章に書かれてあります。
https://www.researchgate.net/publication/264839743_Simulating_Ocean_Water



\boldsymbol{x} = \boldsymbol{x_0} - (\boldsymbol{k} / k)Asin(\boldsymbol{k} \cdot \boldsymbol{x_0} - \omega t )



y = Acos(\boldsymbol{k} \cdot \boldsymbol{x_0} - \omega t )
ここで\boldsymbol{x_0}は定点で\boldsymbol{x_0} = (x_0, z_0)\boldsymbol{k}は波の方向と速さを表すwave vectorとよばれる量、kは波数、\omegaは周波数、tは時間です。プログラムとして実装するときには\boldsymbol{x_0}を波の起点として扱うので、つまりこの式は時間について\boldsymbol{x_0}からwave vectorだけ進んだ点についての高さyを表している式となります。
この式の表し方がプログラミングと相性が悪く、なぜならば今までは各点(x, z)について一意の式で高さyが表されていたのが、この式だとある点\boldsymbol{x_0}から時間とwave vectorについて進んだ点\boldsymbol{x}についてyが定まる微分方程式の解のような計算方法のため、水の表面を有限個の点で区切っているCGでは波の起点から無限に広がっていく波を表現できません。つまりポリゴンの(x,z)座標を固定した空間では時間とともに増え続ける\boldsymbol{x}を計算しきれません。

式が定まっているので未来を先に計算する

微分方程式的な計算方法になるとはいえ、計算式は定まっているため、以下のような計算方法で上の問題を解決しました。

void OneWave(glm::vec3& pos, glm::vec3 origin, float speed, float freq, float time)
{
    glm::vec3 v = pos - origin;
    float d = glm::length(v);
    float d2 = glm::dot(v, v);
    glm::vec3 waveVector = glm::normalize(v);
    float f = d2 * freq - speed * time;

    if(time * speed > d )
    {
        pos.y += (0.5f * cos(f)) / (1 + d2);
    }
}

上記関数をすべての点について適用します。if()以降で計算しているように波が今計算している点に到達すればのyの計算をします。
Gerstner Waveは指向性を持った波を計算していますが、上記関数の波はoriginの位置から全方向に伝わる円形波のようなものを想定して高さを計算しています。if文を工夫することでGerstner Waveのような伝わり方をする波にも対応できると考えてますが、また機会があればそのうちやってみようと思います。
ここではwave vectorのような伝わり方をする波にも、すべての点で伝わるときを計算し、もし伝わっていればyを計算するというようにすれば対応できますよ、という発見でした。