飛行機を目的地の方向に向けたい

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
珈琲

飛行機を目的地の方向に向けたい

#1

投稿記事 by 珈琲 » 12年前

飛行機を目的地の方向に向けたいです。
具体的には、AIの作成でピッチ、ロール、ヨーの操作を駆使して、方向ベクトルの方角に向きたいです。

実際にコードを組んでみたのですが、思うように動きません。
どこが間違っているのでしょうか?
飛行機がまったく方向転換しなくなる事が多々有り、28行目から上が間違っているのか・・・

コード:


//目的地の設定
VECTOR Destination =VGet(10000,0,0);

//目的地の方向へ向きを変えたい
	//目的地の方向ベクトル
	VECTOR DestinationDirection = VNorm(VSub(Destination , ControlAircraft->GetPosition()));

	//ワールド座標系から飛行機の座標系へ変換する回転行列
	MATRIX PredeterminedAngle = MGetIdent();

		PredeterminedAngle.m[0][0] = ControlAircraft->AxisX.x;
		PredeterminedAngle.m[0][1] = ControlAircraft->AxisX.y;
		PredeterminedAngle.m[0][2] = ControlAircraft->AxisX.z;

		PredeterminedAngle.m[1][0] = ControlAircraft->AxisY.x;
		PredeterminedAngle.m[1][1] = ControlAircraft->AxisY.y;
		PredeterminedAngle.m[1][2] = ControlAircraft->AxisY.z;

		PredeterminedAngle.m[2][0] = ControlAircraft->AxisZ.x;
		PredeterminedAngle.m[2][1] = ControlAircraft->AxisZ.y;
		PredeterminedAngle.m[2][2] = ControlAircraft->AxisZ.z;

	//目的地の方向ベクトルを回転させる。これで飛行機から見た方向ベクトルになるはず。(飛行機の正面に目的地があった場合、0.0 , 0.0 , 1.0
	DestinationDirection = VNorm(VTransform(DestinationDirection,PredeterminedAngle));

	//目的地の方向へ45度圏内に入っていなければ、方向を変える
	if( 0.5 > VDot(DestinationDirection,ControlAircraft->GetDirection())){

		if( 0 < DestinationDirection.x ){//右側
			ControlAircraft->Roll(0.5);
			if( 0 < DestinationDirection.y ){
				ControlAircraft->Pitch(1.0);
			}
		}else{
			ControlAircraft->Roll(-0.5);
			if( 0 < DestinationDirection.y ){
				ControlAircraft->Pitch(1.0);
			}
		}
	}

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: 飛行機を目的地の方向に向けたい

#2

投稿記事 by usao » 12年前

なんか毎回「思うように動かない」みたいな曖昧な質問である印象です.
(本当にやろうとしていること が後出しでは回りくどいだけだと思うのですが.)

●そもそも目的を達成した状態はどういう状態ですか?
(例えば目標が地表面にあったら,そのまま飛んだらそこに激突するコースに乗せればよい?
 そのときの機体ロール姿勢は問わない?)

●で,それに関してどういう制御を行おうとしているのですか?
(例えば,
 (1)とりあえず方角だけを揃えることを優先して,
 (2)その後で仰俯角を揃える
 という2段階の処理であって,(1)とは具体的にはこうで,(2)はこうだ,みたいな話)

●まったく方向転換しなくなる,とのことですが,
 じゃあ方向転換しているうちは,想定通りの方向に方向を変えているのですか?

[hr]
ところで,line28の
> if( 0.5 > VDot(DestinationDirection,ControlAircraft->GetDirection()))
これは何を判定されているのでしょうか?
(直前の注釈行とは全く関係ないようですが)

> ControlAircraft->Roll(0.5);
これは何をやっているのでしょうか?
・現在姿勢から0.5(単位不明ですが)だけロールする?
・姿勢を強引に0.5なる値にする?
・その他?

アバター
h2so5
副管理人
記事: 2212
登録日時: 14年前
住所: 東京
連絡を取る:

Re: 飛行機を目的地の方向に向けたい

#3

投稿記事 by h2so5 » 12年前

そもそもローリングとピッチングだけでは水平方向の方向転換ができないんじゃないでしょうか。

実際の航空機では旋回するときにローリングとピッチングで操作するようですが、揚力をシミュレートしていないと再現できないですよね。
http://www.cfijapan.com/study/html/to19 ... urning.htm

珈琲

Re: 飛行機を目的地の方向に向けたい

#4

投稿記事 by 珈琲 » 12年前

usao さんが書きました:なんか毎回「思うように動かない」みたいな曖昧な質問である印象です.
(本当にやろうとしていること が後出しでは回りくどいだけだと思うのですが.)
問題を単純化したほうが、後々応用が効くかなと思い、
目前の問題だけまず解決しようかなと・・・。
でもそのせいで今、後出しはやめろと非難されてるんですよね、申し訳ありません。

それと、ちょっとソースコードを修正できたので(治ってはいない)
フローに関わる部分のソースコード載せます。

usao さんが書きました: ●そもそも目的を達成した状態はどういう状態ですか?
目的地の座標を、飛行機の正面に捉えることです。
飛行機が目的地に向かって飛ぶというAIを作成したいと思っています。
usao さんが書きました: ●で,それに関してどういう制御を行おうとしているのですか?
(例えば,
 (1)とりあえず方角だけを揃えることを優先して,
 (2)その後で仰俯角を揃える
 という2段階の処理であって,(1)とは具体的にはこうで,(2)はこうだ,みたいな話)
(1)「基準座標系から飛行機が持つ座標系に変換」する行列を使って、飛行機からみた目的地の座標に変換し、正規化して方向ベクトルとします。
  この時作成した行列を使って飛行機自身をトランスフォームして座標を出すと、常に座標 0,0,0 回転ベクトルも0,0,0になります(予想では)。
(2)AIをこれから作ります。提示したコードはプロトタイプでして、とにかく方向ベクトルがきちんとあっているかどうかを念願に置いたものです。(27行目から)
(完成できるかはわかりませんが)
usao さんが書きました: ●まったく方向転換しなくなる,とのことですが,
 じゃあ方向転換しているうちは,想定通りの方向に方向を変えているのですか?
いえ、なっていません。
usao さんが書きました: ところで,line28の
> if( 0.5 > VDot(DestinationDirection,ControlAircraft->GetDirection()))
これは何を判定されているのでしょうか?
(直前の注釈行とは全く関係ないようですが)
えーと、直前の注釈と同じ処理のコードを書いたつもりです。
2つのベクトルの内積のよって算出される値が-1.0~1.0ということなので、
1.0だったら2つのベクトルが全く同じ方向を向いている
-1.0だったら全く逆の方向を向いている
0だったら垂直
0.5だったら斜め前・・・?という感じで・・・
usao さんが書きました: > ControlAircraft->Roll(0.5);
これは何をやっているのでしょうか?
・現在姿勢から0.5(単位不明ですが)だけロールする?
・姿勢を強引に0.5なる値にする?
・その他?
失礼しました、これは、予め飛行機側に設定されている飛行機の旋回角度の単位と旋回係数と一緒に飛行機の影響を角度に与える値です。1.0 ~ -1.0の範囲
例えば
ControlAircraft->Pitch(1.0);
とすると、その飛行機が持てる最大の速度でピッチアップします。マイナス方向も同様にピッチダウンします。
ControlAircraft->Pitch(0.0);
とすると、何も起こりません。

珈琲

Re: 飛行機を目的地の方向に向けたい

#5

投稿記事 by 珈琲 » 12年前

変数
VECTOR Destination //目的地です。
VECTOR DestinationDirection //目的地への方角です。単位ベクトル

AIが機体に下せる命令は数種類で、これ以外で機体を操作することはできません。※本当はこのAIクラスとControllerクラス以外から呼び出すことも禁止にしたかったのですが、そんなことをできるのかなぁ・・・?

コード:

	//ピッチ
	void Pitch(float);
	//ロール
	void Roll(float);
	//ヨー
	void Yaw(float);
	//兵装使用
	void WeaponUse();
	//ロックオン対象切り替え
	void LockOnSwitch(int);
	//兵装切り替え
	void WeaponSwitch(int);
	//加速する
	void Acceleration();
	//減速する
	void Deceleration();
AIの部分です。
飛行機に加速や減速、ピッチアップやピッチダウンなどの命令を出してどうにかして操作します。
とりあえず、といって目的地に向かって飛ぶだけ、プロトタイプのままです。(プロトタイプが正常に動かなくて
No.1のソースコードから、一部分関数に変えました。

コード:

void CNonPlayerCharacter::AI_Idle(){
//目的地の方向へ向きを変えたい
	//目的地の方向

	VECTOR DestinationDirection = GetTargetDirection(Destination);

	if(0.7 > VDot(DestinationDirection,ControlAircraft->GetDirection())){

		if( 0 < DestinationDirection.x ){//右側
			ControlAircraft->Roll(0.5);
			if( 0 < DestinationDirection.y ){
				ControlAircraft->Pitch(1.0);
			}
		}else{
			ControlAircraft->Roll(-0.5);
			if( 0 < DestinationDirection.y ){
				ControlAircraft->Pitch(1.0);
			}
		}
	}
}
//AIを呼び出している部分です。
ControlAircraft->Update()は、このAIが保持している飛行機をアップデートします。ダメージ処理や移動処理など。

コード:

void CNonPlayerCharacter::Update(){
	if(ControlAircraft!=NULL){
		if(ControlAircraft->GetExist()){

			(this->*AI_Func)();//AIの状態にはいくつか用意する予定。

			ControlAircraft->Update();
		}
	}
}
//基準座標系の座標を、飛行機の座標系に変換する。MGetAxis2の使い方に難があるかも・・・

コード:

VECTOR CNonPlayerCharacter::GetTargetDirection(VECTOR TargetPosition){
	VECTOR DestinationDirection = VSub(TargetPosition , ControlAircraft->GetPosition());

	//飛行機のローカル座標からワールド座標へ変換する行列の逆行列??正しいのかはわかりません??
	MATRIX PredeterminedAngle =  MGetAxis2(ControlAircraft->AxisX,ControlAircraft->AxisY,ControlAircraft->AxisZ,ControlAircraft->Position);

	return VNorm(VTransform(DestinationDirection,PredeterminedAngle));
}

珈琲

Re: 飛行機を目的地の方向に向けたい

#6

投稿記事 by 珈琲 » 12年前

勿論、最終的には飛行機の安全を確保しながら目的地へ移動するAIを作ったりしたいです。

ソースコードは、一応AIに関する所悩んでる所としては、以上だと思いますが、何か抜けていたらお願いします。

アバター
h2so5
副管理人
記事: 2212
登録日時: 14年前
住所: 東京
連絡を取る:

Re: 飛行機を目的地の方向に向けたい

#7

投稿記事 by h2so5 » 12年前

どうして期待している結果と実際の結果が合っているか確かめようとしないのでしょうか。
「予想では」とか「書いたつもり」ではなく実際に数値を入れて正しいのか確かめてください。
珈琲 さんが書きました: (1)「基準座標系から飛行機が持つ座標系に変換」する行列を使って、飛行機からみた目的地の座標に変換し、正規化して方向ベクトルとします。
  この時作成した行列を使って飛行機自身をトランスフォームして座標を出すと、常に座標 0,0,0 回転ベクトルも0,0,0になります(予想では)。
珈琲 さんが書きました: えーと、直前の注釈と同じ処理のコードを書いたつもりです。
2つのベクトルの内積のよって算出される値が-1.0~1.0ということなので、
1.0だったら2つのベクトルが全く同じ方向を向いている
-1.0だったら全く逆の方向を向いている
0だったら垂直
0.5だったら斜め前・・・?という感じで・・・

珈琲

Re: 飛行機を目的地の方向に向けたい

#8

投稿記事 by 珈琲 » 12年前

テスト用コードを作りました。ブレークポイントを5行目の終わりに設定し、値を見ます。

コード:

	MATRIX Angle =  MGetAxis2(ControlAircraft->AxisX,ControlAircraft->AxisY,ControlAircraft->AxisZ,ControlAircraft->GetPosition());

	VECTOR NewAxisX = VTransform(ControlAircraft->AxisX,Angle);
	VECTOR NewAxisY = VTransform(ControlAircraft->AxisY,Angle);
	VECTOR NewAxisZ = VTransform(ControlAircraft->AxisZ,Angle);
[hr]

初期化直後にもかかわらずNewAxisの値が、恐らく初期座標+Axis分と思われる値が入っていました。
これは第四引数を0,0,0としたことで解決しました。

コード:

	MATRIX Angle =  MGetAxis2(ControlAircraft->AxisX,ControlAircraft->AxisY,ControlAircraft->AxisZ);

	VECTOR NewAxisX = VTransform(ControlAircraft->AxisX,Angle);
	VECTOR NewAxisY = VTransform(ControlAircraft->AxisY,Angle);
	VECTOR NewAxisZ = VTransform(ControlAircraft->AxisZ,Angle);
[hr]

しばらく動かしてからブレークポイントを追加してみました。
NewAxisがまたもや1以上の値に。トランスフォームの種類が悪いのかと予想しました、が、値は変わらず。

コード:

	MATRIX Angle =  MGetAxis2(ControlAircraft->AxisX,ControlAircraft->AxisY,ControlAircraft->AxisZ);

	VECTOR NewAxisX = VTransformSR(ControlAircraft->AxisX,Angle);
	VECTOR NewAxisY = VTransformSR(ControlAircraft->AxisY,Angle);
	VECTOR NewAxisZ = VTransformSR(ControlAircraft->AxisZ,Angle);

珈琲

Re: 飛行機を目的地の方向に向けたい

#9

投稿記事 by 珈琲 » 12年前

一つ前の返信に第四引数指定されていませんでした。

コード:

MATRIX Angle =  MGetAxis2(ControlAircraft->AxisX,ControlAircraft->AxisY,ControlAircraft->AxisZ,VGet(0,0,0));
軸がずれてるのかと思いMGetAxis2の引数の中身をローテーションしてみましたが、3回目当たりのローテーションで意味ないことに気づきやめました。

コード:

    MATRIX Angle =  MGetAxis2(ControlAircraft->AxisZ,ControlAircraft->AxisX,ControlAircraft->AxisY,VGet(0,0,0));
 
    VECTOR NewAxisX = VTransform(ControlAircraft->AxisX,Angle);
    VECTOR NewAxisY = VTransform(ControlAircraft->AxisY,Angle);
    VECTOR NewAxisZ = VTransform(ControlAircraft->AxisZ,Angle);

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: 飛行機を目的地の方向に向けたい

#10

投稿記事 by usao » 12年前

>問題を単純化したほうが、後々応用が効くかなと思い、
>目前の問題だけまず解決しようかなと・・・。
>でもそのせいで今、後出しはやめろと非難されてるんですよね、申し訳ありません。

別に単純化した問題を扱うのは悪くないですし,
不要な箇所までコードを出せとも言っていません.
単に,
「機種を目的地の方向に向ける」ためにどういう手順で処理を行おうとしているのですか?と質問しているだけです.
その肝心のAIの中身が決まっていないのであれば,
「思うように動く」はずもないのですし,誰も何も答えられないと思うのですが.

「後出し云々」については,
そのような質問状況に対して回答者が回答者なりの方法を答える→実は違う方法でやることを考えているみたいなやりとりが過去に行われており,
先に「どういう制御手順でやることを考えているのか」を示していただいた方が話が早かろうと考えたので申し上げました.
非難しているのではなく,単に不毛なやりとりを避けたいだけです.

要するに腹案があるなら示してくださいよ,と.
例えば
「私なら,まずは方角だけを揃え,その後仰俯角を揃える,という手順で考えます.
 方角のずれが少ない場合は,機体ロール姿勢を水平にすると共に方角はヨーイングで近づけることにし,ロール姿勢が十分小さい場合はPitch角の揃えを開始します.
 方角ずれが大きい場合には,90度ローリング+ピッチで急速に方向転換します.ある程度方角が揃った時点で前文のルーチンに入ります.」
とかいう制御フローを示したとして,
その方法をあなたが気に入らないor別の方法を考えている ということであれば,丸々長文が無駄になるので.
(ちなみに↑の文は私がエースコンバットとかで実際に操作する際のフローです.
 へたくそなので,最短の制御は無理→このような操作になります.)

>if(0.7 > VDot(DestinationDirection,ControlAircraft->GetDirection())){
比較値がcos(45度)に近づいたようですね.

珈琲

Re: 飛行機を目的地の方向に向けたい

#11

投稿記事 by 珈琲 » 12年前

目的を書いていませんでした。
目的は機体の座標系を利用して、機体の角度を算出する、です。
h2so5さんの指摘どおり、指定座標系に変換するための行列が間違っていたようです。

機体の座標系を利用して機体を表現したら、必ず原点になるはずです。
NewAxisX == VECTOR(1,0,0)
NewAxisY == VECTOR(0,1,0)
NewAxisZ == VECTOR(0,0,1)
となるのが理想ですが、浮動小数点型の誤差程度なら許容範囲です。


続き
MGetAxis2の代わりにMGetAxis1を使用してみました。
NewAxisはそれぞれ正しい方向に向いていませんでした。

コード:

	MATRIX Angle =  MGetAxis1(ControlAircraft->AxisX,ControlAircraft->AxisY,ControlAircraft->AxisZ,VGet(0,0,0));

	VECTOR NewAxisX = VTransformSR(ControlAircraft->AxisX,Angle);
	VECTOR NewAxisY = VTransformSR(ControlAircraft->AxisY,Angle);
	VECTOR NewAxisZ = VTransformSR(ControlAircraft->AxisZ,Angle);
[hr]

逆行列にしてみました。結果から見ると正解に近いです。
NewAxisX = {x=1.0000000 y=0.00000000 z=0.00000000 }
NewAxisY = {x=0.00000000 y=1.0000000 z=1.4901161e-008 }
NewAxisZ = {x=0.00000000 y=-3.3527613e-008 z=1.0000000 }

が、e-008とはなんぞや・・・

コード:

	MATRIX Angle =  MGetAxis1(ControlAircraft->AxisX,ControlAircraft->AxisY,ControlAircraft->AxisZ,VGet(0,0,0));

	Angle = MInverse(Angle);

	VECTOR NewAxisX = VTransformSR(ControlAircraft->AxisX,Angle);
	VECTOR NewAxisY = VTransformSR(ControlAircraft->AxisY,Angle);
	VECTOR NewAxisZ = VTransformSR(ControlAircraft->AxisZ,Angle);

珈琲

Re: 飛行機を目的地の方向に向けたい

#12

投稿記事 by 珈琲 » 12年前

usao さんが書きました: そのような質問状況に対して回答者が回答者なりの方法を答える→実は違う方法でやることを考えているみたいなやりとりが過去に行われており,
先に「どういう制御手順でやることを考えているのか」を示していただいた方が話が早かろうと考えたので申し上げました.
非難しているのではなく,単に不毛なやりとりを避けたいだけです.

要するに腹案があるなら示してくださいよ,と.
それは、失礼しました。

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: 飛行機を目的地の方向に向けたい

#13

投稿記事 by usao » 12年前

今何かを確認されているコードって他者が見てわかるものなのでしょうか?
貼られているコードで使われている関数とかが
一般的に使われているライブラリの関数か何かであって,
見る人が見ればわかる(つまり他者からアドバイスが得られる状態である)のであれば良いのですが.
オフトピック
ところで,現状態は
ワールド座標系とローカル座標系との間での座標変換 という基礎的な事柄がバグっているという話なのですか?
(つまり本題とは関係ない,かなり前段階のところで問題発生中?)
だとしたら
他のスレッドでやられているミサイルの話等でもそういったこと必要だと思いますし,
(というか今までずっと3次元のSTGをコーディングされてこられたのでしょうから,当然座標系間での変換が出てこなかったはずはないと思うので)
遥か昔に用意されている処理だと思うのですが…
モジュールとして用意していないのだとしても,そこから持って来れば良いような?

[追記]
MGetAxis1とか2とかが出てくる前の
最初に貼られたコードで座標変換は雰囲気的には合ってるように見えるけど…(?)

珈琲

Re: 飛行機を目的地の方向に向けたい

#14

投稿記事 by 珈琲 » 12年前

今まで使用してきたコードは
操作する部分だけです。
プレイヤーはカメラが回転も含めて追従してるので、飛行機の操作はそのまま直感的に反映させればいいだけでした。(Dxlibにカメラ用の関数がある)
つまりワールド⇔ローカルの座標変換は必要ありませんでした。

今何かを確認されているコードって他者が見てわかるものなのでしょうか?
貼られているコードで使われている関数とかが
一般的に使われているライブラリの関数か何かであって,
見る人が見ればわかる(つまり他者からアドバイスが得られる状態である)のであれば良いのですが.
失礼しました、当方Dxlibを使っています。

また、
h2so5 さんが書きました:どうして期待している結果と実際の結果が合っているか確かめようとしないのでしょうか。
「予想では」とか「書いたつもり」ではなく実際に数値を入れて正しいのか確かめてください。
珈琲 さんが書きました: (1)「基準座標系から飛行機が持つ座標系に変換」する行列を使って、飛行機からみた目的地の座標に変換し、正規化して方向ベクトルとします。
  この時作成した行列を使って飛行機自身をトランスフォームして座標を出すと、常に座標 0,0,0 回転ベクトルも0,0,0になります(予想では)。
と指摘され、実際に確かめてみたところ基礎部分が変でした → 直せない という感じです
ワールド座標系とローカル座標系との間での座標変換 という基礎的な事柄がバグっているという話なのですか?
(つまり本題とは関係ない,かなり前段階のところで問題発生中?)
まさにその通りです・・・
MGetAxisのリファレンスの説明の認識が間違っているんだと思いますが、どこが間違っているのか判明せず

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: 飛行機を目的地の方向に向けたい

#15

投稿記事 by usao » 12年前

うーん,よくわからないけど,
”今まではライブラリがその辺の変換を中でやってくれていたのだけれど,
 今回その変換を自前で計算しないとならなくなった”
といった感じ…なのかな?


>ControlAircraft->AxisX
・このControlAircraftというやつもライブラリ側が提供してくれているオブジェクトを指しているのでしょうか?
・そのメンバ AxisX とか GetPosition() とかは実際には何に相当しているのでしょう?

GetPosition()が返す座標が,ワールド座標系で書かれた 飛行機の現在位置 であって,
AxisX,AxisY,AxisZ が, ワールド座標系で書かれた 飛行機座標系の基底ベクトル(3軸の単位方向ベクトル)
なのかな?と思っていたのですが,合っていますか?
 ↓
もしそうであれば,最初に貼られたコードの
(Desitinationが ワールド座標系で書かれた 目的地の現在位置 であれば)
line7~line25 の処理で変換できていないのでしょうか?


>MGetAxisのリファレンスの説明の認識が間違っているんだと思いますが、どこが間違っているのか判明せず
これについては私は存じないので知っている人待ち…かなぁ

珈琲

Re: 飛行機を目的地の方向に向けたい

#16

投稿記事 by 珈琲 » 12年前

AxisXというのはVECTOR型の構造体の変数名です。
VECTOR型は{float x,float y,float z}と定義されていて、私はベクトルや三次元座標として使用しています。
GetPosition()が返す座標が,ワールド座標系で書かれた 飛行機の現在位置 であって,
AxisX,AxisY,AxisZ が, ワールド座標系で書かれた 飛行機座標系の基底ベクトル(3軸の単位方向ベクトル)
なのかな?と思っていたのですが,合っていますか?
はい、そうです。イメージとしては、
実際に手で左手の座標系を作ってみて、指は固定で手首で回転させるようなイメージです。
line7~line25 の処理で変換できていないのでしょうか?
できたと思っていましたが、確認してみたところ変換できていませんでした。

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: 飛行機を目的地の方向に向けたい

#17

投稿記事 by usao » 12年前

VTransform()というのをググってみたところ,以下のような変換みたいです.
>戻り値.x = InV.x * InM.m[0][0] + InV.y * InM.m[1][0] + InV.z * InM.m[2][0] + InM.m[3][0] ;
>戻り値.y = InV.x * InM.m[0][1] + InV.y * InM.m[1][1] + InV.z * InM.m[2][1] + InM.m[3][1] ;
>戻り値.z = InV.x * InM.m[0][2] + InV.y * InM.m[1][2] + InV.z * InM.m[2][2] + InM.m[3][2] ;

つまり↓のような形になってる?
(私が思ってた変換と違う.縦ベクトルに,3*3マトリクスが左から掛けられるのだと思ってた)

コード:

                                        lnM
                               [ 0,0   0,1   0,2 ]
result[x y z] = InV[x y z 1] * [ 1,0   1,1   1,2 ]  ※マトリクスの要素の並びってこうですか?※
                               [ 2,0   2,1   2,2 ]
                               [ 3,0   3,1   3,2 ]
だとしたら lnMの上側3*3のところを転置してみたらダメでしょうか?
(一番下の行は0で埋まっているんですよね? というか,ここにVSubの処理もまとめて書けますけど.←やめとこう)

珈琲

Re: 飛行機を目的地の方向に向けたい

#18

投稿記事 by 珈琲 » 12年前

返信が非常に遅くなりました、すいません。

行列は多少調べてみた程度で、自分にはどのような順序・計算が正しいのかさっぱりわかりません。(例えば移動行列はこのようにあるべきだ、と思うことが出来ません)

とりあえず、MATRIX型の中の配列の中身をひっくり返せばいいのでしょうか?

少し前の、
珈琲 さんが書きました: 逆行列にしてみました。結果から見ると正解に近いです。
NewAxisX = {x=1.0000000 y=0.00000000 z=0.00000000 }
NewAxisY = {x=0.00000000 y=1.0000000 z=1.4901161e-008 }
NewAxisZ = {x=0.00000000 y=-3.3527613e-008 z=1.0000000 }

が、e-008とはなんぞや・・・

コード:

	MATRIX Angle =  MGetAxis1(ControlAircraft->AxisX,ControlAircraft->AxisY,ControlAircraft->AxisZ,VGet(0,0,0));

	Angle = MInverse(Angle);

	VECTOR NewAxisX = VTransformSR(ControlAircraft->AxisX,Angle);
	VECTOR NewAxisY = VTransformSR(ControlAircraft->AxisY,Angle);
	VECTOR NewAxisZ = VTransformSR(ControlAircraft->AxisZ,Angle);
この状態が一番近いので(末尾がe-008という値さえでなければ)、
何かヒントになるんじゃないかと思ってたのですが、インターンシップが重なっちゃってこれ以降あまり試せませんでした。

そもそもこのe-008って普通の計算じゃでないですよね?
MATRIX型というのはfloat配列の集まりだったはずなので、中身は結局四則演算をやってるものだと認識してたんですが

珈琲

Re: 飛行機を目的地の方向に向けたい

#19

投稿記事 by 珈琲 » 12年前

e-008というのを調べてみたところfloatの不動点らしいです。
なぜきっかり0にならないかというと、AxisZから見てAxisYやAxisXがきっちり垂直になっていないからかと思われます。
きっちり垂直にするためには、現在の「3軸の値を初期化したあとゲーム中それを使いまわす」ではなく、
「1軸1回転率から計算の直前に3軸を算出する」という方法が必要かと思われますが、以前のフォーラムの質問で回答が得られなかったのもあって迷宮入りになってます。
課題として後ほどやります。

e-008となる値は極端に小さい値ですので、AIで使用する分には無視できるかと思います。(細かい方向ベクトルに対してピッタリ合わせる必要はないので)

そうすると、計算処理としてはあっているので、AIの判定の部分が原因だと思います。

コード:

if(0.7 > VDot(DestinationDirection,ControlAircraft->GetDirection())){
このif文を抜くと正常に動いてるように見えるのですが、
>if(0.7 > VDot(DestinationDirection,ControlAircraft->GetDirection())){
比較値がcos(45度)に近づいたようですね.
というのはどういう意味なんでしょうか?
内積の解説サイトを見てみたのですが、単位ベクトル同士の計算なら正面が+1.0、真後ろが-1.0だと考えているのですが

アバター
h2so5
副管理人
記事: 2212
登録日時: 14年前
住所: 東京
連絡を取る:

Re: 飛行機を目的地の方向に向けたい

#20

投稿記事 by h2so5 » 12年前

珈琲 さんが書きました:
>if(0.7 > VDot(DestinationDirection,ControlAircraft->GetDirection())){
比較値がcos(45度)に近づいたようですね.
というのはどういう意味なんでしょうか?
内積の解説サイトを見てみたのですが、単位ベクトル同士の計算なら正面が+1.0、真後ろが-1.0だと考えているのですが
単位ベクトルの内積はベクトルのなす角度の余弦に等しいということは解説サイトに書いてないんですかね。
角度が45°なら内積は cos 45° ≒ 0.70710678118 になります。

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: 飛行機を目的地の方向に向けたい

#21

投稿記事 by usao » 12年前

>逆行列
回転マトリクスの逆行列,ということであれば,転置と同じ意味です
(正しい文言(?)をググったところ「直行行列の逆行列は転置」だそうです.)

>e-008
10のマイナス8乗です.
その程度なら影響のほとんどない誤差と見なして良いのではないでしょうか.

>内積
うーん,{内積や外積,行列の本当の基礎}くらいはさすがに勉強しないと
3Dのゲームを作るのは難しい(というか無茶な)気がしますが… (中学校か高校でやったと思うのですけど.)
【内積】
A・B = |A||B|cosθ
ここで,|*|はベクトル*の大きさ,θはAとBがなす角です.
また,内積はA,Bの成分から
A・B = ax*bx + ay*by + az*bz
としても計算できます.
なので,あらかじめ正規化(|A|=|B|=1の状態に)されたA,Bに対して,下側の式で内積の値A・Bを求めれば,その値=上側の式なので
2つのベクトルがなす角についてのcos値が得られるわけです.

珈琲

Re: 飛行機を目的地の方向に向けたい

#22

投稿記事 by 珈琲 » 12年前

単位ベクトルの内積はベクトルのなす角度の余弦に等しいということは解説サイトに書いてないんですかね。
角度が45°なら内積は cos 45° ≒ 0.70710678118 になります。
私の考えだと正面から45度に位置するのは0.5になるはずなので、私の認識が間違っていたということですよね
DestinationDirectionの方向にControlAircraft->GetDirection()はどれぐらい仕事をしたか、という比率を表しているという感じですよね。
まぁ距離1の円周上に存在する点の基本軸値なので、イメージ出来なくはないですが・・。

としたら、

コード:

    //目的地の方向へ45度圏内に入っていなければ、方向を変える
    if( 0.70710678118 > VDot(DestinationDirection,ControlAircraft->GetDirection())){
 
        if( 0 < DestinationDirection.x ){//右側
            ControlAircraft->Roll(0.5);
            if( 0 < DestinationDirection.y ){
                ControlAircraft->Pitch(1.0);
            }
        }else{
            ControlAircraft->Roll(-0.5);
            if( 0 < DestinationDirection.y ){
                ControlAircraft->Pitch(1.0);
            }
        }
    }
と、コメントに沿った形になりますが、
値が少々変わった所で「目標への向きと現在の向きのなす角度が45度以上ある場合、if文のスコープに入る」という動作をしません。
つまり、DestinationDirectionの方向にControlAircraft->GetDirection()は0.707..以下の仕事しかしていなければ、という条件なはずです。(両方共単位ベクトルなので)

これは以前の0.5と比較していたコードの時と根本的な解決になっていないような・・・

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: 飛行機を目的地の方向に向けたい

#23

投稿記事 by usao » 12年前

>これは以前の0.5と比較していたコードの時と根本的な解決になっていないような・・・
ならば根本的なことをきちんとひとつずつ確認していきましょう.

まず,座標変換の問題の解決(DestinationDirectionがまともな値として得られていること)が
十分に確認されているのでしょうか?
まだであれば,
正誤が確認できる状況(機体向きと目標点座標)で何通りか計算させて確実に求められていることを
しっかりと確認してください.
(以降の処理に対する入力なので.入力が間違っていれば話が進まない)

で,そのうえで,
>「目標への向きと現在の向きのなす角度が45度以上ある場合、if文のスコープに入る」という動作をしません。
(現在どうやって確認されているのかわかりませんが)
ifに入るべきか否かが明確な状況のもとで,本当に判定が成功しているかどうかをデバッグし,状況を把握しましょう.
オフトピック
いきなり3Dなアプリ上で実装せずに
別途デバッグ用の「平行な2D平面が3枚くらい存在する世界」とかで
アルゴリズムの原理確認をされた方が,いろいろと早いような気もします.
たまたま見つけたのですが,
DXライブラリのMATRIXに関する話(?)が過去ログにあるようです.
(全然中味見ないでリンク貼っちゃいますので,役に立つかどうか不明ですけど)
http://dixq.net/forum/viewtopic.php?f=3&t=10136
オフトピック
あと,何度も同じようなことを言うようで心苦しいのですが,
(あなたにこのことを言うのはこれを最後にするので,気分を害さないでいただきたい)

「その演算が具体的に何をしているのか=自分が何を書いているのか」
(値の計算自体はライブラリがしてくれるのでしょうけど,その”意味”の側)
を把握されないままに進めていくと,今後も同じようにちょっとしたことで行き詰ってしまうと思いますよ.

例えば,2次元の世界で,ベクトルVを,回転マトリクスRを用いて回転する演算
 V_rotated = R * V
について,「この行列Rの成分とは何なのか」→「すなわちこの式がやってることってこういうこと」
みたいなことを説明できますでしょうか?
回転行列についてはググればcosθとsinθが並んだものを簡単に見つけることはできますが,
回転角θをコードで直接扱っていない場合(今回もそうですよね)
「どうすればよいのでしょう?」となって行き詰ってしまうかもしれません.

もちろん,高度すぎて意味不明な数学みたいなの を祈りつつブラックボックス的に使うしかないときは多々ありますが,
本当に基礎の部分くらいは知っておかないと今後の3Dゲーム制作に支障があると思います.

珈琲

Re: 飛行機を目的地の方向に向けたい

#24

投稿記事 by 珈琲 » 12年前

usao さんが書きました:>これは以前の0.5と比較していたコードの時と根本的な解決になっていないような・・・
ならば根本的なことをきちんとひとつずつ確認していきましょう.

まず,座標変換の問題の解決(DestinationDirectionがまともな値として得られていること)が
十分に確認されているのでしょうか?
まだであれば,
正誤が確認できる状況(機体向きと目標点座標)で何通りか計算させて確実に求められていることを
しっかりと確認してください.
(以降の処理に対する入力なので.入力が間違っていれば話が進まない)
これを証明するには回転行列の中身にもある平面上の三角関数の挙動について熟知していないといけませんよね
現在の向きから手計算で方向を算出しないといけないのでしょうか。
ゲームを作る上で当たり前なのでしょうけど・・・

usao さんが書きました: で,そのうえで,
>「目標への向きと現在の向きのなす角度が45度以上ある場合、if文のスコープに入る」という動作をしません。
(現在どうやって確認されているのかわかりませんが)
ifに入るべきか否かが明確な状況のもとで,本当に判定が成功しているかどうかをデバッグし,状況を把握しましょう.
確認方法は実際にゲームを動かしてます。
というより先のコードそのままです。

機体が目標地点へ向いていなければ旋回するというコードを書く

目標地点を表示・機体を表示してどうなるかみる

真後ろを向いた状態で何もしない→おかしくない?

となり、おかしいと思いました。

何回か聞いたと思いますが、返答を聞けなかったので
//目的地の方向へ45度圏内に入っていなければ、方向を変える
if( 0.70710678118 > VDot(DestinationDirection,ControlAircraft->GetDirection()))
の条件文は、それぞれの入力値がちゃんとした値だったらコメント分に沿う計算式なのでしょうか?

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: 飛行機を目的地の方向に向けたい

#25

投稿記事 by usao » 12年前

>これを証明するには回転行列の中身にもある平面上の三角関数の挙動について熟知していないといけませんよね
>現在の向きから手計算で方向を算出しないといけないのでしょうか。
>ゲームを作る上で当たり前なのでしょうけど・・・

どういうふうにやるにしても
「こうなったら正しい」「正しい結果はこう」という比較対象がないと,動作が正しいかどうか判断つきませんよね.
手計算で簡単に求められるデータを作るのでももちろんOKですし
例えば,以下のようなテスト方法とかだと,全部PCが計算しますが「正しい結果」が既知ですよね.

(1)まず,飛行機の位置T=(0,0,0)としてワールド原点に置き,回転Rも単位行列にして回転が無い状態(ワールド座標系と飛行機座標系がぴったり一致する状態)にする
(2)ランダムでN個のテスト用目標点P[0~N-1]のワールド座標値を生成する
(3)飛行機座標系での,飛行機位置から見たテスト目標点 の位置は P である.
 (今,RもTも何もしない状態だから)
(4)データ全体(飛行機と目標点群)を ワールド原点周りに ある回転量Rで回転させる.
(5)その後,全体を ある並進量Tだけ平行移動させる.
(6)以上でテスト用データができた. (4)のR と (5)のT が飛行機の現在の姿勢と位置を表す.
 Pは(まるで飛行機の一部分であるかのように)飛行機と一緒に位置姿勢が変換された結果の ワールド座標系での位置 としてあたえられている.
 この状態から,P(とRとT)を 「ワールド座標系での位置を飛行機座標系の位置に読み替える 計算処理」 に入力すれば,
 うまくいけば(3)と同じ値が得られるはずである.


>if( 0.70710678118 > VDot(DestinationDirection,ControlAircraft->GetDirection()))
左辺がcos(45度)の値だとして,VDot()が内積の値を返す関数であって,
右辺の DestinationDirection と ControlAircraft->GetDirection() が共に同一の座標系の上での単位方向ベクトルであれば
式としては合っていると思います.で,
>真後ろを向いた状態で何もしない→おかしくない?
このように曖昧な現象を見て判断するよりも
とりあえず毎フレーム 右辺の値をダイレクトに表示してみてはいかがでしょうか.
さらにif()の中に入ったらそのことを示す表示もしてみれば,計算値と判定結果の兼ね合いが見られると思います.
[追記]
↑「何もしない」という状況は「何かすべき,という判定箇所(if)」の他に「何かするコードの側(if(){}の中の処理)」に問題がある可能性も考えられるので,
まずは前者だけに絞ってデバッグしましょう,という話.
最後に編集したユーザー usao on 2013年9月03日(火) 13:54 [ 編集 1 回目 ]

アバター
h2so5
副管理人
記事: 2212
登録日時: 14年前
住所: 東京
連絡を取る:

Re: 飛行機を目的地の方向に向けたい

#26

投稿記事 by h2so5 » 12年前

珈琲 さんが書きました:
usao さんが書きました: で,そのうえで,
>「目標への向きと現在の向きのなす角度が45度以上ある場合、if文のスコープに入る」という動作をしません。
(現在どうやって確認されているのかわかりませんが)
ifに入るべきか否かが明確な状況のもとで,本当に判定が成功しているかどうかをデバッグし,状況を把握しましょう.
確認方法は実際にゲームを動かしてます。
というより先のコードそのままです。

機体が目標地点へ向いていなければ旋回するというコードを書く

目標地点を表示・機体を表示してどうなるかみる

真後ろを向いた状態で何もしない→おかしくない?

となり、おかしいと思いました。
その確認方法で、if文のスコープに入っていないのか、スコープの中の処理に問題があるのか区別できますか?
回りくどい方法を取らないで、if文の直後にprintfやブレークポイントを入れるなどの確実な方法を取ってください。
珈琲 さんが書きました: 何回か聞いたと思いますが、返答を聞けなかったので
//目的地の方向へ45度圏内に入っていなければ、方向を変える
if( 0.70710678118 > VDot(DestinationDirection,ControlAircraft->GetDirection()))
の条件文は、それぞれの入力値がちゃんとした値だったらコメント分に沿う計算式なのでしょうか?
なんども言いますが、「ちゃんとした値」を入れて確認すれば済む話です。

タミア

Re: 飛行機を目的地の方向に向けたい

#27

投稿記事 by タミア » 12年前

横から失礼します。
珈琲 さんが書きました://目的地の方向ベクトルを回転させる。これで飛行機から見た方向ベクトルになるはず。(飛行機の正面に目的地があった場合、0.0 , 0.0 , 1.0
上記より、真後ろ(180°位置)ならDestinationDirectionは(0,0,-1)になるのを想定されてるんですよね?
では、ControlAircraft->GetDirection()が(0,0,1)を返す(ちゃんと正規化されたベクトルが返されるんですよね?)として、
VDotの結果を見てみましょう。
0*0+0*0+(-1)*1 となり、-1が返りますから、if文の条件を満たすはずです。
次に、ControlAircraft->GetDirection()が(1,0,0)を返す場合だと、
0*1+0*0+(-1)*0 で、戻り値は0になりますね。しかし、同じ真後ろ(180°位置)にあるはずなのに上とは結果が異なります。
DestinationDirectionが(0,0,1)、ControlAircraft->GetDirection()が(1,0,0)でも同様の結果になり、
正面にあるはずなのに方向転換しようとしますね。
つまり、コメント文に沿う計算式ではなさそうです。
ただし、DestinationDirectionが珈琲さんの想定通りの結果になっていると仮定した場合であり、
想定していない結果になっていた場合はどうなるかわかりません。

ベクトルや行列の知識がないのでアドバイスなどはできませんが、
このようにこの数値ならどうなるか、といった感じで計算してみると
処理が正しいかどうかわかるかと思います。

珈琲

Re: 飛行機を目的地の方向に向けたい

#28

投稿記事 by 珈琲 » 12年前

usao さんが書きました:>これを証明するには回転行列の中身にもある平面上の三角関数の挙動について熟知していないといけませんよね
>現在の向きから手計算で方向を算出しないといけないのでしょうか。
>ゲームを作る上で当たり前なのでしょうけど・・・

どういうふうにやるにしても
「こうなったら正しい」「正しい結果はこう」という比較対象がないと,動作が正しいかどうか判断つきませんよね.
手計算で簡単に求められるデータを作るのでももちろんOKですし
例えば,以下のようなテスト方法とかだと,全部PCが計算しますが「正しい結果」が既知ですよね.

(1)まず,飛行機の位置T=(0,0,0)としてワールド原点に置き,回転Rも単位行列にして回転が無い状態(ワールド座標系と飛行機座標系がぴったり一致する状態)にする
(2)ランダムでN個のテスト用目標点P[0~N-1]のワールド座標値を生成する
(3)飛行機座標系での,飛行機位置から見たテスト目標点 の位置は P である.
 (今,RもTも何もしない状態だから)
(4)データ全体(飛行機と目標点群)を ワールド原点周りに ある回転量Rで回転させる.
(5)その後,全体を ある並進量Tだけ平行移動させる.
(6)以上でテスト用データができた. (4)のR と (5)のT が飛行機の現在の姿勢と位置を表す.
 Pは(まるで飛行機の一部分であるかのように)飛行機と一緒に位置姿勢が変換された結果の ワールド座標系での位置 としてあたえられている.
 この状態から,P(とRとT)を 「ワールド座標系での位置を飛行機座標系の位置に読み替える 計算処理」 に入力すれば,
 うまくいけば(3)と同じ値が得られるはずである.


手順通りにやってみました(みたつもりです
此方が結果です。誤差が気になりますが・・・あっているんでしょうか?
画像

また、MGetAxis2でもやってみたところ同じような結果になりました。
リファレンスや行列の解説を見たらMGetAxis1の逆行列がMGetAxis2と書いてありました。
うーん・・?以前は違った結果が現れたような・・・。

コード:

#include "DxLib.h"

int ProcessLoop(){
	if(ScreenFlip()!=0)return -1;
	if(ProcessMessage()!=0)return -1;
	if(ClearDrawScreen()!=0)return -1;
	return 0;
}

//飛行機構造体
struct SAircraft{
	VECTOR AxisX;
	VECTOR AxisY;
	VECTOR Direction;
	VECTOR Position;
};

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
	ChangeWindowMode(true);
	SetGraphMode(1280,720,16);
	SetWindowText("回転行列");

	DxLib_Init();

//(1)
	//Aircraftの宣言と初期化
	SAircraft Aircraft ={
		VGet(1,0,0),//X
		VGet(0,1,0),//Y
		VGet(0,0,1),//Direction(Z)
		VGet(0,0,0),//Pos
	};

//(2),(3)
	//ランダムな点を10個作成。また、比較用に保持

	const int P_NUM = 5;
	VECTOR P[P_NUM];
	VECTOR PrevP[P_NUM];

	for(int i=0;i<P_NUM;i++){
		P[i]=VGet(GetRand(100),GetRand(100),GetRand(100));
		PrevP[i]=P[i];
	}

//(4)
	//すべての点PとAircraftを回転させます。値は適当
	float XRot=DX_PI_F/180 * GetRand(360);
	float YRot=DX_PI_F/180 * GetRand(360);
	float ZRot=DX_PI_F/180 * GetRand(360);

	MATRIX MatX = MGetRotX(XRot);
	MATRIX MatY = MGetRotY(YRot);
	MATRIX MatZ = MGetRotZ(ZRot);

	MATRIX RotMatrix = MMult(MatX,MatY);
	RotMatrix = MMult(RotMatrix,MatZ);

	Aircraft.AxisX = VTransform(Aircraft.AxisX,RotMatrix);
	Aircraft.AxisY = VTransform(Aircraft.AxisY,RotMatrix);
	Aircraft.Direction = VTransform(Aircraft.Direction,RotMatrix);

	for(int i=0;i<P_NUM;i++){
		P[i] = VTransform(P[i],RotMatrix);
	}

//(5)
	//平行移動。ただし、AircraftはPositionに適用する値は適当
	VECTOR MoveVector = VGet(GetRand(100),GetRand(100),GetRand(100));

	Aircraft.Position = VAdd(Aircraft.Position,MoveVector);

	for(int i=0;i<P_NUM;i++){
		P[i] = VAdd(P[i],MoveVector);
	}

//(6)
	//準備完了。
	//ワールド変換行列を試してみる。
	MATRIX PredeterminedAngle =  MGetAxis1(Aircraft.AxisX,Aircraft.AxisY,Aircraft.Direction,Aircraft.Position);

	PredeterminedAngle = MInverse(PredeterminedAngle);

	for(int i=0;i<P_NUM;i++){
		P[i] = VTransform(P[i],PredeterminedAngle);
	}

	//結果描画

	DrawFormatString(100,80,GetColor(100,255,100),"変換後");
	DrawFormatString(500,80,GetColor(100,255,100),"返還前");

	for(int i=0;i<P_NUM;i++){
		DrawFormatString(100,100+i*50,GetColor(100,255,100),"P%d.X: %f",i,P[i].x);
		DrawFormatString(100,115+i*50,GetColor(100,255,100),"P%d.Y: %f",i,P[i].y);
		DrawFormatString(100,130+i*50,GetColor(100,255,100),"P%d.Z: %f",i,P[i].z);

		DrawFormatString(500,100+i*50,GetColor(100,255,100),"Pre%d: X,%f",i,PrevP[i].x);
		DrawFormatString(500,115+i*50,GetColor(100,255,100),"Pre%d: Y,%f",i,PrevP[i].y);
		DrawFormatString(500,130+i*50,GetColor(100,255,100),"Pre%d: Z,%f",i,PrevP[i].z);
	}

	WaitKey();
	
	DxLib_End(); // DXライブラリ終了処理
	return 0;

}


珈琲

Re: 飛行機を目的地の方向に向けたい

#29

投稿記事 by 珈琲 » 12年前

画像

飛行機の移動処理を止め、回転だけする飛行機のAIの動作を見てみました。
動画gifなのでちょっとカクついてわかりにくいかもしれません。

目的地は、プレイヤーの飛行機の座標になっています。

左上の緑色の文字が
VDot(DestinationDirection,ControlAircraft->GetDirection())
の値です。
ただ、回転するにつれてこの値がどんどん変化しています。あまり好ましくない変化です。
先のワールド変換行列があっているのだとしたら、内積の認識がまだいまいち・・・

コード:

VECTOR CNonPlayerCharacter::GetTargetDirection(VECTOR TargetPosition){
	VECTOR DestinationDirection = VSub(TargetPosition , ControlAircraft->GetPosition());

	MATRIX PredeterminedAngle =  MGetAxis2(ControlAircraft->AxisX,ControlAircraft->AxisY,ControlAircraft->AxisZ,ControlAircraft->GetPosition());

	return VNorm(VTransform(DestinationDirection,PredeterminedAngle));
}

void CNonPlayerCharacter::AI_Idle(){

//目的地の方向へ向きを変えたい
	//目的地の方向

	VECTOR DestinationDirection;
	//Leaderが目標
	DestinationDirection = GetTargetDirection(AffiliationSquadron->GetMember(0)->GetControlAircraft()->GetPosition());

	MATRIX PredeterminedAngle =  MGetAxis1(ControlAircraft->AxisX,ControlAircraft->AxisY,ControlAircraft->AxisZ,ControlAircraft->GetPosition());

	VECTOR tmpDirection = VNorm(VTransformSR(DestinationDirection,PredeterminedAngle));

 //目的地への方向のライン赤
	DrawLine3D(ControlAircraft->GetPosition(),VAdd(VScale(tmpDirection,1000),ControlAircraft->GetPosition()),GetColor(211,111,111));
 //飛行機の向きライン緑
	DrawLine3D(ControlAircraft->GetPosition(),VAdd(VScale(ControlAircraft->GetDirection(),1000),ControlAircraft->GetPosition()),GetColor(111,211,111));
	
	if(	1 > VDot(DestinationDirection,ControlAircraft->GetDirection())){

		if( 0 < DestinationDirection.x ){//右側
			ControlAircraft->Roll(0.5);
			if( 0 < DestinationDirection.y ){
				ControlAircraft->Pitch(1.0);
			}
		}else{
			ControlAircraft->Roll(-0.5);
			if( 0 < DestinationDirection.y ){
				ControlAircraft->Pitch(1.0);
			}
		}
		DrawFormatString(200,200,123123,"旋回中です%f",VDot(DestinationDirection,ControlAircraft->GetDirection()));
	}else{
		DrawFormatString(200,200,123123,"旋回していません%f",VDot(DestinationDirection,ControlAircraft->GetDirection()));
	}
}

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: 飛行機を目的地の方向に向けたい

#30

投稿記事 by usao » 12年前

座標変換側のテストについては,(コードまで読んでませんがテスト自体がバグってたりしないならば)
結果としては良いのではないでしょうか.
このテストで用いたRとTが,あなたが本番側のコードで用いているそれらと同じデータ形式であれば
計算箇所をそのまま本番側に持って行っても使えるハズです.

gifで示された側は
見るべき値は左上の水色の値で,これは 紫の線と緑の線 がなす角のcos()値になっているべき ということですよね?

まず,今回は少なくとも,内積の値がcos(45度)の境界を越えた際に if(){}のスコープに入ったか入らなかったか,を見たいのだと思うのですが,
gifを見た感じだと常に cos(45度) より小さい値しか出ていないように見えます.(テスト状況が不足,というか)

>ただ、回転するにつれてこの値がどんどん変化しています。あまり好ましくない変化です。
(コードをちゃんと読めばわかるのかもしれませんが,訊いた方が早いと思うので訊きます)
くるくる回ってるやつは,どういう回転をしているのでしょう?
回転軸が 2つの機体を結ぶ紫の線 になっているのであれば,値は誤差程度しか変わらないと思います.
(3D表示だと,そうなっているようにも見えるし,そうじゃないようにも見える)

[追記]
>先のワールド変換行列があっているのだとしたら
こういうことが可能かどうかわからないのですが,変換結果得られた,飛行機座標系での方向ベクトルを
適当な長さの棒として飛行機と一緒に描画する
(飛行機のモデルの一部に棒を加える&棒先端の座標データを動的に変更 という感じ.
 飛行機モデルのポリゴンとかの座標は飛行機の座標系で書かれていると思うので,
 そこに飛行機座標系で得られている棒を追加することは簡単にできたりしないかなぁ,と)
みたいなことができれば,視覚的に確認できるかもしれませんね.

珈琲

Re: 飛行機を目的地の方向に向けたい

#31

投稿記事 by 珈琲 » 12年前

gifで示された側は
見るべき値は左上の水色の値で,これは 紫の線と緑の線 がなす角のcos()値になっているべき ということですよね?
そうです、水色でした、すいません。
まず,今回は少なくとも,内積の値がcos(45度)の境界を越えた際に if(){}のスコープに入ったか入らなかったか,を見たいのだと思うのですが,
gifを見た感じだと常に cos(45度) より小さい値しか出ていないように見えます.(テスト状況が不足,というか)
うーん・・
>ただ、回転するにつれてこの値がどんどん変化しています。あまり好ましくない変化です。
(コードをちゃんと読めばわかるのかもしれませんが,訊いた方が早いと思うので訊きます)
くるくる回ってるやつは,どういう回転をしているのでしょう?
回転軸が 2つの機体を結ぶ紫の線 になっているのであれば,値は誤差程度しか変わらないと思います.
(3D表示だと,そうなっているようにも見えるし,そうじゃないようにも見える)
分岐によってピッチとロールのみ操作しています。
ピッチは、飛行機からみてX軸で、ロールは飛行機から見てZ軸で回転します。
2つの機体を結ぶ紫の線は、軸ではありません。

また、紫の線の描画方法は
飛行機の座標系からみた、目標地点(今回はプレイヤー機の座標)への方向ベクトルを1000倍したものを描画してみたものです。
コードではこの部分です

コード:

//AffiliationSquadron->GetMember(0)->GetControlAircraft()->GetPosition() という座標を、自機の座標系で表す。ただし単位ベクトルなので長さはわからない方角だけ
DestinationDirection = GetTargetDirection(AffiliationSquadron->GetMember(0)->GetControlAircraft()->GetPosition());

//線を描画するためだけに、自機の座標系から基準座標系に戻す行列を作成します。ただし方角だけ
MATRIX PredeterminedAngle =  MGetAxis1(ControlAircraft->AxisX,ControlAircraft->AxisY,ControlAircraft->AxisZ,ControlAircraft->GetPosition());
VECTOR tmpDirection = VNorm(VTransformSR(DestinationDirection,PredeterminedAngle));

//方角ベクトルを1000倍した長さの線を描画してみます。色は、赤っぽい線です
DrawLine3D(ControlAircraft->GetPosition(),VAdd(VScale(tmpDirection,1000),ControlAircraft->GetPosition()),GetColor(211,111,111));

珈琲

Re: 飛行機を目的地の方向に向けたい

#32

投稿記事 by 珈琲 » 12年前

「もしかしたら、自機の座標系で表現した敵機座標と、基準座標系で表現した自機の座標で内積を取っているからおかしな値がでるのかも?」
と閃いて、これこそ正解だ!と思って試してみました。

コード:


	float Dottmp = VDot(DestinationDirection,VGet(0,0,1));//自機の座標系から見たら自機がどこを向いていても+z方向だろう
	if(	1 > Dottmp){

		if( 0 < DestinationDirection.x ){//右側
			ControlAircraft->Roll(0.5);
			if( 0 < DestinationDirection.y ){
				ControlAircraft->Pitch(1);
			}
		}else{
			ControlAircraft->Roll(-0.5);
			if( 0 < DestinationDirection.y ){
				ControlAircraft->Pitch(1);
			}
		}
		DrawFormatString(200,200,123123,"旋回中です%f",Dottmp);
	}else{
		DrawFormatString(200,200,123123,"旋回していません%f",Dottmp);
	}
画像
これは・・・もしかして・・!?

閉鎖

“C言語何でも質問掲示板” へ戻る