3. 座標の保存 – pushMatrix, popMatrix(processing 3D入門)

座標保存の基礎

この項では、3Dグラフィックスにおける重要な概念である、座標の保存(pushMatrix, popMatrix)を解説します。

まず、以下のグラフィックを書いてみてください。

sample3_1

1
2
3
4
5
6
7
8
9
10
11
12
size(400, 400, P3D);
background(0);
 
//赤い直方体
fill(255, 0, 0);    
translate(100, 100, 0);
box(50, 50, 1);    //直方体を描く
 
//緑の直方体
fill(0, 255, 0);    
translate(200, 200, 0);
box(100, 100, 1);    //直方体を描く

ここで、translateが2回使われています。
結果を見てみると分かりますが、座標が足されていて、2つ目のboxの中心点は、x = 300, y = 300です。
これは、つまり相対座標になるので、絶対座標で指定したい場合もあるでしょう。というかむしろその方が多いといえます。
ここで、pushMatrixとpopMatrixという概念が出てきます。

pushMatrix → 現在の座標を保存する。
popMatrix → 保存した座標を再展開する。

使い方は以下の通りです。
前のコードに書き足してみましょう。

sample3_2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
size(400, 400, P3D);
background(0);
 
//赤い直方体
fill(255, 0, 0);    
pushMatrix();    //現在の座標を保存
translate(100, 100, 0);
box(50, 50, 1);    //直方体を描く
popMatrix();    //元の座標に戻す
 
//緑の直方体
fill(0, 255, 0);    
pushMatrix();    //現在の座標を保存
translate(200, 200, 0);
box(100, 100, 1);    //直方体を描く
popMatrix();    //元の座標に戻す

座標保存の応用

それでは、次は応用編としてboxをたくさん複製してみましょう。

まずは、下図のように書いてみてください。X軸方向に6個作成します。
先ほどの項でやったものに似ていますが、ポイントは、回転の中心軸を中央にするということです。

sample3_3_1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
float boxSize = 20;    //立方体のサイズ
float distance = 30;    //立方体同士の距離
float halfDis;    //立方体同士の一辺の全体の距離の半分
int boxNum = 6;    //立方体の数
 
void setup(){
  size(400, 400, P3D);
  halfDis = distance*(boxNum-1)/2;    //6個並んだ際の距離の半分
}
 
void draw(){
  background(0);
  stroke(255, 0, 0, 100);
  line(width/2, 0, width/2, height);
  line(0, height/2, width, height/2);
 
  translate(width/2, height/2);    //立体の中心を画面中央に移動   
  rotateY(radians(mouseX));
  rotateX(radians(mouseY));
 
  stroke(0);
  fill(255);    
 
  for(int x = 0; x < boxNum; x ++){    //立方体を、x軸方向に30ピクセルごとに並べて6個生成
    pushMatrix();
    translate(x*distance-halfDis, 0, 0);
    box(boxSize, boxSize, boxSize);    //20 x 20 x 20pxの立方体を描く
    popMatrix();
  }
}

それができたら、Y方向にも増やします。

sample3_3_2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
float boxSize = 20;    //立方体のサイズ
float distance = 30;    //立方体同士の距離
float halfDis;    //立方体同士の一辺の全体の距離の半分
int boxNum = 6;    //立方体の数
 
void setup(){
  size(400, 400, P3D);
  halfDis = distance*(boxNum-1)/2;    //6個並んだ際の距離の半分
}
 
void draw(){
  background(0);
  stroke(255, 0, 0, 100);
  line(width/2, 0, width/2, height);
  line(0, height/2, width, height/2);
 
  translate(width/2, height/2);    //立体の中心を画面中央に移動   
  rotateY(radians(mouseX));
  rotateX(radians(mouseY));
 
  stroke(0);
  fill(255);    
 
  for(int y = 0; y < boxNum; y ++){    //立方体を、y軸方向に30ピクセルごとに並べて6個生成  
    for(int x = 0; x < boxNum; x ++){    //立方体を、x軸方向に30ピクセルごとに並べて6個生成
      pushMatrix();
      translate(x*distance-halfDis, y*distance-halfDis, 0);
      box(boxSize, boxSize, boxSize);    //20 x 20 x 20pxの立方体を描く
      popMatrix();
    }
  }
}

この要領で、Z方向にも増やします。

sample3_3_3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
float boxSize = 20;    //立方体のサイズ
float distance = 30;    //立方体同士の距離
float halfDis;    //立方体同士の一辺の全体の距離の半分
int boxNum = 6;    //立方体の数
 
void setup(){
  size(400, 400, P3D);
  halfDis = distance*(boxNum-1)/2;    //6個並んだ際の距離の半分
}
 
void draw(){
  background(0);
  stroke(255, 0, 0, 100);
  line(width/2, 0, width/2, height);
  line(0, height/2, width, height/2);
 
  translate(width/2, height/2);    //立体の中心を画面中央に移動   
  rotateY(radians(mouseX));
  rotateX(radians(mouseY));
 
  stroke(0);
  fill(255, 255, 255);    
 
  for(int z = 0; z < boxNum; z ++){    //立方体を、z軸方向に30ピクセルごとに並べて6個生成  
    for(int y = 0; y < boxNum; y ++){    //立方体を、y軸方向に30ピクセルごとに並べて6個生成  
      for(int x = 0; x < boxNum; x ++){    //立方体を、x軸方向に30ピクセルごとに並べて6個生成
        pushMatrix();
        translate(x*distance-halfDis, y*distance-halfDis, z*distance-halfDis);
        box(boxSize, boxSize, boxSize);    //20 x 20 x 20pxの立方体を描く
        popMatrix();
      }
    }
  }
}

回転の保存

sample3_4

回転の場合も前述のサンプルと考え方は一緒です。一つのオブジェクトを回転させるたびに、pushMatrixとpopMatrixを使えば、x, y, z座標はそのままでそれぞれ回転してくれます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//Y軸を中心に回転する立方体
 
void setup(){
  size(400, 400, P3D);
}
 
void draw(){
  background(0);
 
  for(int i = 0; i < 3; i++){ 
    pushMatrix();
    translate((i+1)*100, height/2);    //立体の中心を移動 
    rotateY(radians(mouseX));    //Y軸に対してangleの数値分だけ回転
    box(50, 50, 50);    //50 x 50 x 50pxの立方体を描
    popMatrix();
  }
}