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

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

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

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

Unity3D

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

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

3DCG

コンピュータの演算により、3次元空間の仮想物体を、2次元平面上で表現する手法である。

Q&A

解決済

1回答

6712閲覧

【Unity】異なる座標系での回転情報の変換について教えてください

super_hogehoge

総合スコア29

C#

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

Unity3D

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

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

3DCG

コンピュータの演算により、3次元空間の仮想物体を、2次元平面上で表現する手法である。

0グッド

0クリップ

投稿2018/08/24 19:50

前提・実現したいこと

いつも勉強させていただいております。Unity(というよりは3次元空間を扱う全般)での操作で分からない
点がありましたので質問させて下さい。

異なるローカル座標系A,Bがあり、グローバル座標が同じオブジェクトP, QがそれぞれA,Bの子供になっています。
Aのローカル座標系で回転Xを掛けてPを移動した場所に、Bのローカル座標系で回転Yを掛けてQを移動したいと
考えています。最終的にグローバル座標系でPとQが同一の場所にある結果が得たいです。

回転Yをどうやって求めればよいか教えてください。

具体的な例

・新規のシーン
・EmptyObject A をグローバル座標系に作成 globalrotation(localも) は (12,34,56)
・EmptyObject B をグローバル座標系に作成 globalrotation(localも) は (78,90,12)
・EmptyObject P,Qをグローバル座標系に作成 globalposition(localも) は (3.4, 5.6, 7.8)
・Hierarchy上でPをAの子供に、QをBの子供に移動

※各座標は適当です。

該当のソースコード

上記のような状況で、

C#

1 2Transform P = GameOjbect.Find("P").GetComponent<Transform>(); 3Transform Q = GameOjbect.Find("Q").GetComponent<Transform>(); 4 5P.localPosition = Quaternion.Euler(12,34,56) * P.localPosition; 6Q.localPosition = ?????????????????????????? * Q.localPosition; 7 8#結果的に 9P.Position == Q.Position でグローバルでの座標値を一致させたい 10 11この場合上記の?????????????はどうやって求めれば良いのでしょうか。 12

試したこと

Quaternion.Inverse等を用いて色々と試したのですが、数学的な知識が浅く経験値も無いため
望んだ答えがでませんでした。

・こういった問題を解決する際の考慮しなければいけない点
・気をつけなければいけない点

等もありましたらご教授いただければ幸いです。

補足情報(FW/ツールのバージョンなど)

Unity2018.2
C#

宜しくお願い致します。

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

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

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

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

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

guest

回答1

0

ベストアンサー

こんな感じでどうでしょう。

C#

1using UnityEngine; 2 3public class PQRotator : MonoBehaviour 4{ 5 private void Start() 6 { 7 Transform P = GameObject.Find("P").GetComponent<Transform>(); 8 Transform Q = GameObject.Find("Q").GetComponent<Transform>(); 9 10 Transform A = GameObject.Find("A").GetComponent<Transform>(); 11 Transform B = GameObject.Find("B").GetComponent<Transform>(); 12 13 A.position = Vector3.zero; 14 A.localScale = Vector3.one; 15 A.eulerAngles = new Vector3(12, 34, 56); 16 17 // 初期状態でのP、Qのグローバル座標 18 Vector3 OG = new Vector3(3.4f, 5.6f, 7.8f); 19 20 P.SetParent(A); 21 P.position = OG; 22 23 B.position = Vector3.zero; 24 B.localScale = Vector3.one; 25 B.eulerAngles = new Vector3(78, 90, 12); 26 27 Q.SetParent(B); 28 Q.position = OG; 29 30 // 多少の計算誤差には目をつぶるとして、下記4つの座標はすべてOG...(3.4, 5.6, 7.8)を示すはず 31 Debug.LogFormat("Pワールド座標 : {0}", P.position.ToString("F6")); 32 Debug.LogFormat("A回転 * Pローカル座標 : {0}", (A.rotation * P.localPosition).ToString("F6")); 33 Debug.LogFormat("Qワールド座標 : {0}", Q.position.ToString("F6")); 34 Debug.LogFormat("B回転 * Qローカル座標 : {0}", (B.rotation * Q.localPosition).ToString("F6")); 35 36 // 以下、コメント中の「==」は計算誤差を許容して一致することを意味するものと見なしてください 37 38 // P.position == A.rotation * P.localPosition であるので、両辺に左側からAの逆回転をかけると 39 // Quaternion.Inverse(A.rotation) * P.Position == Quaternion.Inverse(A.rotation) * A.rotation * P.localPosition となり 40 // 右辺の順回転・逆回転は打ち消し合ってQuaternion.identityとなるため 41 // Quaternion.Inverse(A.rotation) * P.position == P.localPosition となる 42 // つまり、P.localPosition == Quaternion.Inverse(A.rotation) * OG である...① 43 44 // また、同じくQについても Quaternion.Inverse(B.rotation) * Q.position == Q.localPosition となる 45 // つまり、Q.localPosition == Quaternion.Inverse(B.rotation) * OG である...② 46 47 // Pのローカル座標に適用したい回転 48 Quaternion RP = Quaternion.Euler(12, 34, 56); 49 50 // Pの新しいローカル座標 51 Vector3 NewPL = RP * P.localPosition; 52 53 // Pの新しいグローバル座標 54 Vector3 NewPG = A.rotation * NewPL; 55 56 // Qのローカル座標に適用するべき回転をRQ、回転を適用して得られた新しいローカル座標をNewQL、 57 // 新しいグローバル座標をNewQGとすると、NewQG == NewPG であって欲しいので 58 // NewQG == B.rotation * NewQL == NewPG == A.rotation * NewPL という関係となる 59 // NewPL = RP * P.localPosition 、NewQL == RQ * Q.localPosition であるので、これを上式に代入し 60 // B.rotation * RQ * Q.localPosition == A.rotation * RP * P.localPosition となる 61 62 // ここで、両辺に左側からBの逆回転をかけて左辺のB.rotationを消すと 63 // RQ * Q.localPosition == Quaternion.Inverse(B.rotation) * A.rotation * RP * P.localPosition 64 // さらに上式に、先ほど示した①、②を代入すると 65 // RQ * Quaternion.Inverse(B.rotation) * OG == Quaternion.Inverse(B.rotation) * A.rotation * RP * Quaternion.Inverse(A.rotation) * OG 66 // 次に、両辺に右側からBの順回転をかけて左辺のQuaternion.Inverse(B.rotation)を消すと 67 // RQ * OG == Quaternion.Inverse(B.rotation) * A.rotation * RP * Quaternion.Inverse(A.rotation) * B.rotation * OG 68 69 // これで両辺のVector3因子はどちらもOGになったので消すことができ 70 // RQ == Quaternion.Inverse(B.rotation) * A.rotation * RP * Quaternion.Inverse(A.rotation) * B.rotation となる...③ 71 72 // ところで、上式の Quaternion.Inverse(B.rotation) * A.rotation と Quaternion.Inverse(A.rotation) * B.rotation は 73 // 2つの回転がそれぞれ逆回転になり、さらに回転順序が逆になったものなので、お互いに逆回転の関係にある 74 75 // そこで、B逆回転とA順回転を組み合わせた回転をRBiAとすると 76 Quaternion RBiA = Quaternion.Inverse(B.rotation) * A.rotation; 77 78 // A逆回転とB順回転を組み合わせた回転は、RBiAの逆回転...Quaternion.Inverse(RBiA) である 79 80 // これらを③に代入すれば式がすっきりし 81 Quaternion RQ = RBiA * RP * Quaternion.Inverse(RBiA); 82 83 // よって、Qの新しいローカル座標は 84 Vector3 NewQL = RQ * Q.localPosition; 85 86 // 求めた回転を適用して、結果を確認してみる 87 88 Debug.Log("----------------"); 89 90 Debug.LogFormat("古いPローカル座標 : {0}", P.localPosition.ToString("F6")); 91 Debug.LogFormat("古いPグローバル座標 : {0}", P.position.ToString("F6")); 92 93 Debug.LogFormat("Pローカル座標に適用する回転 : {0}", RP.eulerAngles.ToString("F6")); 94 95 P.localPosition = RP * P.localPosition; 96 97 Debug.LogFormat("新しいPローカル座標 : {0}", P.localPosition.ToString("F6")); 98 Debug.LogFormat("新しいPグローバル座標 : {0}", P.position.ToString("F6")); 99 100 Debug.Log("----------------"); 101 102 Debug.LogFormat("古いQローカル座標 : {0}", Q.localPosition.ToString("F6")); 103 Debug.LogFormat("古いQグローバル座標 : {0}", Q.position.ToString("F6")); 104 105 Debug.LogFormat("Qローカル座標に適用する回転 : {0}", RQ.eulerAngles.ToString("F6")); 106 107 Q.localPosition = RQ * Q.localPosition; 108 109 Debug.LogFormat("新しいQローカル座標 : {0}", Q.localPosition.ToString("F6")); 110 Debug.LogFormat("新しいQグローバル座標 : {0}", Q.position.ToString("F6")); 111 } 112}

うまくいきましたでしょうか?ちょっと誤差はでるものの、おおむね一致するかと思います。数学の問題みたいで面白いですね。

コンソール

注意するべき点としては、クォータニオン型の因子は掛ける順序が非可換なので、方程式を変形していく際にクォータニオンを両辺に掛ける時は、左辺が右からなら右辺も右から、左からなら左から...となるようにすることでしょうか。

投稿2018/08/24 23:36

Bongo

総合スコア10807

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

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

super_hogehoge

2018/08/28 06:07

ありがとうございます! 丁寧に考える過程を記述して下さり、非常に助かります。 丁寧に知っている情報を組み合わせて導出するのですね・・・非常に勉強になりました。 >>2つの回転がそれぞれ逆回転になり、さらに回転順序が逆になったものなので、お互いに逆回転の関係にある 知りませんでした・・・なるほど。 疑問が解消しましたのでBongo様をベストアンサーとさせていただきます。 返答が遅れ、申し訳ありませんでした。 ありがとうございました、非常に助かりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問