目標点についてカメラを周回させるにはどうすればよいですか?


18

カメラが宇宙を自由に動き回るシーンを描いています。カメラクラスは、(またはビューのトラック続けるを見てポイント、カメラの位置、およびアップベクトル)。これらのベクトル/ポイントは、gluLookAtに渡されます。

パンとズームの実装はほとんど簡単です。しかし、私はポイントの見方をめぐるローテーションをより多くの問題であると感じています。2つの角度をとる関数Camera.rotateを作成します。1つは上/下に回転し、もう1つ視点を中心とした仮想球に沿って左右に回転ます。

これを行う簡単な方法はありますか?

私は(簡単に)四元数について読みましたが、自分のシーンの構成が比較的単純であるため、簡単な解決策があるかどうかを確認したかったのです。


ツールボックスに、軸と角度を指定して、原点を中心にポイントを回転させるものがありますか?
サムホセバー

クォータニオンについての私のゆるい理解以外に何もありません。これを見れば見るほど、四元数が答えになると思います。ただし、Quaternionの式で使用する軸の x、y、およびzの値を計算する方法はわかりません。
ルーク

四元数が行く方法ではないことを私はあなたに伝えません。彼らはあなたの問題に対する非常に良い解決策です。ただし、クォータニオンクラスとGLおよびGLUと対話する方法が必要になります。最初に変換行列に精通するようにしてください。他の人は同意しないかもしれません。
サムホセバー

回転の順番を検討してください。ワールド空間への移動またはカメラ空間への移動に回転を適用する方法は異なります
チャーリー

回答:


25

あなたが求めているのは、アークボール回転です。四元数は、それらがどのように機能するかを理解している場合にのみ簡単なソリューションです。ただし、クォータニオンがなくても同じことができます。

前提条件

一般的なオブジェクトの回転方法を知っていますか?原点にオブジェクトがあるとしましょう。回転方法を知っていますか(ヒント:回転行列を掛けます)?はいの場合、オブジェクトを最初に翻訳してから回転するとどうなるか知っていると思いますか?

角度軸から回転行列を計算する方法を知っている必要があります(パイのように簡単、オンラインで無数の方程式を見てください。それらの多くがコードも提供します)

解決

  • カメラの取得アップ右のベクトルを。それらは正規化する必要があることに注意してください。
  • 焦点からカメラまでのベクトルを取得します(camPosition-Focus)。これは、回転させるベクトルです。これをcamFocusVectorと呼びましょう。
  • カメラに対してヨー/ピッチでどれだけ回転させるかを決定します
  • 2つの回転行列を作成します。1番目の回転行列は、カメラのアップを、決定した軸とヨー角として使用します。2番目の回転マトリックスは、カメラの右側を、決定した軸とピッチ角として使用します。
  • 次に、新しい回転行列でcamFocusVectorを回転します。これは、原点に対するカメラの新しい位置です。もちろん、フォーカスポイントに相対的なものにしたい...
  • フォーカスポイントの位置をcamFocusVectorに追加します。これがカメラの新しい位置になりました。それに応じてカメラを翻訳します。
  • 最後に、lookAt()関数を呼び出して、カメラにフォーカスポイントに焦点を合わせるように依頼します

注意事項

カメラが機能しなくなる特定のケースまたは特異点に注意する必要があります。たとえば、まっすぐ見下ろす。それらに対処する方法を考えてみましょう。

EDIT1:カメラの正規直交ベクトルを再計算する方法

カメラの方向はすでにわかっています((cameraPos-focusPoint).normalize())。ここで、カメラのアップが+ Yであると仮定します(または、ワールドの現在のアップ軸が...それはあなた次第です)。正しい方向に進むには、向かって方向を横切ります。できた?いや!アップベクトルは、他の2つと直交しなくなりました。その、クロス修正する権利を持つ方向を、あなたはあなたの新しい取得アップ

Gram-Schmidtは、ベクトルの正規化に実際に使用する必要があることに注意してください。

再び、(いくつかの場合には機能しないであろう。このような警告のメモを取る方向に平行なアップなど)。


を使用して右ベクトルを取得できることに注意してくださいnormalize(up ^ camFocusVector)(左利きの場合はその逆)。
サムホセバー

これまでのところ見栄えがよく、左/右回転で美しく機能しました(上向きのベクトルがあるので簡単です)。コメント@SamHocevarの「^」はどういう意味ですか?それは外積ですか?また、変換を行った後にアップベクトルを再計算するにはどうすればよいですか?
ルーク

@ルーク:EDIT1をチェック
サマールサ

1
@Samaursaどうもありがとう。あなたのソリューションは完璧に機能し、その過程で多くのことを学びました!
ルーク

2
これは素晴らしい回答です。ご説明ありがとうございます。私の場合、カメラをXY平面内のターゲットポイントの周りでのみ回転させたいので、すべての計算を行った後、常にcameraRight.zを0に設定してからcameraUpベクトルを計算しました。これにより、望ましい効果が得られました。共有のことを考えた
-codemonkey

1

必要なのは典型的なArcBallカメラです。これは基本的にターゲットの位置を保持し、そのターゲットの周りを「球形」にカメラを動かすことができるカメラです。

XNAにありますが、IIRCは以前にこの実装を使用したことがあり、非常にうまく機能しました。

http://roy-t.nl/index.php/2010/02/21/xna-simple-arcballcamera/


その実装は唯一の小さな値のためのアークボールを近似する権利ベクトルに沿って直接移動するように見える。彼はまた、私がカメラを動かしたい場所として、LookAtポイントを動かしています(近くですが、微妙に異なります)。私はサマウルサがこれを達成する最も簡単で完全な方法を提供したと信じています。
ルーク

ご意見ありがとうございます。私はこの実装を「ブラックボックス」として少し使用したことを認めなければなりませんが、問題はありませんでした。明確にするために、おそらくMoveCameraRight / MoveCameraForwardメソッドについて話していましたか?これらのメソッドは、カメラをパンするために追加されましたが、Arcballインターフェイスの一部ではありません。ターゲットの周りでカメラを回転させる場合は、ヨーまたはピッチのプロパティを変更するだけです。
デヴィッドゴーベイア

申し訳ありませんが、それらはパン方法です。ヨーとピッチが変更されたとき、彼がどのようにマトリックスにダーティフラグを設定したかに気がつきませんでした。
ルーク

0

これは、ポイントを中心に回転するための私のコードです。

float distance;      // Straight line distance between the camera and look at point

// Calculate the camera position using the distance and angles
float camX = distance * -sinf(camAngleX*(M_PI/180)) * cosf((camAngleY)*(M_PI/180));
float camY = distance * -sinf((camAngleY)*(M_PI/180));
float camZ = -distance * cosf((camAngleX)*(M_PI/180)) * cosf((camAngleY)*(M_PI/180));

// Set the camera position and lookat point
gluLookAt(camX,camY,camZ,   // Camera position
          0.0, 0.0, 0.0,    // Look at point
          0.0, 1.0, 0.0);   // Up vector

1
それは基本的に私が最初にやった方法です。この方法で行うには多くの問題があります(少なくとも私にとって)。基本的に、この実装は2つの固定軸についてのみ回転します。ほぼ北極まで回転するとします。次に右に回転します。カメラの正しいベクトルを地球の周りをずっと辿るのではなく、自分が小さな円を描いて回転しているのがわかるでしょう。
ルーク

あなたがそれについて言及した今、私は問題を見るために2つの異なる方法があると思います。私のアプリケーションでは、ArcBallカメラを使用して海上のターゲットアイランドの周りを回転させましたが、3軸の自由度を使用すると、プレーンが間違っているように見えます(逆さままたは横向きにアイランドを見るなど)。
デヴィッドゴーベイア

ここでカメラアングルを取得するにはどうすればよいですか?
rafvasq

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.