お世話になっております。
Quaternion回転処理についての質問です。
時点Aから時点B間で自由回転したTransformの角度差(Angle)を取り出したいのですが、
「一定の軸から見た角度差のみ」を算出することは可能でしょうか?
ややこしくて申し訳ないのですが、例えますと、
棒を空中に放った場合、棒は様々な回転をしますが
その回転から「ねじれ(ツイスト)の回転量のみ」を抽出する
というような事がしたいです。
その後、別のtransformにツイスト量だけ
Quaternion.AngleAxisで与える。という目論見なのですが
良い計算方法など御座いましたらご教示お願い致します。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

回答1件
0
ベストアンサー
ご質問者さんの扱っている物体は実際には棒ではないのでしょうが、以下ではとりあえず棒を回すものとして考えてみました。
棒のモデルがZ軸に頭を向けて横たえる形で作られているとすると、棒の軸はtransform.forward
で得られます。
ここで、
- rab...時点Aから時点Bへの回転
- da...時点Aでの
transform.forward
- db...時点Bでの
transform.forward
- rdadb...daをdbの向きに変える、ねじれのない回転
とすると、rdadbが分かればrabとrdadbの差分からねじれ量が分かるはずです。
rdadbを求めたいのですが、この「ねじれのない回転」というのがどういうものなのか私もちょっとイメージが曖昧ですけれども、ペンをくるくる回しながら考えてみたところ、おそらく「回転軸がdaとdbの外積の向きで、回転量がdaとdbのなす角度である回転」...つまり「daをdbの向きにする最短の回転」なら、先端を目標角に向ける以外のひねりが含まれていない「ねじれのない回転」と見なしていいんじゃないかと思います。
【Unity】 Quaternion API解説 - エフアンダーバーの「FromToRotation」にある図をご覧いただきたいのですが、この図の赤い軌道がFromToRotationで得られる最短の回転、緑や青の軌道がそれよりも長い回転です。
目標方向に到達した時のユニティちゃんの視線は赤・緑・青軌道いずれもX+方向を向いていますが、頭の向きは各軌道でそれぞれ異なっています。
赤軌道の姿勢をねじれのない基準姿勢とし、それに対する緑軌道や青軌道の頭の向きの差を「ねじれ量」とすることができないでしょうか?
下記のようなコードを試してみました。回転可視化には姿勢のわかりやすい形状と考えてユニティちゃんを使い、ねじれ軸として形状を棒に見立てると一番長い軸であるY軸を選びました。
同じユニティちゃんですが、上記ではZ軸をねじれ軸として注目していたのに対し、下記実験ではY軸に注目していますので、頭の向きを目標角に向けた時の正面方向のずれをねじれ量とする形になります。
C#
1using UnityEngine; 2 3public class Twist : MonoBehaviour 4{ 5 /// <summary> 6 /// <paramref name="ra" />から<paramref name="rb" />への回転から、軸<paramref name="axis" />に関するねじれ角を得ます。 7 /// </summary> 8 /// <param name="ra">起点の回転。</param> 9 /// <param name="rb">終点の回転。</param> 10 /// <param name="axis">ねじれ軸。</param> 11 /// <returns>軸<paramref name="axis" />に関する0°以上360°未満のねじれ角。</returns> 12 public static float GetTwistAroundAxis(Quaternion ra, Quaternion rb, Vector3 axis) 13 { 14 // 軸を正規化する 15 if (axis == Vector3.zero) 16 { 17 axis = Vector3.forward; 18 } 19 axis.Normalize(); 20 21 // da、db、rab、rdadbを求める 22 var da = ra * axis; 23 var db = rb * axis; 24 var rab = rb * Quaternion.Inverse(ra); 25 var rdadb = Quaternion.FromToRotation(da, db); 26 27 // rdadbからrabへの回転を求めたのち、その軸と角度を抽出する 28 Vector3 deltaAxis; 29 float deltaAngle; 30 var delta = rab * Quaternion.Inverse(rdadb); 31 delta.ToAngleAxis(out deltaAngle, out deltaAxis); 32 33 // dbとdeltaAxisは同一直線上にあるはずだが、向きは逆かもしれない 34 // 角度の正負を統一するため、向きの逆転の有無を調べる 35 // deltaAngleSignはdbとdeltaAxisの向きが一致していれば1、逆転していれば-1になる 36 var deltaAngleSign = Mathf.Sign(Vector3.Dot(db, deltaAxis)); 37 38 // 角度の符号を補正した上で0°~360°におさめて返す 39 var result = (deltaAngleSign * deltaAngle) % 360.0f; 40 if (result < 0.0f) 41 { 42 result += 360.0f; 43 } 44 return result; 45 } 46 47 [SerializeField] private Transform fromFigure; 48 [SerializeField] private Transform toFigure; 49 [SerializeField] private Transform toWithoutTwistFigure; 50 51 private void Start() 52 { 53 // 動作を実験 54 var fromRotation = Quaternion.Euler(0.0f, -10f, -100.0f); 55 var toRotation = Quaternion.Euler(10.0f, 60.0f, -60.0f); 56 57 // ねじれを調べる軸を決定する 58 // Z軸に向けて横たえた棒ならVector3.forward、地面に垂直に立てた棒ならVector3.upが適当と思われる 59 // 今回は姿勢確認にユニティちゃんを使ったので、足元から頭へ向かう軸であるVector3.upを選択した 60 // 調べる軸は必ずしも軸平行である必要はなく、Vector3.oneのような斜めの軸についても調べることができる 61 var axis = Vector3.up; 62 63 // axisに関するねじれを調べる 64 var twist = GetTwistAroundAxis(fromRotation, toRotation, axis); 65 Debug.LogFormat("Twist around {0}: {1}", axis.ToString("F6"), twist); 66 67 // fromRotationの向きからtoRotationの向きへ最短で回転した場合、この姿勢になるはず 68 var toRotationWithoutTwist = Quaternion.FromToRotation(fromRotation * axis, toRotation * axis) * fromRotation; 69 70 // 回転結果を可視化する 71 72 // モデルにfromRotation、toRotation、toRotationWithoutTwistの姿勢をとらせる 73 this.fromFigure.rotation = fromRotation; 74 this.toFigure.rotation = toRotation; 75 this.toWithoutTwistFigure.rotation = toRotationWithoutTwist; 76 77 // 各方向に線を描く 78 var origin = this.transform.position; 79 const float rayLength = 2.0f; 80 // ねじれを調べる軸...白色 81 Debug.DrawRay( 82 origin, 83 toRotation * axis.normalized * rayLength, 84 Color.white, 85 float.PositiveInfinity); 86 // ねじれなし回転の場合のXYZ軸...暗めの薄い赤・緑・青色 87 Debug.DrawRay( 88 origin, 89 toRotationWithoutTwist * Vector3.right * rayLength, 90 new Color(0.5f, 0.0f, 0.0f, 0.5f), 91 float.PositiveInfinity); 92 Debug.DrawRay( 93 origin, 94 toRotationWithoutTwist * Vector3.up * rayLength, 95 new Color(0.0f, 0.5f, 0.0f, 0.5f), 96 float.PositiveInfinity); 97 Debug.DrawRay( 98 origin, 99 toRotationWithoutTwist * Vector3.forward * rayLength, 100 new Color(0.0f, 0.0f, 0.5f, 0.5f), 101 float.PositiveInfinity); 102 // ねじれあり回転の場合のXYZ軸...鮮やかな赤・緑・青色 103 Debug.DrawRay( 104 origin, 105 toRotation * Vector3.right * rayLength, 106 Color.red, 107 float.PositiveInfinity); 108 Debug.DrawRay( 109 origin, 110 toRotation * Vector3.up * rayLength, 111 Color.green, 112 float.PositiveInfinity); 113 Debug.DrawRay( 114 origin, 115 toRotation * Vector3.forward * rayLength, 116 Color.blue, 117 float.PositiveInfinity); 118 } 119}
水色のユニティちゃんが時点Aの姿勢、ピンク色が時点Bの姿勢を想定したものです。一方、黄色は水色ユニティちゃんの頭をまっすぐ最短で目標角度に向けた場合の姿勢で、この黄色姿勢をねじれのない姿勢と考えると、ピンク姿勢は黄色姿勢に対してY軸周りに約+24.4°のねじれがある...という結果になりました。
投稿2018/09/09 06:44
編集2018/09/09 07:26総合スコア10816
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/09/09 12:33