スクリプトガイド > 3Dシーン > 行列スタックの使用
公開日: 11/25/2021

行列スタックの使用

JMPの3Dシーンでは、行列スタックを使って、現在の変換を継続してトラッキングします。スタックは、単位行列に初期化されます。そして、移動、回転、または拡大や縮小のコマンドが指定されるたびに、スタックの最上部の行列が変更されます。

メモ: 多くのOpenGL実装とは異なり、JMPでは転置行列は使いません。

次のプログラム例では、Push MatrixPop Matrixを使って「toy top」の各部分の位置を決めています。各部分を指定した後には、原点に戻っています。この方法を使うと、Translateコマンドを2回使って元に戻すよりも速く処理できます。

図13.15 行列スタックを使った描画 

Drawing With a Matrix Stack

toyTop = Scene Display List();
toyTop << Push Matrix;
toyTop << Translate( 0, 0, .1 );
toyTop << Color( 1, 0, 0 ); // red
 

// baseRadius、topRadius、height、slices、stacksを指定する

toyTop << Cylinder( 1, .2, .2, 25, 5 );
toyTop << Pop Matrix;
toyTop << Push Matrix;
toyTop << Translate( 0, 0, -.1 );
toyTop << Rotate( 180, 1, 0, 0 );
toyTop << Color( 0, 1, 0 ); // 緑
toyTop << Cylinder( 1, .2, .2, 25, 5 );
toyTop << Pop Matrix;
 
toyTop << Color( 0, 0, 1 ); // 青
toyTop << Sphere( .5, 30, 30 ); // radius、slices、stacksを指定する
 
toyTop << Color( 1, 1, 0 ); // 黄色
 

// innerRadius、outerRadius、slices、rings、startAngle、sweepAngleを指定する

toyTop << Partial Disk( 1, 1.2, 25, 2, 0, 270 );
 
toyTop << Push Matrix;
toyTop << Translate( 0, 0, -.1 );
toyTop << Color( 1, 0, 1 ); // マゼンタ
toyTop << Cylinder( 1, 1, .2, 25, 3 );
 

// baseRadius、topRadius、height、slices、stacksを指定する

toyTop << Pop Matrix;
 
toyTop << Push Matrix;
toyTop << Rotate( 90, 1, 0, 0 );
toyTop << Translate( 0, .5, 0 );
toyTop << Color( 0, 1, 1 ); // シアン
toyTop << Text( "center", "baseline", .2, "Toy Top" );
toyTop << Pop Matrix;
 
scene = Scene Box( 600, 600 ); // OpenGLシーンを保持するScene Boxを作成する
 
New Window( "例3", scene ); // シーンをウィンドウに配置する
scene << Perspective( 45, 3, 7 );
scene << Translate( 0.0, 0.0, -4.5 );
scene << Rotate( -85, 1, 0, 0 );
scene << Rotate( 65, 0, 0, 1 );
scene << Call List( toyTop );
 
scene << Update; // ディスプレイボックスを更新する

スタック上の現在の行列を変更したい場合は、Load Matrixコマンドを使います。

Load Matrix(m)

mは、現在の行列スタックにロードされる4行4列のJMP行列です。

同様なコマンドにMult Matrixがあります。

Mult Matrix(m)

Mult Matrixコマンドを実行すると、現在の行列スタックの最上部の行列にmが乗算されます。

次に、簡単なコマンドを実行する行列の例を示します。

移動

 [1  0  0  x
 0  1  0  y
 0  0  1  z
 0  0  0  1]

次の回転用行列に対する説明において、cはcos(a)、sはsin(a)です(ここで、aは回転の角度です)。

X軸を中心にして回転

 [1  0  0  0
 0  c -s  0
 0 -s  c  0
 0  0  0  1]

Y軸を中心にして回転

 [c  0  s  0
 0  1  0  0
-s  0  c  0
 0  0  0  1]

Z軸を中心にして回転

 [c -s  0  0
 s  c  0  0
 0  0  1  0
 0  0  0  1]

例として、表示リストを移動して回転する2通りの方法を示します。初めの例は行列を用いており、2番目の例はTranslateとRotateを用いています。初めの例は、2番目の例と反対の方向に移動します。

// 行列を使った方法

gl << Push Matrix;
xt = Identity( 4 ); // これを0.75だけ左方向に移動する
xt[1, 4] = -.75;
xr = Identity( 4 ); // これを回転する。cosは度ではなくラジアンで指定する
xr[2, 2] = Cos( 3.14159 * a / 180 );
xr[2, 3] = -Sin( 3.14159 * a / 180 );
xr[3, 2] = Sin( 3.14159 * a / 180 );
xr[3, 3] = Cos( 3.14159 * a / 180 );
yr = Identity( 4 );
yr[1, 1] = Cos( 3.14159 * a / 180 );
yr[1, 3] = Sin( 3.14159 * a / 180 );
yr[3, 1] = -Sin( 3.14159 * a / 180 );
yr[3, 3] = Cos( 3.14159 * a / 180 );
zr = Identity( 4 );
zr[1, 1] = Cos( 3.14159 * a / 180 );
zr[1, 2] = -Sin( 3.14159 * a / 180 );
zr[2, 1] = Sin( 3.14159 * a / 180 );
zr[2, 2] = Cos( 3.14159 * a / 180 );
 

// 行列では乗算の順序が重要

gl << Mult Matrix( xt * xr * yr * zr );
gl << Arcball( dl, 1 );
gl << Pop Matrix;
 

// 関数を使った方法

gl << Push Matrix;
gl << Translate( .75, 0, 0 ); // これを0.75だけ右方向に移動する
gl << Rotate( a, 1, 0, 0 ); // これを度単位で回転させる
gl << Rotate( a, 0, 1, 0 ); // ここでは演算子の順序も重要
gl << Rotate( a, 0, 0, 1 );
gl << Arcball( dl, 1 );
gl << Pop Matrix;

行列は、表示リストの描画中にだけ保持されているので、以前の変換行列を遡って読み取ることはできません。以前の変換行列を知る必要がある場合には、JSL変数としてその行列を保持しておき、Load Matrixを使ってその行列をスタック上に置きます。

より詳細な情報が必要な場合や、質問があるときは、JMPユーザーコミュニティで答えを見つけましょう (community.jmp.com).