忍者ブログ

Memeplexes

プログラミング、3DCGとその他いろいろについて

バネ付きカメラ その2(ソースコード)

このChase Camera Sampleはこの、乗り物が動くと徐々に動き出してついていくカメラのサンプルなのです。
これを実現するのに、このサンプルではカメラと宇宙船の間にバネをつけています

つまり宇宙船が動き出せば、バネでつながったカメラがそれに引っ張られて少し動きはじめ、その後バネの収縮によってより速いスピードで動くようになります。
止まるときもすぐに止まるのではなく、ばねの伸びる力によって徐々に止まっていきます。宇宙船の向きが変わったときも同じです。
きちんと、画面が徐々に動き出すような仕組みになっています。

ただしこれだけではいけません!
というのも、エネルギー保存の法則により、一度動き出したバネはいつまでも永久に伸び縮みを繰り返すからです。
このままでは、宇宙船が動くと、カメラは宇宙船に近づき、遠ざかり、近づき、遠ざかり、近づき・・・・・・を永遠に繰り返すことになります。
・・・これでは逆に3D酔いになりやすくなりそうです。

この問題を解決するには、現実世界と同じように、空気抵抗などを考えてやればOKです。
※このバネの動きを抑える力のことを、制動(ダンピング)といいます。

空気抵抗がある程度大きければ、バネはもう振動することはありません。
宇宙船に近づいたあとは、もう離れることはないのです。(ただし、空気抵抗が小さすぎると少しだけ振動してしまうので注意です)

空気抵抗は、普通の速さでは、速度のに比例します。(ものすごく速い物体だと速度の2乗に比例するようになりますが、ここでは無視しましょう)
イメージとしては、速度が2倍になれば抵抗も2倍で、速度が3倍になれば抵抗も3倍です。
つまりある程度速度が速くなると、空気抵抗と力がつりあって、動かす力がなくなります。
これが、アリが地球上の空気のあるところならどんな高さから落ちても死なない理由であり、人が雨に当たって死ぬことのない理由であり、カメラのついたバネが振動せずに止まる理由なのです。

以上のことを表したコードは以下のようになっていました:

Vector3 stretch = position - desiredPosition;
Vector3 force = -stiffness * stretch - damping * velocity;


意味としてはこんな感じです:

力 = -バネの強さ × バネの伸び - カメラに対する、空気の粘っこさ × カメラの速度;

ここで作ったforceから加速度を求め、速度に追加して、それを位置に追加すればバネのシミュレートは完成です。

//加速度分を追加
Vector3 acceleration = force / this.mass;
this.velocity += acceleration * elapsed;

//速度分を追加
this.position += velocity * elapsed;


メソッド全体ではこのような感じでした(ChaseCamera.csより。コメントは日本語訳):

        public void Update(GameTime gameTime)
        {
            if (gameTime == null)
                throw new ArgumentNullException("gameTime");

            UpdateWorldPositions();

            float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;

            // バネの力を計算
            Vector3 stretch = position - desiredPosition;
            Vector3 force = -stiffness * stretch - damping * velocity;

            // 加速度の分を追加
            Vector3 acceleration = force / mass;
            velocity += acceleration * elapsed;

            // 速度の分を追加
            position += velocity * elapsed;

            UpdateMatrices();
        }




拍手[2回]

PR