質問: new Vector3(rot.x, rot.y, rot.z) * 100f; // 機体にトルクを加える // rigidbody.AddTorque(rotationTorque); rigidbody.AddTorque(rotationTorque + restoringTorque); } ```
回答: 順番が前後しますが... **質問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.right`、`Vector3.up`、`Vector3.forward`をそれぞれR、U、Fとし、`transform.right`、`transform.up`、`transform.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)`です。 ``` Quaternion rot = Quaternion.Inverse(transform.rotation); if (rot.w < 0f) { rot.x = -rot.x; rot.y = -rot.y; rot.z = -rot.z; rot.w = -rot.w; } Vector3 restoringTorque = new Vector3(rot.x, rot.y, rot.z) * restoringTorqueMagnitude; // 機体にトルクを加える rigidbody.AddTorque(rotationTorque + restoringTorque); ``` 補足しますと、この方式に書き換えると復元トルクの大きさが小さめに(バネがやわらかく)なりますので、それに応じて`restoringTorqueMagnitude`をもっと大きくしてやるのがいいかと思います。