正式公開版 Ver 1.0(99/12/4公開)
サンプル追加 99/12/8
水表面を粒子モデルで解くサンプルプログラムです。
水粒子サンプル ver1.0をダウンロードする(Windows95/98/NT4.0用、LZH圧縮、100KB)
プログラムソースも公開してます(こちらがメインです)。Visual C++ & MFC用です。
水粒子サンプルVer1.0プログラムソース(Visual C++6.0用、LZH圧縮、28KB)
利用法ですが、マウス左ボタンで初期化。あとは静かにマウスを動かしてください。
なお、内部的には3次元で処理してますが、計算負荷の問題で、2次元表示専用です。
12/8日 関連プログラム追加
かみやんさんの方からプログラムを頂きましたので公開します。内容ですが、Ver1.0でやっていることを別の手法にしたものです。
水粒子サンプル かみやんさんバージョン(EXE+ソース)をダウンロードする(Windows95/98/NT4.0用、LZH圧縮、147KB)
えーと、私が作ったものはAnimeBodyの手法なんで、位置を直接変えて、速度成分は最終的に位置がどの程度変わったか?で求めているんですが、こちらですと、ポテンシャル場のようなものを考えて、近づけば近づくほど離れようとする成分を速度に加えという手法です。方法としては、こちらの方が至極まっとうな方法です。ただし、この手法では球のめり込みが防げません。逆に私が作ったものですと、めり込みはほとんどしないのですが、壁の跳ね返りが変などの現象が起こります。この辺は手法の問題ですので、動きとプログラムを見比べていただくと勉強になるのではないかと思います。
他、ダブルバッファリングでティアリングしないようになっていますし、
> 水深が深いところほど水の圧力が高いというような感じになっているので箱とかを置くと浮力が勝手につくかも(つかないかも)。
ということです。他のもの入れてどういう浮力が発生するかを求めるのは、私の手法ではちょいきついですね(^^;
私の方のですと、どのぐらい力が働くかわからん状態でも動きを計算できるというメリットがありますが、逆にいえば、どのぐらいの力が働くのかわからんということでもあります(笑)。まともなシミュレータには私の手法は使えませんな。ただ、今回のサンプルでわかるように、硬い剛体をらしく処理するのには向いた手法です。
ということで、ありがとうございました>かみやんさん
みなさんも参考にしてくださいね。
12/4日 Ver1.0
ちょっとだけ余裕ができたので趣味プロ。テーマですが、BioのBBSの方で水表面に関する話が出たので、これを試しにやってみました。
すでに、バネメッシュとか差分法などの格子系での(非常に怪しい)プログラムも出してるわけですが、別の考えとして、完全独立の粒子群で液体を表現することも考えられます。とどのところが、パチンコ玉が詰まった箱を考えれば、水のはねるのなどが簡単に表現できるのではないのか?ということです(なお、この辺の文献なんて見たことありませんので、全て想像で作ってます(笑)細かいこと気にしないように)。ということで、前に作ったビリヤードもどきを元にしましたので、プログラムの名前も単純にBallsです。
さてさて、具体的な処理法ですが、実は前作ったBallと同じ処理で個数を増やしてもあまり液体っぽくなりません。まじめにいろいろ処理すればよいのでしょうが、そんなことしてたら一日で組めるようなプログラムにならない。ということで、いつものように直感に基き、てきとーな処理でごまかしてます。
具体的には、毎度のAnimeBodyの手法を使っているというだけです。こういうのも実は簡単に処理できるんですね(^^;
もちろん、厳密には変な計算となっていますが、らしければよいっしょということで。
と、このような簡略化のため、動きの計算部はこれだけです↓
{
int i, j;
for (i = 0; i < BMAX; i++) {
// 移動処理
bp[i] += bv[i];
// 重力処理
bp[i].y += 0.1;
}
// ボール間制約処理
for (int k = 0; k < 3; k++) {
// 本当は何度も繰り返すべき
for (j = 0; j < BMAX; j++) {
for (i = 0; i < BMAX; i++) {
if (i < j) {
// 位置の差を求める
CVector3 vdp = bp[i] - bp[j];
// 球の中心間距離を求める
double dp = vdp.abs();
// 球の中心間距離が2R以下なら接触
if (dp < R * 2) {
// 相対位置の単位ベクトルを求める
CVector3 ndp = vdp.norm();
// 球間距離を2Rに修正
double dr = (R * 2 - dp) * 0.5;
bp[i] += ndp * dr;
bp[j] -= ndp * dr;
}
}
}
}
// 壁制約処理
for (i = 0; i < BMAX; i++) {
if (bp[i].x < R + left)
bp[i].x = R + left;
if (bp[i].x > BWIDTH - R + left)
bp[i].x = BWIDTH - R + left;
if (bp[i].y < R + top)
bp[i].y = R + top;
if (bp[i].y > BHEIGHT - R + top)
bp[i].y = BHEIGHT - R + top;
}
}
for (i = 0; i < BMAX; i++) {
// 最終的な速度を求める
bv[i] = bp[i] - obp[i];
// 位置保存
obp[i] = bp[i];
}
}