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

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

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

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

Q&A

解決済

1回答

1901閲覧

ベクトルやAddTorqueに関して。

退会済みユーザー

退会済みユーザー

総合スコア0

Unity

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

0グッド

0クリップ

投稿2019/07/20 17:25

編集2019/07/21 14:29

前提・実現したいこと

前回の質問に引き続き、後半部分の質問です。

該当のソースコード

C#

1 void FixedUpdate() 2 { 3 float x = Input.GetAxis("Horizontal"); 4 float y = Input.GetAxis("Vertical"); 5 6 // xとyにspeedを掛ける 7 rigidbody.AddForce(x * speed, y * speed, 0); 8 9 Vector3 moveVector = Vector3.zero; 10 Debug.Log(moveForceMultiplier * (moveVector - rigidbody.velocity)); 11 12 rigidbody.AddForce(moveForceMultiplier * (moveVector - rigidbody.velocity)); 13 14 /* 後半部分 これ以降の処理に関して質問です。 */ 15 16 // プレイヤーの入力に応じて姿勢をひねろうとするトルク 17 Vector3 rotationTorque = new Vector3(-y * pitchTorqueMagnitude, x * yawTorqueMagnitude, -x * rollTorqueMagnitude); 18 19 // 現在の姿勢のずれに比例した大きさで逆方向にひねろうとするトルク 20 Vector3 right = transform.right; 21 Vector3 up = transform.up; 22 Vector3 forward = transform.forward; 23 Vector3 restoringTorque = new Vector3(forward.y - up.z, right.z - forward.x, up.x - right.y) * restoringTorqueMagnitude; 24 25 // 機体にトルクを加える 26 rigidbody.AddTorque(rotationTorque + restoringTorque); 27 28 }

試したこと

C#

1// プレイヤーの入力に応じて姿勢をひねろうとするトルク 2Vector3 rotationTorque = new Vector3(-y * pitchTorqueMagnitude, x * yawTorqueMagnitude, -x * rollTorqueMagnitude);

上記コードに関しては理解できました。
実際、下記のコードで試したところ、想定通りの動きをしていたので理解できていると思います。

C#

1rigidbody.AddTorque(rotationTorque);

分からないコードは2点です。

・質問1。
下記コードでrotationTorqueの逆回転(?)のベクトルを生成しているみたいですが、
どのような処理になっているかわからないです。
例えば、x成分に入れているのは、「forward.y - up.z」ですが、これはどういった値なのでしょうか?
他、y成分、z成分に関しても同様です。

C#

1Vector3 restoringTorque = new Vector3(forward.y - up.z, right.z - forward.x, up.x - right.y) * restoringTorqueMagnitude;

・質問2。
x, yの値に応じて回転させるrotationTorqueベクトルと、その逆回転のrestoringTorqueを同時に与えると、
相殺して無回転になるようなイメージをしてしまうのですが、
ゲーム実行した挙動からすると、rotationTorqueで回転した後、restoringTorqueで逆回転させるというような処理になっているのでしょうか?
rigidbody.AddTorque(A + B);
とすると、A回転した後、B回転するようになるのでしょうか?

C#

1rigidbody.AddTorque(rotationTorque + restoringTorque);

追記

C#

1 void FixedUpdate() 2 { 3 float x = Input.GetAxis("Horizontal"); 4 float y = Input.GetAxis("Vertical"); 5 6 // xとyにspeedを掛ける 7 rigidbody.AddForce(x * speed, y * speed, 0); 8 9 Vector3 moveVector = Vector3.zero; 10 11 //rigidbody.AddForce(moveForceMultiplier * (moveVector - rigidbody.velocity)); 12 13 // プレイヤーの入力に応じて姿勢をひねろうとするトルク 14 Vector3 rotationTorque = new Vector3(-y * pitchTorqueMagnitude, x * yawTorqueMagnitude, -x * rollTorqueMagnitude); 15 16 Quaternion target_rot = this.transform.rotation; 17 Quaternion rot = target_rot * Quaternion.Inverse(this.transform.rotation); 18 if(rot.w < 0f){ 19 rot.x = -rot.x; 20 rot.y = -rot.y; 21 rot.z = -rot.z; 22 rot.w = -rot.w; 23 } 24 Vector3 restoringTorque = new Vector3(rot.x, rot.y, rot.z) * 100f; 25 // 機体にトルクを加える 26 // rigidbody.AddTorque(rotationTorque); 27 rigidbody.AddTorque(rotationTorque + restoringTorque); 28 29 }

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

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

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

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

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

guest

回答1

0

ベストアンサー

順番が前後しますが...

質問2について
今回の2つのトルクベクトルは互いに逆であるわけではないのです(もし本当に逆ならば、おっしゃる通り2つの和がゼロベクトルになってしまい、機体に回転する力はかからなくなるでしょう)。コメントにあるように、rotationTorqueはプレイヤーの入力の方へねじれを追加しようとするトルク、restoringTorqueは機体の現在のねじれを解消して無回転の姿勢に戻そうとするトルクです。

rigidbody.AddTorque(A + B);は「A回転したあとB回転」という風に順序があるわけではなく、「トルクA(大きさがAの長さ、回転軸がAの向き)とトルクB(大きさがBの長さ、回転軸がBの向き)を同時にかける」とでも言うべきでしょうかね...?ですのでrigidbody.AddTorque(B + A);でも結果は同じになるはずです。この辺は普段よくやる「Transformの姿勢をQuaternionで回転」とかとはまた違った感覚でしょうから、いろいろいじってみて慣れていただくのがいいでしょうかね。

回転関連の理屈や物理量については、力学の解説書に載っているようなことが使えるはずです。EMANの物理学・力学・回転に関する物理量とか(「力のモーメント」がトルクに相当します)、EMANの物理学・力学・慣性モーメントテンソルといった記事もご参考になるかと思います。

質問1について
簡略化のためにVector3.rightVector3.upVector3.forwardをそれぞれR、U、Fとし、transform.righttransform.uptransform.forwardをそれぞれr、u、fとし、Vector3.Cross(lhs, rhs)をC(lhs, rhs)と書くことにします。

あの復元トルクの式は、rをRの向きに、uをUの向きに、fをFの向きにねじってやれば元の姿勢に戻るだろう...と思ってやってみたものです。
rをRの向きにねじるトルクの軸はrとRの外積の向きにするのがいいでしょう。大きさはどうするべきかですが、どうやらrとRがなす角度に比例させるとフックの法則に従ったバネらしい挙動になるらしいですね。ですが今回は元の姿勢に戻す作用が得られれば十分かと思い、外積の大きさ(rとRがなす角度のサイン、あるいはrとRが作る平行四辺形の符号付き面積といってもいいでしょう)をそのまま利用することにしました。姿勢のずれはさほど大きくはないでしょうから、こんなやり方でもバネっぽく見せられると思います。
uからU、fからFも同様にして、3つのベクトルを足すと

C(r, R) + C(u, U) + C(f, F)

となり、展開すると

(r.y * R.z - r.z * R.y, r.z * R.x - r.x * R.z, r.x * R.y - r.y * R.x) + (u.y * U.z - u.z * U.y, u.z * U.x - u.x * U.z, u.x * U.y - u.y * U.x) + (f.y * F.z - f.z * F.y, f.z * F.x - f.x * F.z, f.x * F.y - f.y * F.x)

となり、R == (1, 0, 0)U == (0, 1, 0)F == (0, 0, 1)なので大幅に簡略化され

(0, r.z, -r.y) + (-u.z, 0, u.x) + (f.y, -f.x, 0)

となって、各成分を足して一つにすると

(f.y - u.z, r.z - f.x, u.x - r.y)

の形が出てきます。これにrestoringTorqueMagnitudeをかけて大きさを調整したものを使いました。

余談
あの姿勢復元コードの投稿後に検索してみたのですが、【Unite Tokyo 2018】誘導ミサイル完全マスターの講演で紹介されている「現在の姿勢から目標の姿勢への回転を表すQuaternionを得て、そのxyz成分に比例したトルクを加える」という案の方がエレガントでよさそうですね。xyz成分の向きはまさしく回転軸の方を向いていますし、大きさは「角度差÷2」のサインに比例しています。トルクの大きさが角度差0°~180°まで単調増加するので、より一層バネっぽくなりそうです。またQuaternionの計算にUnityの提供する各種メソッドがそのまま利用できるため、コードも簡潔になってわかりやすいでしょう。【Unite 2017 Tokyo】スマートフォンでどこまでできる?3Dゲームをぐりぐり動かすテクニック講座では実演しながら解説されており、非常にご参考になるかと思います。

追記
現状だと機体の現在の回転とそれの逆回転をかけてしまっており、得られるクォータニオンが無回転になっているようです。
後ほどじっくり講演を見直していただきたいのですが、トルク源として用いるべき回転は「現在の姿勢から目標の姿勢への相対回転」となります。現在の姿勢はtransform.rotation、目標姿勢はQuaternion.identityです。ですので、講演の式に当てはめるとQuaternion.identity * Quaternion.Inverse(transform.rotation)ということになりますね。
もっと単純に言うと、無回転からtransform.rotationだけ回転すれば現在の姿勢になるのですから、現在の姿勢から無回転に戻す回転はそれの逆回転...Quaternion.Inverse(transform.rotation)です。

C#

1 Quaternion rot = Quaternion.Inverse(transform.rotation); 2 if (rot.w < 0f) { 3 rot.x = -rot.x; 4 rot.y = -rot.y; 5 rot.z = -rot.z; 6 rot.w = -rot.w; 7 } 8 Vector3 restoringTorque = new Vector3(rot.x, rot.y, rot.z) * restoringTorqueMagnitude; 9 10 // 機体にトルクを加える 11 rigidbody.AddTorque(rotationTorque + restoringTorque);

補足しますと、この方式に書き換えると復元トルクの大きさが小さめに(バネがやわらかく)なりますので、それに応じてrestoringTorqueMagnitudeをもっと大きくしてやるのがいいかと思います。

投稿2019/07/21 02:37

編集2019/07/21 15:45
Bongo

総合スコア10807

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

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

退会済みユーザー

退会済みユーザー

2019/07/21 14:48

ご回答ありがとうございます。 質問2に関しては、いろいろ試行錯誤して理解を深めたいと思います。 質問1の式変形のご提示ありがとうございます。 流れが理解できました。 余談のご提示のリンクの方法(Unity提供メソッドを使う方法)を実装してみたいと思い、 質問の追記のように試してみたのですが、上手くいかず(this.transform.rotationを書いている辺りがおかしいという予想はつくのですが)、ご提示の動画のような書き方の実装方法を教えていただけませんか?
Bongo

2019/07/21 15:46

回転計算部分の修正案を追記しました。あんな感じでいかがでしょうか?
退会済みユーザー

退会済みユーザー

2019/07/22 16:30 編集

ご回答ありがとうございます。 なるほど、目標姿勢が現在の回転(回転中の回転)になっていたことが原因だったのですね。 すみません、さらに3点質問です。 1点目。 public float restoringTorqueMagnitude = 100000000000000.0f; とかなり大きな値まで試したのですが、かなりバネの反発力が弱い挙動に見えるのですが、 そういった挙動で合っていますか? (ご教示いただいた通りのコードを試しているつもりですが、もしかしたら、自分のコードがどこかで間違っているかもしれないので) 質問2。 Quaternion.identityが無回転なので、 下記3つのコードは同等ですか? //Aはクォータニオン。 Quaternion.identity * A //1つめのコード。 A * Quaternion.identity //2つめのコード。 A //3つめのコード。 (これはもしかしたら、以前別質問のときに質問させていただいたことかもしれませんが、メモに書いてなかったので、再質問してしまっているかもしれませんが、すみません。今度は必ずメモに残しておきます。) 質問3。 これも当然かもしれない質問で申し訳ないですが、 「Quaternion.identityは、インスペクタのTransformのRotationで、[X:0, Y:0, Z:0]の状態である」ということで合っていますか?
Bongo

2019/07/22 19:43

1点目については、さすがにそれは妙ですね。そのスクリプトをアタッチしたオブジェクトのインスペクター上の入力欄にも、本当にそのような巨大な値が表示されている状態でしょうか?restoringTorqueMagnitudeはシリアライズ対象になっているはずなので、もしかしてシーンファイルに保存された古い値が残っているだけなのではないかと疑われるのですが... 2点目についてはおっしゃる通りで、Quaternion.identityを右からかけても左からかけても値はAのまま維持されます。 3点目も正しいかと思います。まあ念のため申し上げますと、今回のコードではワールド回転を(0, 0, 0)に戻そうとしているのに対し、インスペクター上に(0, 0, 0)を入力するとローカル回転が無回転になるという違いはありますが( https://docs.unity3d.com/ja/current/ScriptReference/Transform-localRotation.html に例示されている最初のコードでは、transform.localRotationにQuaternion.identityをセットすることでローカル回転を無回転に戻しています)...
退会済みユーザー

退会済みユーザー

2019/07/23 14:07

ご回答ありがとうございます。 質問1点目ですが、おっしゃる通り、インスペクタに反映されていませんでした。インスペクタで値を調整したら反動が変わりました。 シリアライズのフィールドは、コードで値を変更しても、インスペクタの方に反映されず、実際は値が変更されないのですね。勉強になりました。 質問2点目と3点目、ありがとうございます。 transform.localRotationにセットすることでインスペクタに反映されることを忘れていました。 理解できました。 とても勉強になりました。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問