これは Unity 2022 で「Look At」スクリプトを作成し、あるオブジェクトを別のオブジェクトの方向に向けるための2つのチュートリアルのうちの2つ目になります。
このチュートリアルの動画版は、現在この言語では利用できません。
動画の書き起こし
こんにちは皆さん。
これは Unity 2022 で「Look At」スクリプトを作成し、あるオブジェクトを別のオブジェクトの方向に向けるための2つのチュートリアルのうちの2つ目になります。
具体的には、前回は問題を分析し、オブジェクトを瞬時に回転させる解決策を実装しました。今回は Quaternions と Slerp を使用して、よりゆっくりと段階的に回転させる方法を作成します。
このチュートリアルでは、Time.deltaTime や Quaternion.Slerp メソッドといった概念についてはすでに理解している前提で進めます。これらについては別のチュートリアルで解説していますので、まだよく分からない場合は、先にそちらを確認することをお勧めします。

前回のチュートリアルでは、カメラのグローバル軸とローカル軸について説明しました。これは、カメラの向きを示す軸を特定するためと、どの軸を中心に回転させるかを明確にするためです。
その後、問題を二次元平面に単純化し、Surveillance Camera の3Dモデルを回転させる角度を計算しました。
スクリプト内では、この角度を deltaAngle と呼び、単位は度です。
Slerp を使用するには、次の3つが必要です。
初期姿勢を示すクォータニオン。
到達すべき目標姿勢を示すクォータニオン。
ゲーム実行中の各フレームにおいて、初期姿勢から最終姿勢への遷移のどの位置にいるかを、0から1の範囲で示す方法。
最初の項目は最も簡単です。transform の rotation プロパティはオブジェクトの姿勢をクォータニオンで表しているため、このフィールドには transform.rotation を使用します。
2つ目もそれほど複雑ではありません。クォータニオンで表された初期姿勢がある場合、そこから回転を適用して得られる目標姿勢のクォータニオンは、初期姿勢と適用する回転の積で求められます。
スクリプトで適用する回転は deltaAngle ですが、これは度で表されています。そのため、Quaternion として表現する必要があります。
幸い、Quaternion クラスの Euler 関数がまさに必要なものです。これは3つのパラメータ、つまり X軸、Y軸、Z軸まわりの回転角を受け取り、その変換を表すクォータニオンを返します。
前述の通り、目標クォータニオンを得るには初期クォータニオンに回転クォータニオンを掛け合わせる必要があります。したがって、Update 内で次のように書きます。
Quaternion targetRotation = (transform.rotation * (Quaternion.Euler(0f, 0f, deltaAngle)));
その直後に、Quaternion.Slerp で計算したクォータニオンを transform.rotation に代入して、オブジェクトの姿勢を更新します。
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, evaluationTime);
ここで evaluationTime を定義する必要があります。これは 0 から 1 の間の float 値で、初期姿勢から最終姿勢への遷移のどの位置にいるかを表します。
まず、この変数をスクリプトクラスの先頭で定義し初期化します。
private float evaluationTime;
そして Start メソッド内で次のように初期化します。
evaluationTime = 0f;

次に、evaluationTime を各フレームごとに増加させる必要があります。これは Slerp を含む命令の直後に次のように書くことで実現できます。
evaluationTime += Time.deltaTime;
もちろん、これはあくまで一例です。Time.deltaTime に変数を掛け合わせ、その値を Inspector でリアルタイムに調整できるようにして、最適な回転速度を見つけることをお勧めします。この点については Time.deltaTime のチュートリアルで説明しています。
ただし、この方法では evaluationTime はリセットされないまま各フレームで増加し続けるため、いずれ 1.0 に到達します。
では、いつリセットすればよいのでしょうか。
別の言い方をすると、いつモデルの新しい回転を開始する準備ができたと言えるのでしょうか。
答えは、モデルがすでに Player の方向を向き、Player が動くのを待っているときです。
通常であれば、Surveillance Camera モデルが Player を向いていて、かつ Player が静止している場合、回転する必要がないため deltaAngle は 0 になると言えます。しかし float 値では、特に異なる単位間の変換がある場合、小さな誤差が生じる可能性があるため、ある程度の許容範囲を設けるほうが安全です。そこで、deltaAngle の絶対値が 1f 未満になったときにアニメーションが終了し、Player が再び動いたときに新しい回転を開始できると定義します。
そのため、Update メソッド内で targetRotation を作成する直前に、次のように書きます。
if(Mathf.Abs(deltaAngle) < 1f) evaluationTime = 0f;
そして、この if 文の else ブロックの中に、次の3つの命令、すなわち目標クォータニオンの定義、Slerp による姿勢変更、evaluationTime の増加を記述します。

修正したスクリプトを保存し、Unity エディターに戻って Play を押し、結果を確認します。この場合、回転速度は Time.deltaTime のみによって決まります。前述の通り、Time.deltaTime に変数を掛け合わせることで、Inspector 上でインタラクティブに調整することも可能です。

まとめると、このチュートリアルでは回転角をクォータニオンに変換して目標姿勢を表す Quaternion を計算する方法を確認しました。そして Slerp を使用して、実行プラットフォームに依存しない形で、Time.deltaTime を用いながら速度調整可能な、よりゆっくりとした回転を実現しました。
さらに、Player が静止して次の移動を待っている状態になったときに回転が再開されるよう、Slerp のリセット条件も定義しました。
これでこの2つのチュートリアルは終了です。また次回お会いしましょう。