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

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

新規登録して質問してみよう
ただいま回答率
85.31%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Q&A

解決済

1回答

2986閲覧

一定の軸から見た角度差のみを算出したいです

maniaiidx

総合スコア12

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

0グッド

0クリップ

投稿2018/09/08 04:51

お世話になっております。

Quaternion回転処理についての質問です。

時点Aから時点B間で自由回転したTransformの角度差(Angle)を取り出したいのですが、
「一定の軸から見た角度差のみ」を算出することは可能でしょうか?

ややこしくて申し訳ないのですが、例えますと、
棒を空中に放った場合、棒は様々な回転をしますが
その回転から「ねじれ(ツイスト)の回転量のみ」を抽出する
というような事がしたいです。

その後、別のtransformにツイスト量だけ
Quaternion.AngleAxisで与える。という目論見なのですが

良い計算方法など御座いましたらご教示お願い致します。

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

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

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

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

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

guest

回答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
Bongo

総合スコア10816

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

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

maniaiidx

2018/09/09 12:33

Bongoさん 詳細な計算方法の解説とご教示、まことにありがとうございます。 大変勉強になりました。 本当にありがとうございます。 教えて頂いたコードを元に、目的の処理や、 リアルタイムでの一定の軸回転のみの抽出、逆算など試行錯誤しつつ、 勉強させて頂きます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.31%

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

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

質問する

関連した質問