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

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

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

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

Q&A

解決済

1回答

960閲覧

Unity(3D)での、物理演算と相性のいいオブジェクト回転方法

unity_beginner_

総合スコア14

Unity

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

0グッド

0クリップ

投稿2022/06/23 08:36

オブジェクトA(this)をオブジェクトB(target)と同じ角度になるように回転させる方法を模索しています。
具体的な条件は以下の通りです。

・指定したオブジェクトBと同じ角度になるようにオブジェクトAを回転させる
・オブジェクトAは滑らかに回転する(a.transform.rotation=b.transform.rotation とはしない)
・回転する途中、回転した後において、物理演算の影響(この表現であっているのかわかりませんが)を受ける。
そのため、回転中に壁などに引っかかった場合回転は止まる(もしくは回転の動きが変化する)

何通りかのスクリプトを書いてみましたが、全て回転がおかしくなりました。
調べてみた所、クォータニオンをオイラー角に変換している所が問題なようです。

クォータニオン型で角速度を与える方法、また他にも何か良い方法がございましたら、教えていただけると幸いです。

1例

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5//回転させるオブジェクト(A)にくっつける 6public class f_quaternion_rotate : MonoBehaviour 7{ 8 public GameObject follow_target; 9 public float sokudo; 10 11 public bool rotate_velo; //trueに設定 12 13 // Start is called before the first frame update 14 void Start() 15 { 16 17 } 18 19 // Update is called once per frame 20 void Update() 21 { 22 Vector3 angle_velo; 23 Quaternion angle; 24 25 Quaternion this_Quat = this.transform.rotation; ///aにあたる 26 Quaternion target_Quat = follow_target.transform.rotation; //bにあたる 27 28 //thisは逆数にする 29 this_Quat = Quaternion.Inverse(this_Quat); 30 31 angle = Get_OuterProduct(this_Quat, target_Quat); 32 33 angle_velo = angle.eulerAngles; 34 { 35 if (angle_velo.x > 180) 36 angle_velo.x -= 360; 37 if (angle_velo.y > 180) 38 angle_velo.y -= 360; 39 if (angle_velo.z > 180) 40 angle_velo.z -= 360; 41 } 42 43 if(rotate_velo==true) 44 { 45 angle_velo = angle_velo / 180 * Mathf.PI; 46 this.GetComponent<Rigidbody>().angularVelocity = angle_velo * 20f * sokudo * Time.deltaTime; 47 } 48 else 49 { 50 this.transform.Rotate(angle_velo); 51 } 52 53 Debug.Log("target: " + follow_target.transform.rotation + "\nthis: " + this.transform.rotation + 54 "\nangle_velo: " + angle_velo); 55 } 56 57 58 Quaternion Get_OuterProduct(Quaternion a, Quaternion b) //クォータニオン型でabの外積を返す 59 { 60 Quaternion c; 61 62 c.x = (a.w * b.x) + (a.x * b.w) + (a.y * b.z) - (a.z * b.y); 63 c.y = (a.w * b.y) + (a.y * b.w) - (a.x * b.z) + (a.z * b.x); 64 c.z = (a.w * b.z) + (a.z * b.w) + (a.x * b.y) - (a.y * b.x); 65 c.w = (a.w * b.w) - (a.x * b.x) - (a.y * b.y) - (a.z * b.z); 66 67 return c; 68 } 69} 70

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

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

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

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

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

bboydaisuke

2022/06/23 12:59

Transform を回す = 物理挙動ではない、です。Transform を動かすのが物理挙動でないのと同じです。 物理挙動として回すには Rigidbody を使って Torque を操作します。
guest

回答1

0

ベストアンサー

たぶんこんな感じじゃないかな...と思って下記のように変更してみましたが、いかがでしょうかね?

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5//回転させるオブジェクト(A)にくっつける 6public class f_quaternion_rotate : MonoBehaviour 7{ 8 public GameObject follow_target; 9 public float sokudo; 10 11 public bool rotate_velo; //trueに設定 12 13 // Start is called before the first frame update 14 void Start() 15 { 16 17 } 18 19 // Update is called once per frame 20 void Update() 21 { 22 Vector3 angle_velo; 23 Quaternion angle; 24 25 Quaternion this_Quat = this.transform.rotation; ///aにあたる 26 Quaternion target_Quat = follow_target.transform.rotation; //bにあたる 27 28 //thisは逆数にする 29 this_Quat = Quaternion.Inverse(this_Quat); 30 31 // この「外積」とおっしゃるのはハミルトン積 32 // ( https://ja.wikipedia.org/wiki/%E5%9B%9B%E5%85%83%E6%95%B0#%E3%83%8F%E3%83%9F%E3%83%AB%E3%83%88%E3%83%B3%E7%A9%8D ) 33 // と同等のものと考えていいでしょうか? 34 // でしたら、わざわざメソッドを作らなくても... 35 // angle = Get_OuterProduct(this_Quat, target_Quat); 36 37 // これでいいんじゃないかと思います 38 angle = this_Quat * target_Quat; 39 40 angle_velo = angle.eulerAngles; 41 { 42 if (angle_velo.x > 180) 43 angle_velo.x -= 360; 44 if (angle_velo.y > 180) 45 angle_velo.y -= 360; 46 if (angle_velo.z > 180) 47 angle_velo.z -= 360; 48 } 49 50 if(rotate_velo==true) 51 { 52 // そしてangularVelocityで回転させたい場合、まず 53 // 自分自身の姿勢から相手の姿勢への相対回転を求めて... 54 // (this_Quatはすでに逆回転になっていることを前提としています) 55 Quaternion relativeRotation = target_Quat * this_Quat; 56 57 // 軸と回転量はこうなりますので... 58 // (ToAngleAxisを使ってもいいかと思います) 59 Vector3 relativeRotationAxis = new Vector3(relativeRotation.x, relativeRotation.y, relativeRotation.z).normalized; 60 float relativeRotationAngle = Mathf.Acos(Mathf.Clamp(relativeRotation.w, -1.0f, 1.0f)) * 2.0f; 61 62 // 角速度はこうなるんじゃないでしょうか 63 // なお、よっぽど特殊なケース(予期しないタイミングでRigidbodyが付け外しされる可能性がある...とか?)でなければ 64 // 今回のコードのようにRigidbodyを毎フレームGetComponentで取得しなくても、たとえばStartで一度だけ取得して 65 // キャッシュしておけば、いくらか効率化できるかと思います 66 this.GetComponent<Rigidbody>().angularVelocity = relativeRotationAxis * (sokudo * relativeRotationAngle); 67 } 68 else 69 { 70 this.transform.Rotate(angle_velo); 71 } 72 73 Debug.Log("target: " + follow_target.transform.rotation + "\nthis: " + this.transform.rotation + 74 "\nangle_velo: " + angle_velo); 75 } 76 77 78 Quaternion Get_OuterProduct(Quaternion a, Quaternion b) //クォータニオン型でabの外積を返す 79 { 80 Quaternion c; 81 82 c.x = (a.w * b.x) + (a.x * b.w) + (a.y * b.z) - (a.z * b.y); 83 c.y = (a.w * b.y) + (a.y * b.w) - (a.x * b.z) + (a.z * b.x); 84 c.z = (a.w * b.z) + (a.z * b.w) + (a.x * b.y) - (a.y * b.x); 85 c.w = (a.w * b.w) - (a.x * b.x) - (a.y * b.y) - (a.z * b.z); 86 87 return c; 88 } 89}

図1

おっしゃる通り、角速度の設定で回転させるのであれば障害物に引っかかることができるかと思います。

図2

投稿2022/06/23 13:39

編集2022/06/23 21:57
Bongo

総合スコア10807

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

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

unity_beginner_

2022/06/26 03:16

ありがとうございます。 追従して回転するオブジェクトの回転速度を調整し、他オブジェクトにめり込むこともなくなりました。 丁寧な解説までしていただき、ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問