質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
OpenGL

OpenGLは、プラットフォームから独立した、デスクトップやワークステーション、モバイルサービスで使用可能な映像処理用のAPIです。

Q&A

1回答

3379閲覧

gluLookAtで求めたカメラの位置、姿勢から平行移動、回転をするには

退会済みユーザー

退会済みユーザー

総合スコア0

OpenGL

OpenGLは、プラットフォームから独立した、デスクトップやワークステーション、モバイルサービスで使用可能な映像処理用のAPIです。

0グッド

1クリップ

投稿2021/05/28 11:01

gluLookAt(eyeX,eyeY,eyeZ,
centerX,centerY,centerZ,
upX,upY,upZ)
で求めたカメラの位置、姿勢があります
eyeはワールド座標系でのカメラの位置
centerはワールド座標系での目視点
upはワールド座標系でのカメラの上方向

カメラ座標系でx,y,zにカメラを平行移動,
目視点を回転軸としてカメラを回転移動
させたいのですがどうすれば良いでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2021/05/29 03:11

所望の結果となるような新しい{カメラ位置,目視点,上方向}の値を求めてそれを gluLookAt に渡す,というのが,最も明確な手段と思えますが,問題点は何なのでしょうか?
guest

回答1

0

カメラ座標系でx,y,zにカメラを平行移動,

というのは,

eyeX,eyeY,eyeZ
centerX,centerY,centerZ

の値を平行移動した座標に更新して,再度 gluLookAt() でマトリクスを更新する部分の処理をやり直せばよいでしょう.
元々,

gluLookAt(eyeX,eyeY,eyeZ, centerX,centerY,centerZ, upX,upY,upZ)

として引数を与えることができている時点で,その時点におけるカメラ座標系の基底ベクトルは既知(算出方法が既知)なわけですから,カメラ座標系の規定ベクトル方向に平行移動する処理は自明でしょう.

例えば,
カメラ座標系のx方向単位ベクトルが u であるとき,
カメラ位置 E = ( eyeX, eyeY, eyeZ ) を,カメラ座標系のx方向にsだけ移動させたいのであれば,
E を,(E + su) に更新すればよいですね.

カメラの姿勢を変えずに平行移動したいならば,
(centerX,centerY,centerZ) についても同じ更新を施せばよいですね.


目視点まわりの回転については,(centerX,centerY,centerZ)の値は保ち,
所望の回転軸周りの回転によって,基底ベクトルの方向と,座標(eyeX,eyeY,eyeZ)とを更新すれば良いでしょう.



[追記]

カメラを平行移動

というのは,
「カメラ位置はそのままにしておき,全てのモデルを(逆方向に)平行移動」することと同じなので,
そういう方向で物事を考えれば,
現在の ModelView マトリクスに,「逆方向に平行移動させる行列」を左から乗じるという形になります.

単純には,

glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); glTranslated( 逆方向の並進移動量 ); gluLookAt( 既存の内容 );

とか書く感じですね.


まぁ,

  • 「"カメラの位置" という意味として扱っている数値の側を変更する」と考えて gluLookAt() に渡す引数値を変えてやる
  • 「モデル群を逆方向に移動させてやればいいよね」と考えて,glTranslated() とかでやる

のどちらであろうが,結局は単一のModelViewマトリクスをいじくっているだけで,やってることは同じなので,「頭の中で考えている話の捉え方が違う」だけですが.

投稿2021/05/31 02:24

編集2021/06/02 04:27
fana

総合スコア11708

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2021/06/01 12:09

回答ありがとうございます 平行移動は以下の方法でできたのですがなぜこの計算順なのかがわかりません gluLookAtで今のカメラの位置、姿勢を決めた後 float m[16] glGetFloatv(​GL_MODELVIEW_MATRIX, m); //gluLookAtの行列 glLoadIdentity(); glTranslatef(s,0,0); glMultMatrixf(m); プログラム実行してみたらそれっぽい動きはしていましたが 上の行列計算は |I s| * |R E| |0 1| |0 1| = |R E+s| |0 1| となりE+suにはなりません 計算方法が間違っていますか? OpenGLの行列は列か行かが優先だとどこかのサイトで書いてあったのですが それが原因ですか? ――――――――― E + suがカメラ座標系でx方向に移動するのはわかりました ありがとうございました
fana

2021/06/02 01:17

glMultMatrixf(m); は,mを,現在の行列に対して "左から" 乗じるので, 更新後の行列 = m * 現在の行列 という形になります. その処理だと,mとは gluLookAt までを行った時点での行列の内容であり, 「現在の行列」というのが,glTranslatef のみを行った状態の行列になっているので, 結果 = (gluLookAtまでの行列) * (glTranslatefだけの行列) という形です. 処理の意味としては,「並進行列を "右から" 乗じることで行列を更新する」ですね.
fana

2021/06/02 02:09

↑ あっ,ちがう! 完全に向きが逆か.
fana

2021/06/02 02:15 編集

glMultMatrixf(m); は,mを,現在の行列に対して "右から" 乗じるので, 更新後の行列 = 現在の行列 * m で,その処理だと,mとは gluLookAt までを行った時点での行列の内容であり, 「現在の行列」というのが,glTranslatef のみを行った状態の行列になっているので, 結果 = (glTranslatefだけの行列) * (gluLookAtまでの行列) という形になり, 処理の意味としては,「並進行列を "左から" 乗じることで行列を更新する」ですね. glLoadIdentity(); glTranslatef(s,0,0); gluLookAt( ... ); としたのと同等.
fana

2021/06/02 02:48 編集

(実際のGLの行列要素値の確認まではしてませんが) gluLookAt で作られる行列というのを | R t | | 0 1 | と書いた場合の,tの部分というのは -E=(-eyeX, -eyeY, -eyeZ)^T ではない(-E に R が作用した形になっている),ということではないかな,と思います.
txty

2021/06/02 10:35

横やり失礼します A=(B*C)*D A=B*(C*D)はおk! A=C*B*Dは駄目くらいはわかるぐらいなんだけど 私は右から乗ずるが未だにわからない,おそらく頭悪いんだろうけど、移動B、回転C、拡大Dのとき、右から乗算するとAはどうなりますか。A=B*C*Dだからtranslatefとかで、 D C B の順? それともC*D B*(C*D)ってするんですか。検討違いだったらすいません。
fana

2021/06/02 11:39

えっとー, 何かベクトル(座標) v があってー, (1) まずは v を定数倍(拡大)して (2) その(1)の結果座標をこんどは回転して (3) その(2)の結果をさらに平行移動する ということをする,という話であれば, ・Dが定数倍する変換行列 ・Cが回転する変換行列 ・Bが平行移動する変換行列 であるとき, (1) とは,D*v である. (2) とは,(1)の結果である D*v にCを乗じるのだから, C*(D*v) である. (3) とは,(2)の結果である C*(D*v) にBを乗じるのだから, B*( C*(D*V) ) である. (1)~(3) の変換をまとめて書けば, 変換結果座標 = B*( C*(D*v) ) = (B*C*D)*v であるから, (1)~(3)の変換を行うための行列Aを用意するのであれば A = B*C*D という行列を作ればよい.
fana

2021/06/02 11:48 編集

で,OpenGL の glTranslated だの glScaled だのいうやつらというのは, 現在の行列に,変換行列を右側から乗じて更新する という形になってる. だから, glLoadIdentity(); //現在の行列の内容を単位行列にする glScaled(); glRotated(); glTranslated(); とかいう順のコードを書いたら, glScaled(); のところで, 更新後の行列 = 現在の行列 * D //現在の行列の右側にDが乗じられる形 という形で更新される. 今,glLoadIdentity() によって,「現在の行列」は単位ベクトルだから,この結果は D である. 次の glRotated(); でも同様に C が右側に乗じられるから, 更新後の行列 = 現在の行列(D) * C となる. 同様に,次の glTranslated(); によって, 更新後の行列 = 現在の行列(D*C) * B となり, 変換行列の中身は (D*C*B) になる. なので,このコードだと,以降に glVertex3D とかで座標vを指定した際に, 変換結果座標 = (D*C*B)*v という形の変換が行われることになる. これだと,行いたい処理(1つ前のコメントの内容)とは異なってしまう.
fana

2021/06/02 11:52

なので, A = B*C*D という話にしたいのであれば,コードは,3つの変換のための記述を逆順にして glLoadIdentity(); //現在の行列の内容を単位行列にする glTranslated(); //コードの順序ではこいつを最初に書く glRotated(); glScaled(); //コードの順序ではこいつを最後に書く という順序にする必要がある.
fana

2021/06/02 11:53

(…っていう話について尋ねられているのか? これは)
fana

2021/06/02 11:58

今回の質問は,「順序的に最後に行われる変換を追加したい」という内容だから, 回答の[追記] は glTranslated( 逆方向の並進移動量 ); //←順序的に最後に行われて欲しい変換 gluLookAt( 既存の内容 ); //←順序的に先に行われて欲しい変換 という順序でコードを書けばいいんじゃない?という形になっている.
txty

2021/06/03 03:18 編集

よく読んでみました。自分のコメント部分は頭で適応できず、参考にできませんでしたがコメントから完全に理解できました。ありがとうございます。あと間違えたのはABnotBAになるが完璧になるわけじゃないってことと最後に積の交換法則使われてる気がして少し不気味です 。dcbをbcdにしたいからね。
fana

2021/06/03 01:05 編集

glTranslated() {//このブロックの中身を並進  glRotated()  {//このブロックの中身を回転   glScaled()   {//このブロックの中身をスケーリング    ...    glVertex3d();    ...   }  } } とか書くと何となくわかりやすいような気がしないでもない.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問