コンテンツ・メディア
コンテンツ メディア
プログラミング実習Ⅰ
コンピュータグラフィックス編①
幾何変換
幾何変換
橋本 直
今日大事なのは…
今日大事なのは…
y
プログラムをじっくり読んで「なぜそうなる
か?」を考えよう
か?」を考えよう。
y
命令によって起きていることを頭の中でイメ
ージしよう
ージしよう。
2本題の前に確認
本題の前に確認
が
y
Processingでは画面の【左上隅】が原点 (0,0)
y
x軸の正の向きは【右】
x軸の正の向きは【右】
y
y軸の正の向きは【下】
x軸
左上隅が原点
: (0,0)
y軸
3幾何変換の基本
幾何変換の基本
幾何変換とは
幾何変換とは
(Geometric Transformation)y
図形の位置や姿勢、変形を表現する変換のこと
⾏移動
◦
平⾏移動
◦
回転
回転
◦
拡大縮小
転
◦
反転
◦
せん断
せん断
y
CG、ゲーム、ロボティクス、画像計測、VR、ARなど
の分野でとても重要なテクニック!
y
Processingのコードで説明しますが、CGプログラミン
Processingのコ ドで説明しますが、CGプログラミン
グ⼀般の概念です。
平⾏移動
平⾏移動
⾏移動 命令
y
平⾏移動の命令
translate(
x⽅向の移動量 y⽅向の移動量
);
translate(
x⽅向の移動量
,
y⽅向の移動量
);
void setup() { size(300, 200); } 150 100 } void draw() { 100 translate( 150, 100 ); ellipse( 0, 0, 80, 80 ); } ① ② } ① x方向に150、y方向に100 平行移動Q 何が起きている?
6 ① x方向に150、y方向に100 平行移動 ② (0,0)を中心に幅80, 高さ80の円を描画Q. 何が起きている?
回転
回転
回転 命令
y
回転の命令
rotate(
回転角度
);
rotate(
回転角度
);
◦
原点中⼼に時計回りの回転。角度はラジアンで指定。
void setup() { i (300 200) 10° size(300, 200); } 10° void draw() { rotate( radians(10) ); rect( 0, 0, 150, 100 ); ①② 幅150高さ100の四角形 rect( 0, 0, 150, 100 ); } ② 幅150高さ100の四角形 7Q. 図形の回転中心はどこ?
① 時計回りに10度回転 ② (0,0)に幅150、高さ100の四角形を描画拡大縮小
拡大縮小
拡大縮小 命令
y
拡大縮小の命令
scale(
x⽅向の拡大率 y⽅向の拡大率
);
scale(
x⽅向の拡大率
,
y⽅向の拡大率
);
◦
拡大率は1.0で等倍。
void setup() { i (300 200) size(300, 200); } void draw() { scale( 2.0, 1.0 ); rect( 50, 50, 80, 80 );① ② rect( 50, 50, 80, 80 ); }Q 位置もずれている?
① 方向を2倍に拡大 ② 8Q. 位置もずれている?
なぜこうなる?
① x方向を2倍に拡大 ② (50, 50)に幅80、高さ80の四角形を描画反転
反転
y
反転処理は scale() に負の値を指定することで⾏う
y
反転処理は scale() に負の値を指定することで⾏う
scale(
-1
,
1
); … 左右反転
l (
1 1
)
上下反転
scale(
1
,
-1
); … 上下反転
scale(
-1
,
-1
); … 上下左右反転
PImage img; void setup() { size( 300, 200 ); img = loadImage("meiji.png"); img = loadImage( meiji.png ); } void draw() { void draw() { translate( 200, 50 ); scale( -1, 1 ); i ( i 0 0 ) 9 image( img, 0, 0 ); } Q. なぜ平行移動させている?せん断
せん断
せん断の命令
y
せん断の命令
shearX(
α
); … x⽅向にせん断(αは角度)
shearX(
α
);
x⽅向にせん断(αは角度)
shearY(
β
); … y⽅向にせん断(βは角度)
◦
角度はラジアン単位で指定。
◦
shearX()とshearY()はProcessing2 0以降の機能
◦
shearX()とshearY()はProcessing2.0以降の機能。
x
x
β
α
10y
y
せん断
せん断
PImage img; void setup() { void setup() { size(300,200); img = loadImage("meiji.png"); }} void draw() { h ( di (30) ) shearX( radians(30) ); image(img, 0, 0); }}30°
11幾何変換で起きていること
幾何変換で起きていること
y
実は、図形そのものが移動・変形している
のではない!
のではない
y
図形がおかれている座標系が移動・変形し
y
図形がおかれている座標系が移動 変形し
た結果として、図形が移動・変形したよう
に⾒えている
に⾒えている。
x
y
12すなわち
すなわち
y
translate() … 座標系を平⾏移動
otate()
座標系を回転
y
rotate()
… 座標系を回転
y
scale()
scale()
… 座標系を拡大縮小・反転
座標系を拡大縮小 反転
y
shearX()
… 座標系をx⽅向に歪ませる
y
shearY()
… 座標系をy⽅向に歪ませる
もう⼀度個々のプログラムを⾒てみよう
13幾何変換の
組み合わせ
幾何変換のルール
幾何変換のルール
①幾何変換をした後でさらに幾何変換を⾏うと
効果が組み合わさる。
効果が組み合わさる。
②幾何変換の順番によって処理結果が異なる場
②幾何変換の順番によって処理結果が異なる場
合がある。
「回転してから平⾏移動」≠「平⾏移動してから回転」
「回転してから平⾏移動」≠「平⾏移動してから回転」
③⼀般的なCGのプログラムにおいて 幾何変
③ 般的なCGのプログラムにおいて、幾何変
換を⾏うと、特に指定がない限りその効果が
継続し それ以降に描く図形はすべてその変
継続し、それ以降に描く図形はすべてその変
換の影響を受ける。
15連続的な平⾏移動
連続的な平⾏移動
f 文 連続的
l
()をや 例を⾒
y
for文で連続的にtranslate()をやる例を⾒てみ
よう。なぜこうなるか考えてみよう。
void setup() { void setup() { size(400, 400); } void draw() { background(150);for (int i=0; i<10; i++) { fill(i*20, 0, 0); rect(0, 0, 30, 30); translate(40, 40); } 16 } }
解説
解説
y
for文の処理を分解して考えてみよう
y
for文の処理を分解して考えてみよう
fill(0*20 0 0); fill(4*20 0 0)i 0 のとき
fill(0*20, 0, 0);とき
rect(0, 0, 30, 30); translate(40, 40); fill(4*20, 0, 0); rect(0, 0, 30, 30); translate(40, 40);i=0 のとき
i=4 のとき
fill(1*20, 0, 0);rect(0, 0, 30, 30); fill(5*20, 0, 0);rect(0, 0, 30, 30);
i=1 のとき
i=5 のとき
( ) translate(40, 40); fill(2*20, 0, 0); rect(0, 0, 30, 30); translate(40, 40);i=2 のとき
fill(2 20, 0, 0); rect(0, 0, 30, 30); translate(40, 40);(中略)
i=2 のとき
fill(3*20, 0, 0); rect(0, 0, 30, 30); t l t (40 40) fill(9*20, 0, 0); rect(0, 0, 30, 30); translate(40 40);i=3 のとき
i=9 のとき
17 translate(40, 40); translate(40, 40);y
translate()した後でさらにtranslate()すると、
()
()
座標系がどんどん移動していく
y
四角形を(0 0)に描いてるつもりでも 座標系
y
四角形を(0, 0)に描いてるつもりでも、座標系
が動いてるので、実際の描画位置はずれていく
translate(40, 40) i=0のとき translate(40, 40) l ( ) i=1のとき translate(40, 40) i=2のとき translate(40, 40) i=3のとき 18回転と平⾏移動の組み合わせ
回転と平⾏移動の組み合わせ
次のプログラムをよく読んで なぜそのような結果に
y
次のプログラムをよく読んで、なぜそのような結果に
なるのか推理してみよう。
void setup() { size(350,350); }} void draw() { background(200); translate(200, 50);for (int i=0; i<12; i++) { fill(i*20, 0, 0); rect(0 0 40 40); rect(0, 0, 40, 40); rotate(radians(30)); translate(60, 0); }
Q 最初に描かれる四角形は
19 } }Q. 最初に描かれる四角形は
どれだろうか?
解説
解説
y
「座標系を30度回転させた後でx⽅向に60平⾏
y
「座標系を30度回転させた後でx⽅向に60平⾏
移動」を繰り返しながら四角形を描いている。
① translate(200, 50) ② rotate(radians(30) ③ translate(60, 0) ③ ( ) 20「回転してから平⾏移動」と
回転してから平⾏移動」と
「平⾏移動してから回転」は 異なる
y
結果を比較してみよう
回転してから平行移動 平行移動してから回転 void setup() { size(400, 400); } void setup() { size(400, 400); } } void draw() { background(200); } void draw() { background(200); background(200); rotate(radians(45)); translate(200 100); background(200); translate(200, 100); rotate(radians(45)); translate(200, 100); rect(0, 0, 160, 80 ); } rotate(radians(45)); rect(0, 0, 160, 80 ); } 21 } }幾何変換の効果はいつまで保持
幾何変換の効果はいつまで保持
される?
される?
P ocessingにおいて 幾何変換の効果が保持
y
Processingにおいて、幾何変換の効果が保持
されるのは
draw()の最後の⾏まで。
y
次にdraw()が実⾏される時に、前回までの幾
何変換 効
何変換の効果はリセットされる。
始時点
座標
y
すなわち、draw()の開始時点において、座標
系の原点は左上隅にあり、平⾏移動や回転はさ
れていない状態になる。
22⾏列スタック
⾏列スタック
幾何変換を物体ごとに指定したい
幾何変換を物体ごとに指定したい
幾何変換を繰り返
く 座標系 状態 ど ど
y
幾何変換を繰り返していくと座標系の状態はどんどん
複雑になっていく。このままでは複数のオブジェクト
を個別に異なる位置姿勢で配置したいときに不便
を個別に異なる位置姿勢で配置したいときに不便。
y
例えば、ゲーム中で
キャラクタA・B・Cが
A
キャラクタA B Cが
それぞれ異なる位置と向き
にいるようなシ ン
A
にいるようなシーン。
y
原点から平⾏移動と回転を繰り返してA、B、Cを順番
に描いていくのは非常に面倒。
24⾏列スタック
⾏列スタック
オブジ クト群に対す 幾何変換を階層的に表現 き
y
オブジェクト群に対する幾何変換を階層的に表現でき
る「⾏列スタック」と呼ばれる手法を使う。
y
CGの世界では、幾何変換の情報は内部的に「⾏列」に
格納されていて、それを「スタック」というデータ構
造 管
呼ぶ
造で管理しているのでこう呼ぶ。
y
⾏列スタックの命令
pushMatrix()
pushMatrix()
◦
実⾏すると、その時点の幾何変換の状態を保存する。
popMatrix()
popMatrix()
◦
pushMatrix()で保存した時点の幾何変換の状態を呼
び出す
び出す。
25pushMatrix()とpopMatrix()
pushMatrix()とpopMatrix()
使 ⽅
y
使い⽅
◦
幾何変換と描画命令の組をpushMatrix()と
◦
幾何変換と描画命令の組をpushMatrix()と
popMatrix()ではさむ。必ず対にする。
pushMatrix();
① この時点での幾何変換の状態を保存するpushMatrix();
translate(120, 120);
rotate(radians(10));
② 幾何変換
の状態を保存する(
( ));
rect(0, 0, 50, 50);
popMatrix();
③ 描画命令
④ さきほど保存した幾何p p
();
変換の状態を復活させる 26 ※字下げはしなくてもよいが、したほうが構造がわかりやすくなる。void setup() { size(300, 200); }