座標保存の基礎
この項では、3Dグラフィックスにおける重要な概念である、座標の保存(pushMatrix, popMatrix)を解説します。
まず、以下のグラフィックを書いてみてください。
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 → 保存した座標を再展開する。
使い方は以下の通りです。
前のコードに書き足してみましょう。
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個作成します。
先ほどの項でやったものに似ていますが、ポイントは、回転の中心軸を中央にするということです。
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方向にも増やします。
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方向にも増やします。
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(); } } } } |
回転の保存
回転の場合も前述のサンプルと考え方は一緒です。一つのオブジェクトを回転させるたびに、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(); } } |