行列
行列の生成
位置や距離、大きさなどは Vector3 構造体を使い、方向や回転には Quaternion 構造体を使いました。これらは、必要最小限の情報量で3次元空間のオブジェクトを操作できますが、個別の値として扱わなければなりません。3次元空間上の物体の位置、回転、大きさを 1 つの値として表現することはできません。
複数の変換を 1 つの値として扱うには、4 × 4 の正方行列を用います。線形代数学や幾何学における行列の性質を理解することは重要ですが、プログラミングにおける 4 × 4 の正方行列の実体は、単に 4 × 4 の 2 次元配列にすぎません。Unity の場合、行列は 16 個の float 型要素で構成されます。Vector3 構造体や Quaternion 構造体に比べ情報量が多くなりますが、行列は多くの変換を 1 つの値で記述できるため、計算にとても便利です。
行列は UnityEngine.Matrix4x4 構造体で表されます。
public struct Matrix4x4
この構造体はデフォルトのコンストラクタのみです。
行列の各要素はフィールドとして公開されています。m00 フィールドから m33 フィールドまで、規則的に 2 次元配列の添字のような名前で 16 個のフィールドが提供されています。個々の要素を対象に値を設定または取得するには、これらのフィールドを使うとよいでしょう。
public float m00
public float m33
一方、16 個もの要素を個別のフィールドとして扱うのが面倒なこともあります。繰り返し文を使って行列のすべての要素に対して共通の操作を行いたい場合や、行列を別の値に変換したい場合はインデクサを使います。インデクサはオーバーロードされており、1次元配列として要素にアクセスする方法と、2 次元配列として要素にアクセスする方法の両方を提供しています。
public float this[int index]
public float this[int row, int column]
index パラメータには 0 ~ 15 までの要素番号を指定します。例えば this[0] は m00 と、this[5] は m10 と同じです。
row パラメータと column パラメータには、0 ~ 3 までの行番号と列番号をそれぞれ指定します。例えば this[0, 0] は m00 と、this[1, 0] は m10 と同じです。
using UnityEngine; public class Test : MonoBehaviour { void Start() { Matrix4x4 m; m[0, 0] = 1; m[1, 1] = 1; m[2, 2] = 1; m[3, 3] = 1; print("m=" + m); } }
コード1は Matrix4x4 構造体の m 変数を作成し、インデクサを通していくつかの要素に値を設定しています。その後、print() メソッドで行列の文字列表現を出力しています。実行結果から、行列の指定した要素が正しく 1 で初期化されていることが確認できます。
インデクサを使った値の読み書きは、繰り返し文などすべての要素を網羅的に処理する場合に便利ですが、コード1のように特定の要素にアクセスする場合は、フィールドを使ったほうが意図を読み取りやすいかもしれません。特に、行列の初期化が目的であれば以下のようにオブジェクト初期化子を使えます。
Matrix4x4 m = new Matrix4x4() { m00 = 1, m11 = 1, m22 = 1, m33 = 1 };
ただし、単位行列を取得することが目的であれば Matrix4x4 構造体の静的な identity プロパティから取得できます。このプロパティは読み取り専用です。
public static Matrix4x4 identity { get; }
identity プロパティは常に単位行列に等しい Matrix4x4 構造体の値を返します。すなわち m00 フィールド、m11 フィールド、m22 フィールド、m33 フィールドの 4 つが 1 で、それ以外のフィールドが 0 の状態の行列です。