数学関数_PhysX
数学関数 (2006/09/11 更新)
3DCGでは「ベクトル・行列演算」これが必須です。同じように3D空間である物理演算でもこのベクトル行列演算は避けて通れないものになります。PhysXでは数学関連の関数は「NxMath(数学関数)」「NxMat33(3x3行列演算)」「NxMat34(3x4行列演算)」「NxQuat(クォータニオン)」「NxVec3(ベクトル演算)」のクラスに分別されています。
そこで、これだけは覚えておいたほうがいいかも、というものをチョイスします。と、その前に、浮動小数点の値を表す型についてです。
NxReal / NxF32/ NxF64
スカラー値である浮動小数点単体は、以下のように定義されます。
型名 | 意味 |
---|---|
NxF32 | 32ビット単精度浮動小数点(float型) |
NxF64 | 64ビット倍精度浮動小数点(double型) |
NxReal | NxF32と同じ |
最終的な描画ではOpenGLまたはDirectXで扱うことになると思われますので、コンバート時には注意です。たいていはNxReal(NxF32)で扱うとは思いますが。
NxMathクラス(一般的な数学演算関数)
sin/cosなどの三角関数、平方根、逆数平方根、logなどなど、数学関数が使用できます。すべてstatic関数です。とはいえ、ANSI-Cでのmath.hでサポートされているものばかりですので、これを使う意味があるのか、というのはちょっと分からないです。(プラットフォーム依存の吸収のためか、最適化がほどこされているのか・・)
NxVec3(ベクトル演算関数)
おそらくもっともよく使うであろうベクトルです。xyzの3つの要素を持ちます(それぞれの要素はNxReal型)。
NxVec3 v1; v1 = NxVec3(0.0f, 1.0f, 2.0f);
とするとき、(v1.x, v1.y, v1.z)がそれぞれのxyz要素(public)になっています。
NxVec3 v1, v2, v3, v4; v1 = NxVec3(0.0f, 1.0f, 2.0f); v2 = NxVec3(3.0f, 4.0f, 5.0f); v3 = v1 + v2; v4 = v1 - v2;
値の代入はNxVec3(x, y, z)とすることにより、戻り値としてNxVec3型が返されます。加減剰余算は、NxVec3同士で行うことができます。上記の場合は、v3に(3.0f, 5.0f, 7.0f)が入り、v4に(-3.0f, -3.0f, -3.0f)が入ることになります。
ベクトルを正規化する
NxVec3型の要素の長さが1.0になるように正規化します。
NxVec3 v1; float len; v1 = NxVec3(3.0f, 4.0f, 5.0f); len = v1.normalize();
v1に入った(3.0f, 4.0f, 5.0f)を「v1.normalize()」で正規化します。v1は(0.424264f, 0.565685f, 0.707107f)となり、lenにはベクトルの長さ(7.071068f)が返ります。v1の値自身が変更される点に注意してください。
ベクトルの長さを求める
NxVec3 v1; float len; v1 = NxVec3(3.0f, 4.0f, 5.0f); len = v1.magnitude();
「v1.magnitude();」にてベクトルの長さを求めます。lenにはベクトルの長さ(7.071068f)が返ります。v1自身の値は変更されません。
ベクトル同士の内積を求める
NxVec3 v1, v2; float fVal; v1 = NxVec3(3.0f, 4.0f, 5.0f); v2 = NxVec3(1.0f, 2.0f, 3.0f); fVal = v1.dot(v2);
この例ではv1とv2の内積を「fVal = v1.dot(v2);」で求めています。戻り値のfValが内積の結果です。ここでは26.0fが返ります。計算内容は「fVal = v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;」と同じです。
ベクトル同士の外積を求める
NxVec3 v1, v2, v3; v1 = NxVec3(3.0f, 4.0f, 5.0f); v2 = NxVec3(1.0f, 2.0f, 3.0f); v3.cross(v1, v2);
この例ではv1とv2の外積を「v3.cross(v1, v2);」で求めています。v1とv2の外積計算の結果をv3に格納しています。ここではv3に「2.0f, -4.0f, 2.0f」が返ります。計算内容は以下と同じです。
v3.x = v1.y * v2.z - v1.z * v2.y; v3.y = v1.z * v2.x - v1.x * v2.z; v3.z = v1.x * v2.y - v1.y * v2.x;
NxMat34クラス(3x4行列)
回転と移動の行列を表します。内部的にはNxMat33(回転行列)とNxVec3(移動)で表現されます。
とはいえ、DirectX/OpenGLで扱う行列は4x4なので変換する必要があります。この変換関数も内包されています。
[ rx1 ry1 rz1 ] [ rx1 ry1 rz1 0.0f ] [ rx2 ry2 rz2 ] ==> [ rx2 ry2 rz2 0.0f ] [ rx3 ry3 rz3 ] [ rx3 ry3 rz3 0.0f ] [ tx ty tz ] [ tx ty tz 1.0f ]
このうち(tx, ty, tz)の部分が移動のベクトルとなります。
NxMat34 m; float matA[16]; // 3x4行列の内容を4x4のfloatとして取得 m.getColumnMajor44(matA);
「NxMat34」を作成した初期段階では、単位行列が入っています。「m.getColumnMajor44(matA);」により、float型16個分(4x4個分)の配列に内容を持ってくることができます。
[ matA[0] matA[1] matA[2] matA[3] ] = [ 1 0 0 0 ] [ matA[4] matA[5] matA[6] matA[7] ] = [ 0 1 0 0 ] [ matA[8] matA[9] matA[10] matA[11] ] = [ 0 0 1 0 ] [ matA[12] matA[13] matA[14] matA[15] ] = [ 0 0 0 1 ]
ただし、「matA[3] / matA[7] / matA[11] / matA[15]」に相当する部分は常に「0, 0, 0, 1」が入ることになります。
逆に、値を変更したい場合は
matA[0] = 1.0f; matA[1] = 0.0f; matA[2] = 0.0f; matA[3] = 0.0f; matA[4] = 0.0f; matA[5] = 1.0f; matA[6] = 0.0f; matA[7] = 0.0f; matA[8] = 0.0f; matA[9] = 0.0f; matA[10] = 1.0f; matA[11] = 0.0f; matA[12] = 3.0f; matA[13] = 5.0f; matA[14] = 4.0f; matA[15] = 1.0f; m.setColumnMajor44(matA);
のように「setColumnMajor44」を使用します。これでmに対して行列値を指定することになります。ただし、「matA[3] / matA[7] / matA[11] / matA[15]」での値は無視されます。
行列の値の取り出し・取得は、getColumnMajor44 / setColumnMajor44を利用するようにしてください。
単位行列を指定
NxMat34 m; m.id();
NxMat34型であるmが定義された段階では単位行列が入っているのですが、改めて単位行列を入れたい場合があります。その場合は「m.id();」のように指定すると行列mは単位行列で初期化されます。
行列の乗算
NxMat34 m, m2, m3; // ここでm / m2に何らかの値を代入したとする... m3 = m * m2;
このように、普通の乗算と同様に計算できます。
行列とベクトルの乗算
NxVec3 v, v2; NxMat34 m; // mに何らかの変換行列を入れるとする... v = NxVec3(1.0f, 2.0f, 3.0f); v2 = m * v;
3x4行列にXYZ要素を持つベクトルを掛けて、結果をNxVec3型で返します。行列 * ベクトルの乗算はOKですが、ベクトル * 行列の乗算は不可です。
逆行列の計算
NxMat34 m, m2; // mに何らかの変換行列を入れるとする... bool ret = m.getInverse(m2);
3x4の行列mを逆行列計算し、結果をm2に代入します。処理に成功すると、戻り値はtrueを返します。
すでに回転の行列が正規直交であると分かっている場合は、転置するだけで済みます。この場合は、
ret = m.getInverseRT(m2);
のほうが素早く計算できます。
Future's Laboratory 技術格納庫 2004-2013 Yutaka Yoshisaka.