[3D Tips #1] ベクトル
3D の基礎知識として絶対に欠かせない「ベクトル」や「行列」。今回はベクトルについて。
ベクトルは大きさと方向を持った量のこと。
2 次元のベクトルの場合は、<x, y> 2 つの成分を持ち(厳密には、どんな成分を持たせるかは実装者次第で、n 次元のベクトルは n 個の成分を持つというだけ)、 AS でいうところの Point クラスのようなもの。Point クラスでいえば、大きさは length メソッドで求まり、方向は x, y 成分の各数値になる。ただ、3D で扱うベクトルは 3 次元なので <x, y, z> 3 つの成分を持つ独自のクラスを作る必要がある。この時、持たせておくクラスメンバは下記の通り。
<必須になるクラスメンバ>
・x, y, z の各プロパティ
・length メソッド
ベクトルの大きさを求める。三平方の定理で求まる。
参考:deq notes さん 「ベクトルの基礎」
・normalize メソッド
ベクトルの大きさが 1 になるように <x, y, z> 各成分を変更する。各成分をベクトルの大きさで割ることで求まる。この時、各数値は 0 で割れず(割り算の基本)、1 の時は割る必要がない。こうして求まったベクトルを「単位ベクトル」といい、単位ベクトルを求めることを「正規化 (normalize) 」という。法線ベクトル (normal) とは関係無いので注意すること。
参考:deq notes さん 「ベクトルの利用」
・cross メソッド
ベクトル同士の外積を求める。2 つのベクトルに対し垂直なベクトルを求めるのに必要で、3D では法線ベクトルを求めるときなどに使用する。3 次元の場合、返り値はベクトルになる。数式で表すときは「P × Q」と表し、普通の乗算とは異なるので注意すること。
参考:deq notes さん 「内積と外積」
・dot メソッド
ベクトル同士の内積を求める。2 つのベクトルのなす角度を求めるのに必要で、3D では面の可視判定などに使用する。3 次元の場合、返り値は数値になる。数式で表すときは「P ・ Q」と表し、普通の乗算とは異なるので注意すること。
参考:deq notes さん 「内積と外積」
参考:Flashゲーム講座&ASサンプル集 さん 「交差判定について」の「内積とは?」の項目
<あると良いクラスメンバ>
・invert メソッド
ベクトルの <x, y, z> 各成分を反転する。
・add メソッド
ベクトルの <x, y, z> 各成分を加算する。数式で表すときは「P + Q」と表し、普通の加算とは異なるので注意すること。
・sub メソッド
ベクトルの <x, y, z> 各成分を減算する。数式で表すときは「P - Q」と表し、普通の減算とは異なるので注意すること。
以上を踏まえて定義した Vector3D クラスは下記のとおり。
なお、今後のために IVector3D インターフェースを実装する。
Vector3D クラス
package
{
public class Vector3D implements IVector3D
{
private var _x:Number;
private var _y:Number;
private var _z:Number;
/**
* 新しい Vector3D インスタンスを作成します。
*
* @param x ベクトルの x 成分です。
* @param y ベクトルの y 成分です。
* @param z ベクトルの z 成分です。
*/
public function Vector3D(x:Number = 0, y:Number = 0, z:Number = 0):void
{
_x = x;
_y = y;
_z = z;
}
/**
* ベクトルの x 成分です。
*/
public function get x():Number
{
return _x;
}
public function set x(value:Number):void
{
_x = value;
}
/**
* ベクトルの y 成分です。
*/
public function get y():Number
{
return _y;
}
public function set y(value:Number):void
{
_y = value;
}
/**
* ベクトルの z 成分です。
*/
public function get z():Number
{
return _z;
}
public function set z(value:Number):void
{
_z = value;
}
/**
* ベクトルの大きさです。
*/
public function get length():Number
{
return Math.sqrt(x * x + y * y + z * z);
}
/**
* ベクトルを正規化して単位ベクトルにします。
*/
public function normalize():void
{
var l:Number = length;
if (l != 0 && l != 1)
{
x /= l;
y /= l;
z /= l;
}
}
/**
* 対象のベクトルとの外積を返します。
*
* @param v 対象のベクトルです。
* @return 対象のベクトルとの外積。
*/
public function cross(v:IVector3D):Vector3D
{
return new Vector3D(
y * v.z - z * v.y,
z * v.x - x * v.z,
x * v.y - y * v.x
);
}
/**
* 対象のベクトルとの内積を返します。
*
* @param v 対象のベクトルです。
* @return 対象のベクトルとの内積。
*/
public function dot(v:IVector3D):Number
{
return x * v.x + y * v.y + z * v.z;
}
/**
* ベクトルを反転します。
*/
public function invert():void
{
x *= -1;
y *= -1;
z *= -1;
}
/**
* 対象のベクトルで加算します。
*
* @param v 対象のベクトルです。
*/
public function add(v:IVector3D):void
{
x += v.x;
y += v.y;
z += v.z;
}
/**
* 対象のベクトルで減算します。
*
* @param v 対象のベクトルです。
*/
public function sub(v:IVector3D):void
{
x -= v.x;
y -= v.y;
z -= v.z;
}
/**
* ベクトルの複製を作成します。
*
* @return ベクトルの複製。
*/
public function clone():Vector3D
{
return new Vector3D(x, y, z);
}
/**
* このオブジェクトのストリング表現を返します。
*
* @return このオブジェクトのストリング表現。
*/
public function toString():String
{
return "[object Vector3D {x:" + x + ", y:" + y + ", z:" + z + "}]";
}
}
}
IVector3D インターフェース
package
{
public interface IVector3D
{
function get x():Number;
function set x(value:Number):void;
function get y():Number;
function set y(value:Number):void;
function get z():Number;
function set z(value:Number):void;
}
}
とりあえず今日はここまで。突っ込み大歓迎、答えられる範囲なら質問も大歓迎です。次は 3D 用の行列についてまとめます。