マニュアル

導入手順

必要なヘッダは swizzle_vmath.hpp のみです。 また、一連の機能は SwizzleVmath という名前空間上に定義されています。 リンクが必要なコードは一切ありません。

つまり、ソース冒頭に
	#include "swizzle_vmath.hpp"
	using namespace SwizzleVmath ;
の 2 行を追加すれば、導入完了です。

ベクトルについて

  • ベクトルの宣言方法
    ベクトルの宣言は、次のように行います。
    	VecN_t vecA ;
    
    N の位置には、次元数を書きます。次元数は、1 〜 4 が指定できます。

    ベクトル宣言時に、ベクトルに保持させる値を指定できます。 以下のような、いくつかのスタイルが利用できます。

    • ベクトルの各成分を指定する
      最大 4 つの成分を指定できます。
      	Vec4_t vecA(1,2,3,4);
      
      	Vec3_t vecB(1,2,3);
      
    • ベクトルの次元数と一致する配列を引数として与える
      	float paramA[4] = {1,2,3,4};
      	Vec4_t vecA(paramA);
      
      	float paramB[3] = {1,2,3};
      	Vec3_t vecB(paramB);
      
    • すでに作成されているベクトルからコピーする
      	Vec4_t vecB(vecA);
      
  • ベクトル成分の参照方法
    任意の成分を参照するには、次のように記述します。
    	vecA.aVal[要素番号]
    
    x y z w の名前で参照するには、次のように記述します。
    	vecA.x()
    	vecA.y()
    	vecA.z()
    	vecA.w()
    
    r g b a の名前で参照するには、次のように記述します。
    	vecA.r()
    	vecA.g()
    	vecA.b()
    	vecA.a()
    
    いずれも、float 型の値と見なされます。

  • ベクトル同士の演算
    例えば、ベクトル同士の加算は次のように記述します。 ベクトルの全成分に対する並列加算が実行され、 vecA には (6,8,10,12) が得られます。
    	Vec4_t vecB(1,2,3,4);
    	Vec4_t vecC(5,6,7,8);
    	Vec4_t vecA = vecB + vecC ;
    
    同様に、並列減算、並列乗算、並列除算が記述できます。
    	vecA = vecB - vecC ;
    	vecA = vecB * vecC ;
    	vecA = vecB / vecC ;
    
  • 符号反転
    '-' を付けることで符号反転が可能です。 次の例では、vecA には (-1,-2,-3,-4) が得られます。
    	Vec4_t vecB(1,2,3,4);
    	Vec4_t vecA = -vecB ;
    
  • swizzle 指定方法
    演算対象のメンバを swizzle 指定メソッドで指定可能です。
    	vecA.xyzw()     演算対象 = x y z w
    	vecA.rgba()     演算対象 = r g b a
    	vecA.xxyy()     演算対象 = x x y y
    	vecA.gb()       演算対象 = g b
    
    swizzle 指定を行うとどのような解釈が行われるかの例を、次に示します。
    	Vec4_t vecA(1,2,3,4);
    	vecA.xyzw() => ベクトル(1,2,3,4) と見なされる。
    	vecA.rgba() => ベクトル(1,2,3,4) と見なされる。
    	vecA.xyz()  => ベクトル(1,2,3) と見なされる。
    	vecA.xyxy() => ベクトル(1,2,1,2) と見なされる。
    	vecA.aa()   => ベクトル(4,4) と見なされる。
    	vecA.x()    => float 値 (1) と見なされる。
    	vecA.y()    => float 値 (2) と見なされる。
    	vecA.z()    => float 値 (3) と見なされる。
    	vecA.w()    => float 値 (4) と見なされる。
    	vecA.r()    => float 値 (1) と見なされる。
    	vecA.g()    => float 値 (2) と見なされる。
    	vecA.b()    => float 値 (3) と見なされる。
    	vecA.a()    => float 値 (4) と見なされる。
    
    具体的には、次のように用います。
    	Vec4_t vecB(1,2,3,4);
    	Vec4_t vecC(5,6,7,8);
    	Vec4_t vecA;
    	vecA.wzyx() = vecB.xyxy() + vecC.zwzw() ;
    
    この記述は、
    	vecA.w() = vecB.x() + vecC.z() ;
    	vecA.z() = vecB.y() + vecC.w() ;
    	vecA.y() = vecB.x() + vecC.z() ;
    	vecA.x() = vecB.y() + vecC.w() ;
    
    のように解釈されるので、vecA には (10,8,10,8) が得られます。

    ここで注意が必要なのが、宣言時の次元数と、 swizzle 指定部の次元数は、 必ずしも一致させる必要はないということです。 例えば、次のように 4 次元ベクトルとして宣言しておいて、 2 次元ベクトルとして操作を行うことができます。
    	Vec4_t vecA(1,2,3,4);
    	Vec4_t vecB(5,6,7,8);
    	vecA.wx() = vecB.yz() ;
    
    この記述は、
    	vecA.w() = vecB.y();
    	vecA.x() = vecB.z();
    
    のように解釈されるので、vecA には (7,2,3,6) が得られます。

  • ブロードキャスト演算について
    ベクトルの全フィールドに対して、 スカラ値との演算を行うことを、 ブロードキャスト演算と呼ぶことにします。

    次の例は、ベクトルの全成分を 2 倍するブロードキャスト乗算です。
    	vecA.xyz() *= 2.0f ;
    
    この記述は、
    	vecA.x() *= 2.0f ;
    	vecA.y() *= 2.0f ;
    	vecA.z() *= 2.0f ;
    
    のように解釈されます。

    同様に、ブロードキャスト除算が記述できます。
    	vecA.xyz() /= vecA.w() ;
    
    ブロードキャスト除算は、内部的には高速化のため、 引数の逆数をブロードキャスト乗算する仕様になっています。 よってこの記述は、
    	float Tmp = 1.0f / vecA.w() ;
    	vecA.x() *= Tmp ;
    	vecA.y() *= Tmp ;
    	vecA.z() *= Tmp ;
    
    のように解釈されます。

行列について

  • 行列の宣言方法
    行列の宣言は、次のように行います。
    	MatNxM_t matA ;
    
    N M の位置には、次元数を書きます。次元数は、1 〜 4 が指定できます。

    行列宣言時に、行列に保持させる値を指定できます。 以下のような、いくつかのスタイルが利用できます。

    • 行列の各成分を指定する
      最大 16 個の成分を指定でき、 省略した部分には 0 を指定したものとみなされます。
      	Mat4x4_t    matA(
      	              1, 2, 3, 4
      	            , 5, 6, 7, 8
      	            , 9,10,11,12
      	            , 13,14,15,16
      	            );
      
      4x4 以下の行列でも、次の様に 16 個のパラメータを要求します。 次の例では、 2x3 部分(1 〜 6 が指定されている部分)以外は無視されます。
      	Mat2x3_t    matB(
      	              1, 2, 3, 0
      	            , 4, 5, 6, 0
      	            , 0, 0, 0, 0
      	            , 0, 0, 0, 0
      	            );
      
    • 行列の次元数と一致する配列を引数として与える
      	float paramA[4][4]
      	=   {
      	        { 1, 2, 3, 4}
      	    ,   { 5, 6, 7, 8}
      	    ,   { 9,10,11,12}
      	    ,   {13,14,15,16}
      	    };
      	Mat4x4_t matA(paramA);
      
      	float paramB[2][3]
      	=   {
      	        { 1, 2, 3}
      	    ,   { 4, 5, 6}
      	    };
      	Mat2x3_t matB(paramB);
      
    • すでに作成されている行列からコピーする
      	Mat4x4_t MatB(MatA);
      
  • 行列成分の参照方法
    任意の成分を参照するには、次のように記述します。
    	matA.aaVal[行番号][列番号]
    
    指定の行を、行ベクトルとしてアクセスするには、 次のように記述します。
    	matA.rRow(行番号)
    
  • 行列同士の演算
    加算減算については、各成分に対する並列の演算となります。
    	Mat4x4_t    matB(
    	                1,1,1,1
    	            ,   1,1,1,1
    	            ,   1,1,1,1
    	            ,   1,1,1,1
    	            );
    	Mat4x4_t    matC(
    	                2,2,2,2
    	            ,   2,2,2,2
    	            ,   2,2,2,2
    	            ,   2,2,2,2
    	            );
    	Mat4x4_t    matA = matB + matC ;
    
    上記の例では、matA には、
    	 3,3,3,3
    	,3,3,3,3
    	,3,3,3,3
    	,3,3,3,3
    
    が得られます。

    乗算については、行列の積が得られます。 例えば、Local → World 行列と、World → Screen 行列を合成して、 Local → Screen 行列を作成するには、次のように記述します。
    	matLocalToScreen = matLocalToWorld * matWorldToScreen ;
    
    ベクトルを行ベクトルとして扱うので、掛け順序に注意してください。

    なお、行列の除算は用意されていません。

  • 行列とベクトルの演算
    ベクトルを行列で変換することが出来ます。 例えば、Local → Screen 行列を使って、 Local 座標を Screen 座標に変換するには、 次のように記述します。
    	vecScreen = vecLocal * matLocalToScreen ;
    
    ベクトルを行ベクトルとして扱うので、掛け順序に注意してください。

  • 演算対象の行数列数の指定方法
    演算対象の行数列数を指定することが可能です。 具体的には、'.m' + 行次元数 + 'x' + 列次元数 + '()' というメソッドで、 指定の行数列数の参照を取得します。 例えば、次のようにします。
    	matA.m4x4()         4x4 行列
    	matA.m3x2()         3x2 行列
    	matA.m1x4()         1x4 行列
    
    ベクトルの場合と同様に、 行列の宣言時の次元数と、行数列数指定部の次元数は、 必ずしも一致させる必要はありません。 例えば次のように、4x4 行列として宣言しておき、 3x3 行列とみなして演算することが可能です。
    	Mat4x4_t    matA( 省略 );
    	Vec4_t      vecA( 省略 );
    	Vec4_t      vecB( 省略 );
    	vecB.xyz() = vecA.xyz() * matA.m3x3() ;
    
    このような演算は、4x4 行列で 3 次元の回転+平行移動を表現している場合に、 回転のみの変換結果を得たい場合に利用できます。

  • 符号反転
    '-' を付けることで符号反転が可能です。
    	Mat4x4_t    matB(
    	                 1, 2, 3, 4
    	            ,    5, 6, 7, 8
    	            ,    9,10,11,12
    	            ,   13,14,15,16
    	            );
    	Mat4x4_t    matA = -matB ;
    
    上記の例では、matA には、
    	  -1, -2, -3, -4
    	, -5, -6, -7, -8
    	, -9,-10,-11,-12
    	,-13,-14,-15,-16
    
    が得られます。

  • ブロードキャスト演算について
    ベクトルと同様、行列の全要素に対して、 スカラ値との並列演算を行うような演算が可能です。

    詳細は、ベクトルのブロードキャスト演算の項目を参照してください。

算術関数について

3D 分野で良く用いられる一般的な算術関数が用意されています。

  • Dot
    内積の計算を行います。
    	Vec3_t vecA(1,0,0);
    	Vec3_t vecB(0,1,0);
    	float Result = Dot( vecA , vecB );
    
    vecA と vecB は直交しているので、Result は 0 となります。

  • Cross
    3 次元の外積の計算を行います。
    	Vec3_t vecB(1,0,0);
    	Vec3_t vecC(0,1,0);
    	Vec3_t vecA = Cross( vecB , vecC );
    
    vecA は (0,0,1) となります。

  • Length2
    各成分の 2 乗の和を求めます。
    	Vec4_t vecA(1,1,1,1);
    	float Result = Length2( vecA );
    
    Result は 4 になります。

  • Length
    各成分の 2 乗の和の平方根を求めます。
    	Vec4_t vecA(1,1,1,1);
    	float Result = Length( vecA );
    
    Result は 2 になります。

  • Max
    ベクトルの成分ごとの最大値を求めます。
    	Vec4_t vecB(1,2,3,4);
    	Vec4_t vecC(4,3,2,1);
    	Vec4_t vecA = Max( vecB , vecC );
    
    vecA は (4,3,3,4) になります。

  • Min
    ベクトルの成分ごとの最小値を求めます。
    	Vec4_t vecB(1,2,3,4);
    	Vec4_t vecC(4,3,2,1);
    	Vec4_t vecA = Min( vecB , vecC );
    
    vecA は (1,2,2,1) になります。

  • Clamp
    ベクトルの成分ごとのクランプ結果を求めます。
    	Vec4_t vecB(0,1,2,3);
    	Vec4_t vecMin(1,1,1,1);		/* 成分ごとの下限 */
    	Vec4_t vecMax(2,2,2,2);		/* 成分ごとの上限 */
    	Vec4_t vecA = Clamp( vecB , vecMin , vecMax );
    
    vecA は (1,1,2,2) になります。

  • Abs
    ベクトルの成分ごとの絶対値を求めます。
    	Vec4_t vecB(-1,0,1,2);
    	Vec4_t vecA = Abs( vecB );
    
    vecA は (1,0,1,2) になります。

  • Lerp
    ベクトルの線形補間を行います。
    	Vec4_t vecB(0,1,2,3);
    	Vec4_t vecC(0,3,6,9);
    	Vec4_t vecA = Lerp( vecB , vecC , 0.5f );
    
    vecA は (0,2,4,6) になります。

  • Normalize
    ベクトルの正規化を行います。
    	Vec3_t vecB(1,2,3);
    	Vec3_t vecA = Normalize( vecB );
    
    vecA = vecA / Length( vecA ); と同じ効果が得られます。

  • Transpose
    行列の転置を行います。
    	Mat4x4_t    matA(
    	                 1, 2, 3, 4
    	            ,    5, 6, 7, 8
    	            ,    9,10,11,12
    	            ,   13,14,15,16
    	            );
    	matA.m3x3() = Transpose( matA.m3x3() );
    
    上記の例では、matA には、
    	  1, 5, 9, 4
    	, 2, 6,10, 8
    	, 3, 7,11,12
    	,13,14,15,16
    
    が得られます。

  • Inverse
    転置と平行移動を用いた逆行列計算を行います。
    	Mat4x4_t    matA(
    	                 1, 2, 3, 4
    	            ,    5, 6, 7, 8
    	            ,    9,10,11,12
    	            ,   13,14,15,16
    	            );
    	matA = Inverse( matA );
    
    上記の例では、matA には、
    	  1, 5, 9, 0
    	, 2, 6,10, 0
    	, 3, 7,11, 0
    	,-86,-254,-422,1
    
    が得られます。


注意事項

本項目では、注意事項についてまとめます。 すでに触れた内容についても、改めてまとめます。

  • 次元数に矛盾のある処理を記述してはならない
    次元数に矛盾のある処理を記述しても、 コンパイル段階ではエラーとならず、 実行結果は不定となります。 (大抵は、矛盾のある要素を 0 に置き換えて処理が成されます。)

    次元数に矛盾のある処理とは、例えば以下のようなものを指します。

    • 次元数拡張
      次の例では、3 次元ベクトルをコピーして、4 次元ベクトルを作成しています。
      	Vec3_t vecA(1,2,3);
      	Vec4_t vecB(vacA);
      
      正しく記述するには、次のようにします。
      	Vec3_t vecA(1,2,3);
      	Vec4_t vecB ;
      	vecB.xyz() = vecA.xyz();
      	vecB.w() = 0 ;
      
    • swizzle 指定による次元数拡張
      3 次元ベクトルに対して、 4 次元ベクトルの swizzle 指定を行っています。
      	Vec3_t vecA(1,2,3);
      	Vec4_t vecB = vecA.xyzw();
      
    • 次元の一致しない演算(ベクトルの例)
      	Vec4_t vecA(1,2,3,4);
      	Vec4_t vecB(5,6,7,8);
      	Vec4_t vecC ;
      	vecC.xyzw() = vecA.xyz() + vecB.xy();
      
    • 次元の一致しない演算(行列の例)
      	matC.m4x4() = matA.m2x4() * matB.m2x4();
      
    • 次元の一致しない演算(演算関数の例)
      Cross 関数は、3 次元ベクトルを入力として受け取り、 3 次元ベクトルを返すので、次のような記述は誤りです。
      	Vec4_t vecA(1,2,3,4);
      	Vec4_t vecB(5,6,7,8);
      	Vec4_t vecC ;
      	vecC.xy() = Cross( vecA.xy() , vecB.xy() );
      
  • 演算の優先度に配慮する
    ベクトルと行列の関わる計算は、式の解釈順序により、 実行速度が大きく異なってくる場合があります。

    非推奨
    	Vec4_t matA(省略);
    	Vec4_t matB(省略);
    	Vec4_t vecA(1,2,3,4);
    	Vec4_t vecB = vecA * matA * matB ;
    
    推奨
    	Vec4_t matA(省略);
    	Vec4_t matB(省略);
    	Vec4_t vecA(1,2,3,4);
    	Vec4_t vecB = (vecA * matA) * matB ;
    
    「非推奨」の側では、 乗算処理部にて vecB = vecA * (matA * matB) と解釈されているため、 演算コストは

    • 行列 対 行列 の乗算 1 回
    • ベクトル 対 行列 の乗算 1 回

    であるのに対して、「推奨」の側では、 演算コストは

    • ベクトル 対 行列 の乗算 2 回

    と、軽くなっています。