Push 'n Pop
前回は挑戦して別のものが出来上がってしまいました。
今回は本来やりたかったことのやり方がわかったので覚書として書いておこうと思います。
まずは繰り返しで画面上に円を配置
void setup(){
size(800, 600, P3D);
noStroke();
}
void draw(){
background(0);
for(int x = 150; x < width-100; x += 100){
for(int y = 100 ; y < height-50; y += 100){
ellipse(x, y, 50, 50);
}
}
}
for の繰り返しを使用してイイ感じに円を配置。間隔は感覚で。
これを3D方向に回転させていきます。
回転にはrotate()を使いますが、このrotateは座標(0, 0)を中心として回転するので、『任意の座標をを中心として回転!』ということができません。最初につまづいていたのはここです。
それぞれを回転させたいということはこの一つ一つの円の中心を(0, 0)にするようなコードが必要になります。translateを使うのはなんとなくわかるのですが、問題はそれをどこにいれるか。
void setup(){
size(800, 600, P3D);
noStroke();
}
void draw(){
background(0);
translate(width/2, height/2);
rotate(radians(mouseX));
for(int x = 150; x < width-100; x += 100){
for(int y = 100 ; y < height-50; y += 100){
ellipse(x, y, 50, 50);
}
}
}
画面の中心を原点にするとこうなります。
ではこれを繰り返しの中に入れてはどうか?
void setup(){
size(800, 600, P3D);
noStroke();
}
void draw(){
background(0);
translate(width/2, height/2);
for(int x = 150; x < width-100; x += 100){
rotate(radians(mouseX));
for(int y = 100 ; y < height-50; y += 100){
ellipse(x, y, 50, 50);
}
}
}
整列していたものがバラバラになってしまいました。結局原点を変えていないので回転は依然として画面の中心を基点にしています。
void setup(){
size(800, 600, P3D);
noStroke();
}
void draw(){
background(0);
for(int x = 150; x < width-100; x += 100){
for(int y = 100 ; y < height-50; y += 100){
ellipse(x, y, 50, 50);
translate(x, y);
rotate(radians(mouseX));
}
}
}
ではこの繰り返しの円の中心として設定しているx, yをtranslate()にいれてはどうか?これはいけそうな気がする!!
おお。全然いけてない。
push matrix, pop matrix
と、ここでタイトルのpush matrix, pop matrixの出番です。
この関数は現在の座標を保存し、別の座標を呼び出し、また以前にあったものに戻す。という作業ができます。どういうことになるか見てみましょう。
下記のコードは四角の描画とtranslate()を繰り返したものです。順に追うと、
①(100, 100)の位置に一辺が50の四角
②次に座標(100, 100)を原点にする。これ以降のコードの基点はここになる。
③一辺が100の四角。位置は原点(0, 0)なので、②の位置に描かれる。①の座標と実質変わらない位置のため、同じ位置に大きい四角が描かれる
④再度座標の設定。②と同じ関数だが、②の時点で座標の位置が変わっているので、この時点での座標位置は一つめのtranslate(100, 100)が加算されている分になる。原点は(200, 200)のにある。
void setup(){
size(800, 600);
noFill();
}
void draw(){
rect (100, 100, 50, 50);
translate(100, 100);
rect (0, 0, 100, 100);
translate(100, 100);
rect (0, 0, 100, 100);
}
少しわかりやすいようにガイドを引きました。交点が座標変更をする前の(100, 100)、(200, 200)の位置になります。
これでも問題はないんですが、translateを繰り返すとどんどん加算されてしまっていくということです。元の座標を覚えていられなさそう。。。。
pushとpopを使うと、変更する座標の範囲を指定することができます。実際に使ってみましょう。
void setup(){
size(800, 600);
noFill();
}
void draw(){
stroke(255);
line(0, 100, width, 100);
line(100, 0, 100, height);
line(0, 200, width, 200);
line(200, 0, 200, height);
stroke(0);
rect (100, 100, 50, 50);
pushMatrix();
translate(100, 100);
rect (0, 0, 100, 100);
popMatrix();
translate(100, 100);
rect (0, 0, 100, 100);
}
①(100, 100)の位置に一辺が50の四角
pushMatrix(); これで現在の座標[=(0, 0)が原点]を保存します
②次に座標(100, 100)を原点にする。これ以降のコードの基点はここになる。
③一辺が100の四角。位置は原点(0, 0)なので、②の位置に描かれる。①の座標と実質変わらない位置のため、同じ位置に大きい四角が描かれる
popMatrix(); 保存した座標を呼び出します
④再度座標の設定。popMatrix();によって一番初めの(0,0)が原点の座標に戻っています。なので以前のように座標位置は加算されず、②と同じことが繰り返されることになります。なので最後の四角は同じ位置になるので線だけの描画では重なって見えません。
push Matrix とpopMatrixは二つセットで使用されます。上記の例で見たように挟まれた部分に新しい座標位置が適用されます。これを利用して冒頭の並んだ円を個別に回転させてみましょう。
void setup(){
size(800, 600, P3D);
noStroke();
}
void draw(){
background(0);
for(int x = 150; x < width-100; x += 100){
for(int y = 100 ; y < height-50; y += 100){
pushMatrix();
translate(x, y);
rotateX(radians(mouseX));
ellipse(0, 0, 50, 50);
popMatrix();
}
}
}
繰り返しの中にtranslateとpush,popMatrixを入れました。
まずpushMatrixで一番初めの座標が保存されます[原点= 0, 0]
そのままのrotateでは回転がわからない(円なので当然)ので、X方向の回転であるrotateXに変更しました。回転はマウスの動きに反応するようにmousXを入れました。次に円を描きます。一回目の円は[x=150, y= 100]の位置。冒頭ではxとyの位置にしていましたが、ここではtranslateによってx,yの位置は移動するので指定する必要がありません。なので原点での描画になっています。最後にpopMatrixによって保存された座標が呼び出されます。
その後繰り返しのループに入ります。二回目は(250, 200)を原点とし、円が描画されます。以降は同様です。
これで最初に行われていたバラバラになってしまう理由もわかりました。(それとtranslateとrotateの順番もバラバラでした。。。。)座標が記録されないことにより、加算代入で増えていく座標は等間隔で並ばずにどんどん広くなってしまい、バラバラになります。push pop Matrixがあることにより、最初の座標位置が保存(固定)され、そこが基準になるため崩れることなく円が描画できます。
もっと感覚的に
回転はできましたが、動かしてみると違和感があります。
横に動かすと円は縦方向に回転します。これだとマウスで円を動かしている感覚にはなりません。この場合X とYを逆にする必要があります。
完成です。
XとYを逆にすることに関してはまた別の機会に。
この記事が気に入ったらサポートをしてみませんか?