水の表現の挑戦 波の表現について2
後ろからの図
youtu.be
横からの図
youtu.be
波の表現、といいますか波の高さの計算について考察・改良しました。
最初はGerstner waveについて調べていたのですが、上記例はそれを参考にしつつ計算式自体は少し変形させたものを使用しています。
今までの式
波の高さの計算は色々なブログや記事を見ているとheight mapとよんでいるようです。今まで使っていたheight mapはの点に対して定まるをsinやcosなどで計算していましたが、Gerstner波の計算はこの手法とは異なります。
Gerstner Wave
オリジナルの式はこちらの4.1章に書かれてあります。
https://www.researchgate.net/publication/264839743_Simulating_Ocean_Water
ここでは定点で、は波の方向と速さを表すwave vectorとよばれる量、は波数、は周波数、は時間です。プログラムとして実装するときにはを波の起点として扱うので、つまりこの式は時間についてからwave vectorだけ進んだ点についての高さを表している式となります。
この式の表し方がプログラミングと相性が悪く、なぜならば今までは各点について一意の式で高さが表されていたのが、この式だとある点から時間とwave vectorについて進んだ点についてが定まる微分方程式の解のような計算方法のため、水の表面を有限個の点で区切っているCGでは波の起点から無限に広がっていく波を表現できません。つまりポリゴンの座標を固定した空間では時間とともに増え続けるを計算しきれません。
式が定まっているので未来を先に計算する
微分方程式的な計算方法になるとはいえ、計算式は定まっているため、以下のような計算方法で上の問題を解決しました。
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()以降で計算しているように波が今計算している点に到達すればのの計算をします。
Gerstner Waveは指向性を持った波を計算していますが、上記関数の波はoriginの位置から全方向に伝わる円形波のようなものを想定して高さを計算しています。if文を工夫することでGerstner Waveのような伝わり方をする波にも対応できると考えてますが、また機会があればそのうちやってみようと思います。
ここではwave vectorのような伝わり方をする波にも、すべての点で伝わるときを計算し、もし伝わっていればを計算するというようにすれば対応できますよ、という発見でした。