これは Unity でオブジェクトを別のオブジェクトの方向に向ける方法についての 2 本のチュートリアルのうちの 1 本目です。具体的には、監視カメラの 3D モデルが Player に自動的に向きを合わせ、シーン内での動きを追従するようにする方法を見ていきます。


このチュートリアルには日本語の音声はありません。以下の動画は英語音声で、日本語・英語・その他の言語の字幕付きでご覧いただけます。動画の下には、日本語に翻訳した書き起こしを掲載しています。


動画の書き起こし

こんにちは皆さん。

これは Unity でオブジェクトを別のオブジェクトの方向に向ける方法についての 2 本のチュートリアルのうちの 1 本目です。具体的には、監視カメラの 3D モデルが Player に自動的に向きを合わせ、シーン内での動きを追従するようにする方法を見ていきます。

このチュートリアルは Unity 2022 を使用して作成されており、2 つのパートに分かれています。

第 1 部では問題を分析し、Rotate メソッドを使用してカメラを瞬時に回転させる方法を扱います。

第 2 部ではクォータニオンと Slerp メソッドを使用して、より滑らかで段階的な回転を作成します。

実装に進む前に、解決すべき問題を分析してみましょう。

カメラはローカルの垂直軸の周りにのみ回転できるため、問題を 2D 平面に単純化できます。この点を分かりやすくするために、シーンを TOP ビュー、Orthogonal モードで表示しています。

監視カメラの 3D モデルと Player は、すべてのゲームオブジェクトと同様に、シーン内の位置を示す XYZ Position 座標を持っています。

position.y 座標には関心がありません。カメラはその LOCAL 軸の周りにのみ回転するため、x と z の位置座標のみを考慮します。つまり、両オブジェクトが同じ平面上にあり、y 座標が同じ値であると仮定します。

さらに、このケースでは監視カメラを基準座標系の原点、つまりデカルト平面での 0,0 の点と見なすことができます。

それだけでなく、この場合は負の LOCAL Y 軸に対応するカメラの向いている方向を、デカルト座標の軸の 1 つと見なすこともできます。

次に、仮想カメラと Player のシーン内の位置を結ぶ方向を特定できます。これは単なるベクトルであり、ここでも 2 次元、つまり GLOBAL X と Z のみを考慮します。

したがって、監視カメラに適用したい回転は、アセットの向き、つまり負のローカル Y 軸と、監視カメラから Player を結ぶ理想的なベクトルとの間の角度で与えられます。この角度を求めれば、ローカル垂直軸の周りに 3D モデルへ適用すべき回転量が分かります。

幸運なことに、2 引数アークタンジェントと呼ばれる数学関数があり、Mathf の Atan2 メソッドとして実装されています。この関数は、2 点の座標差で与えられる方向ベクトルをパラメータとして受け取り、まさにこの角度を計算します。

具体的には、Atan2 はデカルト平面の X 軸と、原点からターゲットへ向かう方向ベクトルとの間の角度を求めます。

このケースでは、原点は監視カメラの 3D モデルの X と Z 座標です。したがって、ターゲット座標 x, y は監視カメラと Player の座標差で与えられ、X 軸は監視カメラの負の LOCAL Y 軸と一致します。

関数は 2 つのパラメータを逆順で取ります。デカルト平面では atan2(y, x) と書きますが、Unity の参照系では x 軸が横方向、z 軸が前後方向、y 軸が垂直方向であり今回は考慮しないため、atan2(x, z) と記述します。

Unity のオンラインドキュメントによると、Mathf.Atan2 は y と x の座標を受け取り、この場合は x と z になりますが、y/x のタンジェントを持つ角度をラジアンで float として返します。

Unity の Rotate 関数は角度を度単位で受け取るため、コードを書く際には単位の違いと必要な変換を考慮する必要があります。

問題と解決方法を分析したので、最初の実装、Rotate を使った瞬時回転に進みましょう。

まず、LookAtObject という新しい C# スクリプトを作成し、実際の監視カメラに関連付けます。ここで実際の監視カメラと言っているのは、このアセットが実際には 3 つの要素、壁に設置するベース、pivot 要素、そしてカメラ本体で構成されているためです。

カメラをそのローカル垂直軸、つまり LOCAL 垂直軸の周りに回転させたいのです。

Unity の仮想空間では GLOBAL 垂直軸は y 軸ですが、各オブジェクトは独自の LOCAL 参照系を持つことができます。この監視カメラの 3D モデルでは、Unity エディタで LOCAL 表示モードに切り替えると分かるように、それが LOCAL Z 軸です。

この違いにより、プロジェクトにはわずかな複雑さが生じます。シーンのグローバル平面上で、オブジェクトの X と Z 座標を使って回転角を計算し、その後でアセットのローカル垂直軸の周りに回転を実行する必要があります。

まず、追従するオブジェクトへの参照を作成します。Transform 型の変数 objectA を作成し、Inspector で Player に関連付けます。

[SerializeField] private Transform objectA;

ここまでできたら、先ほど説明した解決方法を Update 内に実装します。カメラの LOCAL 垂直軸は Z 軸であることを思い出してください。

必要なのは 3 行のコードだけです。

1 行目で、カメラの現在の向きと、向くべき向きとの間の角度を計算します。

2 行目で、目的の向きにするためにカメラのローカル Z 軸の周りに実行すべき回転量を計算します。

3 行目で、Rotate メソッドを使って実際の回転を行います。このメソッドには 2 つのパラメータが必要で、ローカル垂直ベクトルと、そのベクトルの周りに実行する回転量です。

まず、監視カメラの向きと目標の向きとの間の角度を計算します。Mathf の Atan2 関数を使用し、戻り値のラジアンを度に変換します。

2D 平面では、Atan2 は 2 点の Y 座標の差と X 座標の差を受け取ります。順序はターゲットと観測者です。

Unity のグローバル座標系では、X と Z が 2D 平面上にあり、GLOBAL Y がシーンの垂直軸です。したがって、次のように書きます。

float theta = Mathf.Atan2((objectA.transform.position.x - transform.position.x), (objectA.transform.position.z - transform.position.z)) * Mathf.Rad2Deg;

これで度単位の角度が得られます。

次に 2 行目です。実行すべき回転量を度単位で計算します。

float deltaAngle = Mathf.DeltaAngle(transform.eulerAngles.z, theta);

transform.eulerAngles.z は監視カメラの現在の向きを表し、theta は前のステップで計算した目標の向きです。

3 行目で監視カメラを回転させます。

transform.Rotate(Vector3.forward, deltaAngle);

ここでは回転軸として Vector3.forward を使用しています。これはオブジェクトの LOCAL Z 軸を表します。この 3D モデルでは、LOCAL Z 軸が前後方向ではなく、オブジェクトのローカル垂直軸になっているためです。

スクリプトを保存し、Unity エディタに戻って Play を押し、最終結果を確認してください。

NOTE - 監視カメラがターゲットの方向を向いていない場合は、Inspector で監視カメラの初期 XYZ Rotation の値が 0 に設定されていることを確認してから、もう一度試してください。

まとめです。この第 1 部では、解決すべき問題を分析し、2 つのオブジェクトを同一平面上で考える方法、方向ベクトルの計算方法、そしてローカル参照系を考慮しながら監視カメラに適用する方法を確認しました。

その後、Rotate 関数を使用して、ゲームの各フレームでオブジェクトを Player の方向に瞬時に向ける方法を実装しました。

次のパートでは、回転クォータニオンを計算し、Slerp 関数を使用して、よりゆっくりと回転させる方法を見ていきます。

チュートリアルを検索

フレーズ、または複数のキーワードをカンマで区切って入力してください。

Francesco Milaneseによる3Dモデル、チュートリアル、コンピューターグラフィックス関連の資料を掲載しています。3Dモデルの使用ライセンスは、各モデルのページに掲載されているリンク先の外部ストアで購入できます。ご利用には、適用されるライセンス条件が適用されます。 Francesco Milanese — イタリアVAT番号:06321250877。お問い合わせ:info@francescomilanese.com


プライバシー及びクッキーの使用に関する拡張情報の通知