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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Three.js

Three.jsはWebGLをサポートしているJavaScriptの3D描画用ライブラリです。

Q&A

0回答

2151閲覧

Three.jsのQuaternionを使って速度ベクトル変換が正しくできない。

zero1962

総合スコア8

Three.js

Three.jsはWebGLをサポートしているJavaScriptの3D描画用ライブラリです。

1グッド

0クリップ

投稿2016/11/07 09:52

###前提・実現したいこと
Three.jsのQuaternionを使って3Dモデルを座標変換し移動させたい。
(フライトシミュレータのように)

###発生している問題・エラーメッセージ
Three.jsのQuaternionを使って3Dモデルを座標変換し、
同時に機体軸方法の単位ベクトルも座標変換したのちに
速度スカラーを掛け合わし、位置に積算して移動を表現するのですが、

問題は、クオータニオンの角度をオイラー角に変換してみるとプラスマイナス
90度で符号が変わってしまうため、速度ベクトルの作業変換も
90度以上の運動で3Dモデルの姿勢と速度方向の符号が変わって機体軸方向の
速度表現ができません。

90度以内の動作は正常のようです。

クォータニオンからオイラー角表示した場合、各軸プラスマイナス180度は
連続値になるようにはどうすればよいのでしょうか?

エラーメッセージ
とくにありません。

###該当のソースコード

var target = new THREE.Quaternion(); var Qmodel = new THREE.Quaternion(); var P = new THREE.Vector3( 0, 0, 0 ); var V = new THREE.Vector3( 0, 0, 0 ); var Vb = new THREE.Vector3( 0, 0, 0.5); var X_axis = new THREE.Vector3( 1, 0, 0 ).normalize(); var Y_axis = new THREE.Vector3( 0, 1, 0 ).normalize(); var Z_axis = new THREE.Vector3( 0, 0, 1 ).normalize(); var Euler = new THREE.Vector3( 0, 0, 0 ); var Edeg = new THREE.Vector3( 0, 0, 0 ); var Edeg_1 = new THREE.Vector3( 0, 0, 0 ); var Rate = new THREE.Vector3( 0, 0, 0 ); function loop() { requestAnimationFrame( loop ); frameTime = clock.getDelta(); Time += frameTime; document.getElementById( 'Vb.x' ).value = Vb.x.toFixed(2); document.getElementById( 'Vb.y' ).value = Vb.y.toFixed(2); document.getElementById( 'Vb.z' ).value = Vb.z.toFixed(2); document.getElementById( 'Edeg.x' ).value = Edeg.x.toFixed(2); document.getElementById( 'Edeg.y' ).value = Edeg.y.toFixed(2); document.getElementById( 'Edeg.z' ).value = Edeg.z.toFixed(2); document.getElementById( 'Rate.x' ).value = Rate.x.toFixed(2); document.getElementById( 'Rate.y' ).value = Rate.y.toFixed(2); document.getElementById( 'Rate.z' ).value = Rate.z.toFixed(2); if ( Go_BTN_Status && Back_BTN_Status ) { V.z = 0; } if ( !Go_BTN_Status ) { V.z = Menu.Speed * frameTime * -1; } if ( !Back_BTN_Status ) { V.z = Menu.Speed * frameTime; } Qmodel = mesh.quaternion; if ( rad_Pitch > 0.0 ) { target.setFromAxisAngle( X_axis, ( Math.PI / 180 ) * 1 ); Qmodel.multiply(target); Vb.applyQuaternion(target); } else if ( rad_Pitch < 0.0 ) { target.setFromAxisAngle( X_axis, ( Math.PI / 180 ) * -1 ); Qmodel.multiply(target); Vb.applyQuaternion(target); } else if ( rad_Pitch == 0.0 ) { target.setFromAxisAngle( X_axis, ( Math.PI / 180 ) * 0 ); Qmodel.multiply(target); Vb.applyQuaternion(target); } if ( rad_Roll > 0.0 ) { target.setFromAxisAngle( Z_axis, ( Math.PI / 180 ) * 1 ); Qmodel.multiply(target); Vb.applyQuaternion(target); } else if ( rad_Roll < 0.0 ) { target.setFromAxisAngle( Z_axis, ( Math.PI / 180 ) * -1 ); Qmodel.multiply(target); Vb.applyQuaternion(target); } else if ( rad_Roll == 0.0 ) { target.setFromAxisAngle( Z_axis, ( Math.PI / 180 ) * 0 ); Qmodel.multiply(target); Vb.applyQuaternion(target); } if ( rad_Yaw > 0.0 ) { target.setFromAxisAngle( Y_axis, ( Math.PI / 180 ) * 1 ); Qmodel.multiply(target); Vb.applyQuaternion(target); } else if ( rad_Yaw < 0.0 ) { target.setFromAxisAngle( Y_axis, ( Math.PI / 180 ) * -1 ); Qmodel.multiply(target); Vb.applyQuaternion(target); } else if ( rad_Yaw == 0.0 ) { target.setFromAxisAngle( Y_axis, ( Math.PI / 180 ) * 0 ); Qmodel.multiply(target); Vb.applyQuaternion(target); }

// Q2dcm
var q00,q11,q22,q33;
var q01,q02,q03;
var q12,q23,q31;
var m11,m12,m13;
var m21,m22,m23;
var m31,m32,m33;

q00 = Qmodel.w * Qmodel.w; q11 = Qmodel.x * Qmodel.x; q22 = Qmodel.y * Qmodel.y; q33 = Qmodel.z * Qmodel.z; q01 = Qmodel.w * Qmodel.x; q02 = Qmodel.w * Qmodel.y; q03 = Qmodel.w * Qmodel.z; q12 = Qmodel.x * Qmodel.y; q23 = Qmodel.y * Qmodel.z; q31 = Qmodel.z * Qmodel.x; m11 = q00 + q11 - q22 - q33; m21 = 2.0 * ( q12 - q03 ); m31 = 2.0 * ( q31 + q02 ); m12 = 2.0 * ( q12 + q03 ); m22 = q00 - q11 + q22 - q33; m32 = 2.0 * ( q23 - q01 ); m13 = 2.0 * ( q31 - q02 ); m23 = 2.0 * ( q23 + q01 ); m33 = q00 - q11 - q22 + q33;

// Dcm2vec
Euler.x = Math.atan( m32 / m33 );
Euler.y = -Math.asin( m31 );
Euler.z = Math.atan( m21 / m11 );
Edeg.x = -(( Euler.x ) * 180.0 / Math.PI );
Edeg.y = (( Euler.y ) * 180.0 / Math.PI );
Edeg.z = (( Euler.z ) * 180.0 / Math.PI );

// Rate Check
Rate.x = Edeg.x - Edeg_1.x;
Rate.y = Edeg.y - Edeg_1.y;
Rate.z = Edeg.z - Edeg_1.z;

if (( Rate.y < 0.0 )&&( Edeg.y > 0.0 )) { Edeg.y = 180 - Edeg.y; P.y -= (V.z * Vb.y); axis_v.position.y -= (V.z * Vb.y); } else if (( Rate.y > 0.0 )&&( Edeg.y < 0.0)) { Edeg.y = -180 - Edeg.y; P.y -= (V.z * Vb.y); axis_v.position.y -= (V.z * Vb.y); } else { P.y += (V.z * Vb.y); axis_v.position.y += (V.z * Vb.y); } Edeg_1.x = Edeg.x; Edeg_1.y = Edeg.y; Edeg_1.z = Edeg.z; P.x += (V.z * Vb.x); P.z += (V.z * Vb.z); }

###試したこと
オイラー角を条件に符号が不連続になるところで、速度ベクトルの符号を変更しようとした。
これにより、ヨーはプラスマイナス180度表示となり、ヨー運動は正しくできたが、
ピッチ、ロールが入ると運動がおかしくなる。

###補足情報(言語/FW/ツール等のバージョンなど)
Three.jp r77

bochan2👍を押しています

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

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

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

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

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

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

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

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

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問