Version: Unity 6.0 (6000.0)
言語 : 日本語
Programming with mathematics
一般的な数学関数の使用

ベクトルによるオブジェクトの動作

ベクトルは数学の基本的な概念で、方向と大きさを表現することができます。ゲームやアプリケーションでは、キャラクターの位置、移動速度、2 つのオブジェクト間の距離など、基本的なプロパティを表すために使用します。

ベクトル演算は、グラフィックス、物理演算、アニメーションなど、コンピュータープログラミングの多くの面で基本となるものであり、Unity を最大限に活用するために、深く理解しておくと役に立ちます。

ベクトルは複数の次元で表現できます。Unity では 2D、3D、4D ベクトルを扱うために Vector2、Vector3、Vector4 クラスを用意しています。これら 3 種類の Vector クラスは、magnitude などの多くの関数を共有しています。そのため、このページの情報のほとんどは、特に指定がない限り、3 種類の Vector すべてに当てはまります。

このページでは、Vector クラスの概要と、Vector クラスを使ったスクリプトの一般的な使用方法について説明します。Vector クラスのすべてのメンバーの詳細なリファレンスについては、Vector2Vector3Vector4 のスクリプトリファレンスページを参照してください。

ベクトル演算を理解する

追加コード

2 つのベクトルを互いに足すと、元の 2 つのベクトルを一方から他方へと続く “ステップ” として捉えたのと同じ結果になります。結果は同じになるので、2 つのパラメーターの順番は関係ありません。

最初のベクトルを空間上の点とした場合、2 つ目のベクトルはその位置からのオフセットまたは “ジャンプ” とみなすことができます。例えば、地面から 5 単位上の場所を見つけるためには以下の計算を使用することができます。

 var pointInAir = pointOnGround + new Vector2(0, 5);

ベクトルが力を表す場合、向きや大きさ (力の大きさ) を表すと考えると分かりやすいです。2 つの力のベクトルを足すと、2 つの力の組み合わせによる新しいベクトルが得られます。この考え方は複数の異なるコンポーネントの力を同時に適用する場合に役立ちます (例えば、前方へ推進するロケットが同時に横風の影響を受ける場合など)。

ここでは 2D のベクトルを例に挙げていますが、3D や 4D のベクトルにも同じ考え方を適用できます。

減算

ベクトルの減算は、あるオブジェクトから別のオブジェクトに対する向きと距離を計算する場合に最もよく使用します。減算の場合は、2 つのパラメーターの順番が計算結果に 影響を与える ことに注意してください。

// The vector d has the same magnitude as c but points in the opposite direction.
var c = b - a;
var d = a - b;

数字については、負の値のベクトルを足すのは、正の値のベクトルを減算するのと同じです。

// These both give the same result.
var c = a - b;
var c = a + -b;

負の値のベクトルはもとと同じ大きさであり、同一線分上に沿いますが、まったく逆の方向となります。

あるオブジェクトから別のオブジェクトへの向きと距離

もし空間上の 1 点を別の点から引くと、結果は 1 つのオブジェクトから他方を “指す” ベクトルになります。

// Gets a vector that points from the player's position to the target's.
var heading = target.position - player.position;

ターゲットオブジェクトの方向を指すとともに、このベクトルの大きさは 2 つの位置の間の距離に等しくなります。距離は固定したまま、ターゲットへの方向を示す “正規化された” ベクトルが必要になる場合もあります (例えば、砲弾を誘導する場合など)。ベクトルを正規化するには、そのベクトルの大きさで割る必要があります。

var distance = heading.magnitude;
var direction = heading / distance; // This is now the normalized direction.

大きさ (magnitude) と正規化されたプロパティの両方を別々に使用する場合、両方ともに CPU をかなり消費するため (両方とも平方根計算を含むため)、この方法がより望ましいと言えます。

比較に使用する距離だけが必要な場合 (例えば、近接度合いのチェックなど) は、大きさの計算をすべて回避することができます。sqrMagnitude プロパティはベクトルの大きさの値の 2 乗を求め、大きさと同じように計算されますが時間のかかる平方根演算は行われません。この場合は大きさと既知の距離を比較する代わりに、大きさの 2 乗とその距離の 2 乗を比較します。

if (heading.sqrMagnitude < maxRange * maxRange) {
    // Target is within range.
}

これは実際の magnitude を比較するよりも遥かに効率的です。

3D で作業するときに、ターゲットへの “地上の進行方向” が必要になる場合があります。例えば、地面に立っているプレイヤーが、空中に浮かんでいるターゲットに近づく必要があるとします。ターゲットの位置からプレイヤーの位置を引くと、上向きにターゲットに向かうベクトルが得られます。これはプレイヤーの Transform の向きを決めるには適切ではありません。プレイヤー自身も上を向いてしまうからです。実際に必要なのは、プレイヤーの位置からターゲットの真下の地面の位置までのベクトルです。この位置は、減算の結果を取得して Y 座標を 0 に設定することで得られます。

var heading = target.position - player.position;
heading.y = 0;  // This is the overground heading.

スカラーの乗算と除算

ベクトルに関する説明では、普通の数値 (例えば、Float 値) をスカラーと呼ぶのが一般的です。これは、ベクトルには大きさと方向の両方があるのに対して、スカラーには “スケール” または大きさしかないことを意味しています。

ベクトルにスカラーを乗算すると、元のベクトルと同じ方向を向くベクトルが得られます。ただし、新しいベクトルの大きさは元の大きさにスカラーの値を乗算した値となります。

同様に、スカラーの除算は元のベクトルの大きさをスカラーで割ります。

これらの演算はベクトルが動作のオフセットまたは力を表現するときに便利です。これにより、ベクトルの向きを変えることなく大きさを変更できます。

あるベクトルをそれ自体の大きさで除算すると、結果は大きさが 1 のベクトルとなり、これは正規化されたベクトルと呼ばれています。正規化されたベクトルにスカラーを乗算すると、結果の大きさはスカラーの値と同じになります。これは力の向きが一定で、強さが制御可能な場合に便利です (例えば、車の車輪は常に前に進みますが、力はドライバーによって制御されます)。

ドット積

ドット積は 2 つのベクトルから、1 つのスカラーを返します。このスカラーは 2 つのベクトルの大きさを掛け合わせたものに、ベクトル間の角度の余弦を掛けた結果と等しくなります。両方のベクトルが正規化されている場合、余弦の値は基本的に最初のベクトルが 2 番目のベクトルの方向にどれだけ伸びるかを表します (またはその逆。パラメーターの順序は関係ありません)。

下の図は、参照ベクトルと比較して、どのように様々な角度のベクトルが、1 と –1 の間のドット積を返すかを示しています。

ドット積は余弦の計算よりも数学的に単純な演算です。そのため、状況によっては Mathf.Cos 関数やベクトルの大きさの演算の代わりに使用することができます (完全に同じことを行うわけではありませんが、同等の効果が得られる場合もあります)。ただし、ドット積関数の計算は CPU 時間を大幅に短縮するため、有用な最適化となる可能性があります。

ドット積は、あるベクトルの大きさが別のベクトルの方向にある量を計算する場合に役立ちます。

例えば自動車のスピードメーターは通常、タイヤの回転速度を測定することで機能します。ただし、車は正面に前進移動していない場合があります (例えば横滑りしている場合)。この場合、一部の動きは車の正面に向かっていないため、スピードメーターによって測定されません。オブジェクトの rigidbody.velocity ベクトルの大きさは、全体的な運動方向のスピードを示します。前進方向のスピードのみを求めるにはドット積を使用します。

var fwdSpeed = Vector3.Dot(rigidbody.velocity, transform.forward);

任意の方向を使用できますが、この計算では方向ベクトルを必ず正規化しておく必要があります。速度の大きさよりも結果が正確になるだけでなく、大きさを求める際に必要な時間のかかる平方根演算も行わずに済みます。

クロス積

クロス積は、3D ベクトルに対してのみ意味を持ちます。2 つの 3D ベクトルを入力として取り、もう 1 つの 3D ベクトルを結果として返します。

結果のベクトルは、2 つの入力ベクトルに垂直になります。入力ベクトルの順番による出力ベクトルの方向は、“右ねじの法則” を使用して覚えることができます。入力ベクトルの順番に合わせて指を曲げると、親指が出力ベクトルの方向を指します。パラメーターの順番を逆にすると、結果のベクトルは正反対になりますが、大きさは同じです。

結果の大きさは入力ベクトルの大きさを掛け合わせて、さらにベクトル間の角度の正弦を乗算したものと等しくなります。正弦関数で役立つ値の一部を以下に示します。

クロス積は、戻り値にいくつかの有用な情報の組み合わせが含まれるため、複雑に見えるかもしれません。しかし、ドット積と同様に数学的に非常に効率的であり、正弦や余弦などの超越関数に依存する時間がかかるコードを最適化するために役立ちます。

法線/垂直ベクトルの計算

“法線” ベクトル (平面に垂直なベクトル) はメッシュ生成に頻繁に使用され、他にも経路追従などの場面で役立つことがあります。平面上の 3 つの点 (メッシュ三角形の角など) を取得すれば、以下のように法線を求めることができます。 - 3 つの点から 1 つを選びます - 他の 2 つのポイントから別々に選んだ点を引きます (結果として 2 つの新しいベクトル、“Side 1” と “Side 2” になります)。 - ベクトル “Side 1” と “Side 2” のクロス積を計算します。 - クロス積の結果は、元の 3 点がある平面に垂直な新しいベクトル、つまり “法線” となります。

Vector3 a;
Vector3 b;
Vector3 c;

Vector3 side1 = b - a;
Vector3 side2 = c - a;

Vector3 normal = Vector3.Cross(side1, side2);

“左手の法則” を使うと、2 つのベクトルをクロス積関数に渡す順番を決めることができます。上側の面 (法線が外を向く面) から見下ろすと、1 つ目のベクトルが右回りに 2 つ目のベクトルの方に回転するようにします。

入力ベクトルの順番を逆にすると、結果は正反対の方向になります。

メッシュの場合、法線ベクトルは正規化する必要があります。これには normalized プロパティを使用できますが、別のテクニックが役立つこともあります。正規化には、垂直ベクトルを大きさで割る方法もあります。

float perpLength = perp.magnitude;
perp /= perpLength;

もう 1 つ役に立つ知識として、三角形の面積は perpLength/2 と等しくなります。これはメッシュ全体の表面積を知る必要がある場合、または相対的な面積に基づく確率でランダムに三角形を選択したい場合に便利です。

追加リソース

Programming with mathematics
一般的な数学関数の使用