WisdomSoft - for your serial experiences.

ベクトル

大きさと向きを表す情報であるベクトルは、ゲーム内での物体の位置や力を制御するために重要なデータ型です。

2次元ベクトル

グラフィックスプログラミングでは、空間の座標や距離などを表すために、複数の数値要素を組み合わせた値を用います。XNA Framework では 3DCG プログラミングに必要となる基本的な数学型を最初から提供しています。

物理学で大きさと向きを持った量のことをベクトルと呼び、この概念は数学や幾何学で広く応用されています。XNA Framework を含め、線形代数学を扱う 3DCG プログラミングではベクトルに相当するデータが必要になります。しかし、難しく考える必要はありません。プログラミングの世界では、ベクトル型とは複数の数値要素からなるデータ型であり、技術者にとっては配列と違いはありません。

XNA Framework が提供するベクトル型は2つの要素からなる2次元ベクトル、3つの要素からなる3次元ベクトル、そして4つの要素からなる4次元ベクトルの3種類です。基本的に、他の一般的な 3DCG グラフィックス API で使われるベクトル型と共通しているでしょう。

X 要素と Y 要素からなる2次元ベクトルは Microsoft.Xna.Framework.Vector2 構造体で荒業れます。

Microsoft.Xna.Framework.Vector2 構造体
[TypeConverterAttribute("typeof(Microsoft.Xna.Framework.Design.Vector2Converter)")]
[SerializableAttribute]
public struct Vector2 : IEquatable<Vector2>

この構造体のコンストラクタはオーバーロードされており、各要素を初期化する値を指定できます。

Vector2 構造体のコンストラクタ
public Vector2 (float value)
public Vector2 (float x, float y)

1 つの value パラメータ飲みを受け取るコンストラクタで生成された値は、2次元ベクトルの 2 つの要素がともに value パラメータに指定した値で初期化されます。x パラメータには X 要素の値を y パラメータには Y 要素の値を指定します。

コード1
using System.Diagnostics;
using Microsoft.Xna.Framework;

public class TestGame : Game
{
    public static void Main(string[] args)
    {
        Vector2 v1 = new Vector2();
        Vector2 v2 = new Vector2(1);
        Vector2 v3 = new Vector2(10, 100);

        Debug.WriteLine("v1=" + v1);
        Debug.WriteLine("v2=" + v2);
        Debug.WriteLine("v3=" + v3);
    }
}
実行結果
コード1 実行結果

コード1は Vector2 型の値を生成し、その文字列表現を出力しています。実行結果を見れば、正しく 2 つの要素を持ったベクトルが生成できていることが確認できます。

各要素の値はフィールドで公開されています。X 要素の値は X フィールドから、Y 要素の値は Y フィールドから設定または取得できます。

Vector2 構造体 X フィールド
public float X
Vector2 構造体 Y フィールド
public float Y

Vector2 構造体の値は、これらのフィールドを通して任意のタイミングで設定または取得できます。各要素の値は float 型なので、コンストラクタやフィールドで浮動小数点数リテラルを指定する場合は F 接尾辞を忘れないでください。

コード2
using System.Diagnostics;
using Microsoft.Xna.Framework;

public class TestGame : Game
{
    public static void Main(string[] args)
    {
        Vector2 v;
        v.X = 3.14F;
        v.Y = 1.41F;
        Debug.WriteLine("X=" + v.X + ", Y=" + v.Y);
    }
}
実行結果
コード2 実行結果

コード2は X フィールドと Y フィールドの値を読み書きしています。

3次元ベクトル

X 要素、Y 要素、Z 要素からなる3次元ベクトルは Microsoft.Xna.Framework.Vector3 構造体で表されます。機能的には Z 要素が増えた以外は Vector2 構造体と同じです。

Microsoft.Xna.Framework.Vector3 構造体
[TypeConverterAttribute("typeof(Microsoft.Xna.Framework.Design.Vector3Converter)")]
[SerializableAttribute]
public struct Vector3 : IEquatable<Vector3>

この構造体のコンストラクタはオーバーロードされており、各要素を初期化する値を指定できます。

Vector3 構造体のコンストラクタ
public Vector3 (float value)
public Vector3 (float x, float y, float z)
public Vector3 (Vector2 value, float z)

パラメータを受け取らないコンストラクタは全ての要素を 0 で初期化します。単一の value パラメータを指定するコンストラクタは、パラメータの値でベクトルのすべての要素を初期化します。x パラメータには X 要素の値を、y パラメータには Y 要素の値を、z パラメータには Z 要素の値を指定します。Vector2 型の value パラメータは X 要素と Y 要素を初期化する値を指定します。

コード3
using System.Diagnostics;
using Microsoft.Xna.Framework;

public class TestGame : Game
{
    public static void Main(string[] args)
    {
        Vector3 v1 = new Vector3();
        Vector3 v2 = new Vector3(1);
        Vector3 v3 = new Vector3(1.5F, 2.5F, 3.5F);
        Vector3 v4 = new Vector3(new Vector2(10, 20), 30);

        Debug.WriteLine("v1=" + v1);
        Debug.WriteLine("v2=" + v2);
        Debug.WriteLine("v3=" + v3);
        Debug.WriteLine("v4=" + v4);
    }
}
実行結果
コード3 実行結果

コード3は Vector3 構造体の値を生成し、それぞれの値の文字列表現を出力しています。

Vector2 構造体と同様、各要素の値はフィールドで公開されています。X 要素の値は X フィールドから、Y 要素の値は Y フィールドから、Z 要素の値は Z フィールドから設定または取得できます。

Vector3 構造体 X フィールド
public float X
Vector3 構造体 Y フィールド
public float Y
Vector3 構造体 Z フィールド
public float Z

Vector3 構造体の値は、これらのフィールドを通して任意のタイミングで設定または取得できます。

コード4
using System.Diagnostics;
using Microsoft.Xna.Framework;

public class TestGame : Game
{
    public static void Main(string[] args)
    {
        Vector3 v;
        v.X = 10;
        v.Y = 20;
        v.Z = 30;

        Debug.WriteLine("X=" + v.X + ", Y=" + v.Y + ", Z=" + v.Z);
    }
}
実行結果
コード4 実行結果

コード4は Vector3 構造体の X フィールド、Y フィールド、Z フィールドから要素の値を設定及び取得しています。

4次元ベクトル

X 要素、Y 要素、Z 要素、そして W 要素からなる4次元ベクトルは Microsoft.Xna.Framework.Vector4 構造体で表されます。

Microsoft.Xna.Framework.Vector4 構造体
[TypeConverterAttribute("typeof(Microsoft.Xna.Framework.Design.Vector4Converter)")]
[SerializableAttribute]
public struct Vector4 : IEquatable<Vector4>

この構造体のコンストラクタはオーバーロードされており、各要素を初期化する値を指定できます。パラメータの構造は Vector2 構造体や Vector3 構造体と同じです。

Vector4 構造体のコンストラクタ
public Vector4 ()
public Vector4 (float value)
public Vector4 (float x, float y, float z, float w)
public Vector4 (Vector2 value, float z, float w)
public Vector4 (Vector3 value, float w)

パラメータを受け取らないコンストラクタは全ての要素を 0 で初期化します。単一の value パラメータを指定するコンストラクタは、パラメータの値でベクトルのすべての要素を初期化します。

x パラメータには X 要素の値を、y パラメータには Y 要素の値を、z パラメータには Z 要素の値を、w パラメータには W 要素の値を指定します。Vector2 型の value パラメータには X 要素と Y 要素の値を表す2次元ベクトルを、Vector3 型の value パラメータには X 要素、Y 要素、Z 要素の値を表す3次元ベクトルを指定します。

コード5
using System.Diagnostics;
using Microsoft.Xna.Framework;

public class TestGame : Game
{
    public static void Main(string[] args)
    {
        Vector4 v1 = new Vector4();
        Vector4 v2 = new Vector4(1);
        Vector4 v3 = new Vector4(1.5F, 2.5F, 3.5F, 4.5F);
        Vector4 v4 = new Vector4(new Vector2(10, 20), 30, 40);
        Vector4 v5 = new Vector4(new Vector3(100, 200, 300), 400);

        Debug.WriteLine("v1=" + v1);
        Debug.WriteLine("v2=" + v2);
        Debug.WriteLine("v3=" + v3);
        Debug.WriteLine("v4=" + v4);
        Debug.WriteLine("v5=" + v5);
    }
}
実行結果
コード5 実行結果

コード5は Vector4 構造体の値を生成し、その結果を出力しています。

Vector2 や Vector3 構造体と同様、各要素の値はフィールドで公開されています。X 要素の値は X フィールドから、Y 要素の値は Y フィールドから、Z 要素の値は Z フィールドから、W 要素の値は W フィールドから設定または取得できます。

Vector4 構造体 X フィールド
public float X
Vector4 構造体 Y フィールド
public float Y
Vector4 構造体 Z フィールド
public float Z
Vector4 構造体 W フィールド
public float W

Vector4 構造体の値は、これらのフィールドを通して任意のタイミングで設定または取得できます。

コード6
using System.Diagnostics;
using Microsoft.Xna.Framework;

public class TestGame : Game
{
    public static void Main(string[] args)
    {
        Vector4 v;
        v.X = 10;
        v.Y = 20;
        v.Z = 30;
        v.W = 40;

        Debug.WriteLine("X=" + v.X + ", Y=" + v.Y + ", Z=" + v.Z + ", W=" + v.W);
    }
}
実行結果
コード6 実行結果

コード6は Vector4 構造体の各要素を表す X フィールド、Y フィールド、Z フィールド、及び W フィールドから値を設定し、出力しています。

固定値の取得

ベクトルを表す各構造体は、ベクトルの初期値や基準値として用いられる標準的な値のいくつかを静的な読み取り専用プロパティで提供しています。コンストラクタで初期化するよりも、簡単かつ確実に値を取得できるため利用すると便利です。

全ての要素が 0 の状態のベクトルは Zero プロパティで提供されています。これはパラメータを渡さない空のコンストラクタで作られる値と同じですが、ベクトルが 0 であるという意図をコード上で明示的に表すことができます。

Vector2 構造体 Zero プロパティ
public static Vector2 Zero { get; }
Vector3 構造体 Zero プロパティ
public static Vector3 Zero { get; }
Vector4 構造体 Zero プロパティ
public static Vector4 Zero { get; }

Zero プロパティは Vector2 構造体、Vector3 構造体、Vector4 構造体の、すべてのベクトル型で用意されています。ベクトルのすべての要素が 0 の状態の値を得られます。

コード7
using System.Diagnostics;
using Microsoft.Xna.Framework;

public class TestGame : Game
{
    public static void Main(string[] args)
    {
        Debug.WriteLine("Vector2 Zero=" + Vector2.Zero);
        Debug.WriteLine("Vector3 Zero=" + Vector3.Zero);
        Debug.WriteLine("Vector4 Zero=" + Vector4.Zero);
    }
}
実行結果
コード7 実行結果

同様に、すべての要素が 1 に設定されたベクトルは One プロパティから取得できます。

Vector2 構造体 One プロパティ
public static Vector2 One { get; }
Vector3 構造体 One プロパティ
public static Vector3 One { get; }
Vector4 構造体 One プロパティ
public static Vector4 One { get; }

One プロパティも、すべてのベクトル型で提供されています。

コード8
using System.Diagnostics;
using Microsoft.Xna.Framework;

public class TestGame : Game
{
    public static void Main(string[] args)
    {
        Debug.WriteLine("Vector2 One=" + Vector2.One);
        Debug.WriteLine("Vector3 One=" + Vector3.One);
        Debug.WriteLine("Vector4 One=" + Vector4.One);
    }
}
実行結果
コード8 実行結果

Vector2 構造体と Vector3 構造体には、これらのプロパティに加えて方向を表す単位ベクトルを返すプロパティも提供しています。

Vector2 構造体では X 軸の単位ベクトルを UnitX プロパティから、Y 軸の単位ベクトルを UnitY プロパティから取得できます。

Vector2 構造体 UnitX プロパティ
public static Vector2 UnitX { get; }
Vector2 構造体 UnitY プロパティ
public static Vector2 UnitY { get; }

同様に Vector3 構造体では UnitX プロパティと UnitY プロパティに加えて Z 軸の単位ベクトル UnitZ プロパティが提供されています。

Vector3 構造体 UnitX プロパティ
public static Vector3 UnitX { get; }
Vector3 構造体 UnitY プロパティ
public static Vector3 UnitY { get; }
Vector3 構造体 UnitY プロパティ
public static Vector3 UnitZ { get; }

この流れから容易に想像できますが Vector4 構造体でも各軸の単位ベクトルを返す UnitX プロパティ、UnitY プロパティ、UnitZ プロパティに加えて、W 軸の単位ベクトルを返す UnitW プロパティが提供されています。

Vector4 構造体 UnitX プロパティ
public static Vector4 UnitX { get; }
Vector4 構造体 UnitY プロパティ
public static Vector4 UnitY { get; }
Vector4 構造体 UnitY プロパティ
public static Vector4 UnitZ { get; }
Vector4 構造体 UnitW プロパティ
public static Vector4 UnitW { get; }

これらの単位ベクトルはゲーム中のベクトルの初期値として多様な場所で利用されるため、覚えておくと便利です。

コード9
using System.Diagnostics;
using Microsoft.Xna.Framework;

public class TestGame : Game
{
    public static void Main(string[] args)
    {
        Debug.WriteLine("Vector2 UnitX=" + Vector2.UnitX);
        Debug.WriteLine("Vector2 UnitY=" + Vector2.UnitY);

        Debug.WriteLine("Vector3 UnitX=" + Vector3.UnitX);
        Debug.WriteLine("Vector3 UnitY=" + Vector3.UnitY);
        Debug.WriteLine("Vector3 UnitZ=" + Vector3.UnitZ);

        Debug.WriteLine("Vector4 UnitX=" + Vector4.UnitX);
        Debug.WriteLine("Vector4 UnitY=" + Vector4.UnitY);
        Debug.WriteLine("Vector4 UnitZ=" + Vector4.UnitZ);
        Debug.WriteLine("Vector4 UnitW=" + Vector4.UnitW);
    }
}
実行結果
コード9 実行結果

コード9では、各次元のベクトル型で用意された単位ベクトルのプロパティを出力しています。コンストラクタで明示的に初期化して同じ値を作ることができますが、これらのプロパティを用いたほうが便利でしょう。

これら各軸の単位ベクトルに加えて Vector3 構造体型では 3 次元空間の各方向を表す単位ベクトルを静的プロパティで提供しています。左方向(-1, 0, 0)は Left プロパティ、右方向(1, 0, 0)は Right プロパティ、上方向(0, 1, 0)は Up プロパティ、下方向(0, -1, 0)は Down プロパティ、後方向(0, 0, 1)は Backward プロパティ、そして前方向(0, 0, -1)は Forward プロパティから取得できます。

Vector3 構造体 Left プロパティ
public static Vector3 Left { get; }
Vector3 構造体 Right プロパティ
public static Vector3 Right { get; }
Vector3 構造体 Up プロパティ
public static Vector3 Up { get; }
Vector3 構造体 Down プロパティ
public static Vector3 Down { get; }
Vector3 構造体 Backword プロパティ
public static Vector3 Backword { get; }
Vector3 構造体 Foward プロパティ
public static Vector3 Foward { get; }

なかでも重要なのは Z 軸の方向で、Z 軸の値が正であれば手前に、負であれば奥に向かう座標系のことを右手座標系と呼び、その逆の座標系を左手座標系と呼びます。Windows で標準的な 3D グラフィックスの API である DirectX では左手座標系が用いられていますが、XNA Framework は右手座標系が用いられています。

コード10
using System.Diagnostics;
using Microsoft.Xna.Framework;

public class TestGame : Game
{
    public static void Main(string[] args)
    {
        Debug.WriteLine("Left=" + Vector3.Left);
        Debug.WriteLine("Right=" + Vector3.Right);
        Debug.WriteLine("Up=" + Vector3.Up);
        Debug.WriteLine("Down=" + Vector3.Down);
        Debug.WriteLine("Backward=" + Vector3.Backward);
        Debug.WriteLine("Forward=" + Vector3.Forward);
    }
}
実行結果
コード10 実行結果

コード10は Vector3 構造体の上下左右前後を表す各単位ベクトルを出力しています。

ベクトルの大きさ

ベクトルの大きさは、すべてのベクトル型で共通して Length() メソッドから取得できます。このメソッドは、ベクトルに設定されている各要素の値からベクトルの大きさを計算して結果を返します。

Vector2 構造体 Length() メソッド
public float Length ()
Vector3 構造体 Length() メソッド
public float Length ()
Vector4 構造体 Length() メソッド
public float Length ()

このプロパティから得られるベクトルの大きは、ベクトル要素の2乗和の平方根です。ベクトルは大きさと向きを情報として持っていますが、そこから大きさだけを取り出しすことができます。

コード11
using System.Diagnostics;
using Microsoft.Xna.Framework;

public class TestGame : Game
{
    public static void Main(string[] args)
    {
        Vector2 v1 = new Vector2(5, 3);
        Vector2 v2 = new Vector2(1, 1);

        Debug.WriteLine(v1 + " Length=" + v1.Length());
        Debug.WriteLine(v2 + " Length=" + v2.Length());
    }
}
実行結果
コード11 実行結果

コード11は 2 次元ベクトルの大きさを取得し、それを出力しています。実行結果から X 要素の 2 乗と Y 要素の 2 乗を加算した結果(x * x + y * y)の平方根であることが確認できます。

ベクトルの大きさをどのように解釈し、何に利用するかはプログラム次第です。大きさ、長さ、強さなど、ベクトル型を使って表現するデータの種類によって意味は変わってきます。重要なのは、ベクトルの向きに関係なく、ベクトルの大きさだけを float 型の値として抽出できるという点です。例えば、異なる向きのベクトルを容易に比較できるようになります。

単位ベクトル

単位ベクトルは常にベクトルの大きさ、すなわち Length() メソッドの戻り値が 1 になるベクトルのことです。ベクトルの大きさを均一化することで、ベクトルの向きだけを抽出できます。単位ベクトルは、方向を表すベクトルとして利用できます。

任意のベクトルから単位ベクトルを取得するには、すべてのベクトル型で共通して Normalize() メソッドを用います。このメソッドは、現在のベクトルを単位ベクトルに変換するインスタンスメソッドと、指定したベクトルを単位ベクトルに変換して返す静的メソッドが、各ベクトル型で用意されています。

Vector2 構造体 Normalize() メソッド
public void Normalize ()
public static Vector2 Normalize (Vector2 value)
Vector3 構造体 Normalize() メソッド
public void Normalize ()
public static Vector3 Normalize (Vector3 value)
Vector4 構造体 Normalize() メソッド
public void Normalize ()
public static Vector4 Normalize (Vector4 value)

value パラメータには単位ベクトルに変換する元のベクトルを指定します。

コード12
using System.Diagnostics;
using Microsoft.Xna.Framework;

public class TestGame : Game
{
    public static void Main(string[] args)
    {
        Vector2 source = new Vector2(5, 3);
        Vector2 normalized = Vector2.Normalize(source);
        float length = normalized.Length();

        Debug.WriteLine("Source=" + source);
        Debug.WriteLine("Normalized=" + normalized);
        Debug.WriteLine("Length=" + length);
    }
}
実行結果
コード12 実行結果

コード12は適当な Vector2 構造体の値から Normalize() メソッドを用いて単位ベクトルを取得し、その結果を出力しています。また、Length() メソッドで単位ベクトルからベクトルの大きさを取得し、その結果が 1 であることも実行結果から確認できます。