線型代数学
ベクトル
ベクトルとは、一般的には「大きさと向きをもつ量」であり「矢印で表すことのできる量」である。


2次元のベクトルは2つの成分(x, y)があり、3次元の場合は3の成分(x, y, z)がある。Unityでは Vector2 と Vector3 の構造体があり、それぞれのベクトルを作成ができる。
Vector2 vec2D = new Vector2(vx, vy); // vxとvyはfloatである
Vector3 vec3D = new Vector3(vx, vy, vz); // vzもfloatである
ゲームの中で、ベクトルをよく使うものである。例えば、3D空間で、キャラクターの速度が「左向き:秒速2メートル、前方:秒速10メートル」であるとしたら…
// 3D空間だと、x:左右、y:上下、z:前後
Vector3 velocity = new Vector3(-2, 0, 10);
また、ゲームの場合は、向きと量はもちろんそうであるが、その他に「位置」もベクトルで表現する。
// プレーヤーはシーンの中心点から前方100メートルにいる
Vector3 playerPosition = new Vector3(0, 0, 100);
演算
やはり、ベクトルは重要なので、ベクトルの演算を学ばないといけない。
加算
2つのベクトルを足すことができる。その結果は各成分の足し算である:
2次元の場合:
|
|
3次元の場合:
|
|
Unityでは「+」の演算子で2つのベクトルを足すことができる
Vector3 v = new Vector3(vx, vy, vz); // vx, vyとvzは何かのfloat型の数値
Vector3 w = new Vector3(wx, wy, wz); // wx, wyとwzは何かのfloat型の数値
Vector3 vw = v + w;
幾何学的に、足し算は2つの矢印を連続し、1つ目のベクトルの始点から2つ目のベクトルの終点までに新しいベクトルを作成するイメージ:

減算
引き算は同じ形で行う:
Vector3 v = new Vector3(vx, vy, vz); // vx, vyとvzは何かのfloat型の数値
Vector3 w = new Vector3(wx, wy, wz); // wx, wyとwzは何かのfloat型の数値
Vector3 vw = v - w;
幾何学的には、引くベクトルの向きを反転してから連続に繋がる
練習
加算と減算を使い、2つのオブジェクトを相対的に移動
- シーンに2つの3Dゲームオブジェクトを追加し、距離的に放してください。
- 1つ目の名前は「Control」
- 2つ目の名前は「Follower」
- スクリプト「VectorTest」を作成し…
- Follower と Control の相対位置を求める(減算)
- Control をシーン内で動かしたら、Follower が移動を真似する(加算)
スクリプト:VectorTest
// ベクトル演算の練習」
public class VectorTest : MonoBehaviour
{
// 移動すべきのオブジェクト
[SerializeField] private GameObject control;
// controlを追跡するオブジェクト
[SerializeField] private GameObject follower;
// controlとfollowerの相対位置
private Vector3 relativePosition;
private void Start()
{
// 初期位置を取得
var v = control.transform.position;
var w = follower.transform.position;
// 相対位置を計算(減算で)
relativePosition = w - v;
}
private void Update()
{
// followerの位置が、controlの位置 + 相対位置
follower.transform.position =
control.transform.position + relativePosition;
}
}
実数との掛け算、割り算
ベクトルを実数との掛け算ができる。各成分との掛け算になる:
|
|
Unityでは、普通の掛け算演算子「*」で計算できる:
Vector3 v = new Vector3(vx, vy, vz); // vx, vyとvzは何かのfloat型の数値
Vector3 nv = v * n; // nは何かの実数(float)である
練習
先ほど作った「VectorTest」を更新し、相対位置の「倍率(scale)」を Inspector で変えられるようにする。
スクリプト:VectorTest
// ベクトル演算の練習」
public class VectorTest : MonoBehaviour
{
// 移動すべきのオブジェクト
[SerializeField] private GameObject control;
// controlを追跡するオブジェクト
[SerializeField] private GameObject follower;
// 相対位置の倍率
[SerializeField] private float scale = 1;
// controlとfollowerの相対位置
private Vector3 relativePosition;
private void Start()
{
// 初期位置を取得
var v = control.transform.position;
var w = follower.transform.position;
// 相対位置を計算(減算で)
relativePosition = w - v;
}
private void Update()
{
// 倍率を適用する
Vector3 scalePos = relativePosition * scale;
// followerの位置が、controlの位置 + 相対位置
follower.transform.position =
control.transform.position + scalePos;
}
}
ベクトルの長さ
場合により、ベクトルの長さを求めたいときもある。これには「ピタゴラスの定理」(三平方の定理)を利用する。ピタゴラスの定理を思い出しましょう。直角三角形があれば…

c 辺の長さは:
|
|
つまり…
|
|
これはベクトルの成分とよく似ているので:

これができる!
|
|
ここで || v || はベクトルの「ノルム」といわれ、ベクトルの長さを表している。Unityでは、Vectorの便利な「magnitude」がある:
Vector2 p = new Vector2(3, 4);
float len = p.magnitude; // len は p の長さ(5)である
単位ベクトル
ベクトルの長さを「1」にすると、そのベクトルは単位円の中に入り、各成分がsinとcosを一致させることができる。その他にも、ベクトルの長さを調整する前に、まず長さを1に戻さないといけないが必要である。その場合は単位ベクトルを求めないといけない。

単位ベクトルを求めるのは、ベクトルをノルムで割るだけ:

Unityでは「normalized」というプロパティーで単位ベクトルを求めることができる。
// 任意の長さのベクトル v があるとして:
Vector3 v = new Vector3(30, 12, -15);
// uはvと同じ向き(方向)であるが、長さは「1」である(単位ベクトル)
Vector3 u = v.normalized;
ベクトル同士の”掛け算”(内積と外積)
ベクトル同士の掛け算はできないが、2つの特別な関数がある。内積(dot product)と外積(cross product)。それぞれは限られた使い方があるが、必要な時にとても便利である。
内積
内積の定義は以下の通りになる:


ある2つのベクトル「v」と「w」の内積は、それぞれのベクトルのノルム(長さ)とその2つのベクトルの間の角度のコサインの掛け算である。答えは実数である。
これは何に便利かというと、2つのベクトルの間の角度を求めたいなら、内積を使えば良いでしょう。まず、vとwを単位ベクトルにすると、長さは1になるので、式は単純になる:

そして、角度を求めるのは:

Unityで内積の計算を実装されている:
Vector3 v = new Vector3(vx, vy, vz);
Vector3 w = new Vector3(wx, wy, wz);
float dot = Vector3.Dot(v, w); // 内積
// 角度を求めたいなら
float radians = Mathf.Acos(dot);
// そして
float angle = radians * Mathf.Rad2Deg;
練習
警備員の視野を利用するゲーム
警備員のスクリプト
// 警備員の前に泥棒がいるかいないか確認する
public class GuardMan : MonoBehaviour
{
// 泥棒への向きが欲しいので、泥棒が必要
[SerializeField]
private GameObject thief;
// 視野(度)
[SerializeField]
private float viewAngle;
// 色を変えるため
private MeshRenderer rend;
private void Start()
{
rend = GetComponent<MeshRenderer>();
}
private void Update()
{
// 警備員の前向きのベクトル
Vector3 v = transform.forward; // 青い矢印のこと
// 泥棒への向き
Vector3 w = thief.transform.position - transform.position;
// 単位ベクトルにする
w.Normalize();
// 内積で角度のコサインを求める
float dot = Vector3.Dot(v, w);
// 内積からラジアン角度を求める
float radian = Mathf.Acos(dot);
// 度に変換
float angle = radian * Mathf.Rad2Deg;
// 警備員と泥棒の角度が視野よりも小さければ、発見!
if (angle < viewAngle)
rend.material.color = Color.red;
// 見えない
else
rend.material.color = Color.green;
}
}
外積
2つのベクトル外積の式は以下の通りである:

そして、Unityでも計算を実装されている:
Vector3 v = new Vector3(vx, vy, vz);
Vector3 w = new Vector3(wx, wy, wz);
Vector3 cross = Vector3.Cross(v, w); // 外積の結果は新しいベクトルである
式よりも、外積の幾何学的な意味は重要。2つの3Dベクトル「v」と「w」は平面を定義すし、それで「v」と「w」の外積の結果は:


従って、2つのベクトルがあれば、そのベクトルで作られた「面」を直交するベクトルを求めることができる。面の「法線ベクトル」、または3D空間の傾きの方向を求めることができる!
行列





