座標保存の基礎
この項では、3Dグラフィックスにおける重要な概念である、座標の保存(pushMatrix, popMatrix)を解説します。
まず、以下のグラフィックを書いてみてください。

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 → 保存した座標を再展開する。
使い方は以下の通りです。
前のコードに書き足してみましょう。

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個作成します。
先ほどの項でやったものに似ていますが、ポイントは、回転の中心軸を中央にするということです。

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方向にも増やします。

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方向にも増やします。

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();
}
}
}
}
回転の保存

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