コンテンツ メディア プログラミング実習 Ⅰ コンピュータグラフィックス編 1 幾何変換 橋本直
今日大事なのは プログラムをじっくり読んで なぜそうなるか? を考えよう 命令によって起きていることを頭の中でイメージしよう 2
本題の前に確認 Processingでは画面の 左上隅 が原点 (0,0) x 軸の正の向きは 右 y 軸の正の向きは 下 x y : (0,0) 3
幾何変換の基本 4
幾何変換とは (Geometric Transformation) 図形の位置や姿勢 変形を表現する変換のこと 平 移動 回転 拡大縮小 反転 せん断 CG ゲーム ロボティクス 画像計測 VR AR などの分野でとても重要なテクニック! Processingのコードで説明しますが CG プログラミング 般の概念です
平 移動 平 移動の命令 translate( x 向の移動量, y 向の移動量 ); void setup() { size(300, 200); 150 100 void draw() { translate( 150, 100 ); ellipse( 0, 0, 80, 80 ); x 150 y 100 (0,0) 80, 80 Q. 6
回転 回転の命令 rotate( 回転角度 ); 原点中 に時計回りの回転 角度はラジアンで指定 void setup() { size(300, 200); 10 void draw() { rotate( radians(10) ); rect( 0, 0, 150, 100 ); 150 100 10 (0,0) 150 100 Q. 7
拡大縮小 拡大縮小の命令 scale( x 向の拡大率, y 向の拡大率 ); 拡大率は1.0で等倍 void setup() { size(300, 200); void draw() { scale( 2.0, 1.0 ); rect( 50, 50, 80, 80 ); x 2 (50, 50) 80 80 Q. 8
反転 反転処理は scale() に負の値を指定することで う scale( -1, 1 ); 左右反転 scale( 1, -1 ); 上下反転 scale( -1, -1 ); 上下左右反転 PImage img; void setup() { size( 300, 200 ); img = loadimage("meiji.png"); meiji.png void draw() { translate( 200, 50 ); scale( -1, 1 ); image( img, 0, 0 ); Q. 9
せん断 せん断の命令 shearx(α); x 向にせん断 (α は角度 ) sheary(β); y 向にせん断 (βは角度) 角度はラジアン単位で指定 shearx() と sheary() は Processing2.0 以降の機能 x x β y α y 10
せん断 PImage img; void setup() { size(300,200); img = loadimage("meiji.png"); void draw() { shearx( radians(30) ); image(img, 0, 0); 30 11
幾何変換で起きていること 実は 図形そのものが移動 変形しているのではない! 図形がおかれている座標系が移動 変形した結果として 図形が移動 変形したように えている y x 12
すなわち translate() 座標系を平 移動 rotate() 座標系を回転 scale() 座標系を拡大縮小 反転 shearx() 座標系をx 向に歪ませる sheary() 座標系をy 向に歪ませる もう 度個々のプログラムを てみよう 13
幾何変換の 組み合わせ 14
幾何変換のルール 1 幾何変換をした後でさらに幾何変換を うと効果が組み合わさる 2 幾何変換の順番によって処理結果が異なる場合がある 回転してから平 移動 平 移動してから回転 3 般的な CG のプログラムにおいて 幾何変換を うと 特に指定がない限りその効果が継続し それ以降に描く図形はすべてその変換の影響を受ける 15
連続的な平 移動 for 文で連続的に translate() をやる例を てみよう なぜこうなるか考えてみよう 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
解説 for 文の処理を分解して考えてみよう i=0 のとき i=4 のとき fill(0*20, 0, 0); fill(4*20 0 0) rect(0, 0, 30, 30); translate(40, 40); fill(4*20, 0, 0); rect(0, 0, 30, 30); translate(40, 40); fill(1*20, 0, 0); rect(0, 0, 30, 30); translate(40, 40); i=1 のとき i=5 のとき fill(5*20, 0, 0); rect(0, 0, 30, 30); translate(40, 40); i=2 のとき fill(2*20, 20, 0, 0); rect(0, 0, 30, 30); translate(40, 40); ( 中略 ) fill(3*20, 0, 0); fill(9*20, 0, 0); rect(0, 0, 30, 30); rect(0, 0, 30, 30); translate(40, t 40); translate(40, 40); i=3 のとき i=9 のとき 17
translate() した後でさらにtranslate() すると 座標系がどんどん移動していく 四角形を (0, 0) に描いてるつもりでも 座標系が動いてるので 実際の描画位置はずれていく i=0 のとき i=1 のとき translate(40, 40) translate(40, 40) i=2 のとき i=3 のとき translate(40, 40) 18
回転と平 移動の組み合わせ 次のプログラムをよく読んで なぜそのような結果になるのか推理してみよう 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); rotate(radians(30)); translate(60, 0); Q. 19
解説 座標系を 30 度回転させた後で x 向に 60 平 移動 を繰り返しながら四角形を描いている 1 translate(200, 50) 2 rotate(radians(30) 3 translate(60, 0) 20
回転してから平 移動 と 平 移動してから回転 は異なる 結果を比較してみよう void setup() { size(400, 400); void draw() { background(200); rotate(radians(45)); translate(200, 100); void setup() { size(400, 400); void draw() { background(200); translate(200, 100); rotate(radians(45)); rect(0, 0, 160, 80 ); rect(0, 0, 160, 80 ); 21
幾何変換の効果はいつまで保持 される? Processing において 幾何変換の効果が保持されるのはdraw() の最後の まで 次にdraw() が実 される時に 前回までの幾何変換の効果はリセットされる すなわち draw() の開始時点において 座標系の原点は左上隅にあり 平 移動や回転はされていない状態になる 22
列スタック 23
幾何変換を物体ごとに指定したい 幾何変換を繰り返していくと座標系の状態はどんどんど複雑になっていく このままでは複数のオブジェクトを個別に異なる位置姿勢で配置したいときに不便 例えば ゲーム中でキャラクタ A B C がそれぞれ異なる位置と向きにいるようなシーン A 原点から平 移動と回転を繰り返して A B C を順番に描いていくのは非常に面倒 24
列スタック オブジェクト群に対する幾何変換を階層的に表現できる 列スタック と呼ばれる手法を使う CGの世界では 幾何変換の情報は内部的に 列 に格納されていて それを スタック というデータ構造で管理しているのでこう呼ぶ 列スタックの命令 pushmatrix() 実 すると その時点の幾何変換の状態を保存する popmatrix() pushmatrix() で保存した時点の幾何変換の状態を呼び出す 25
pushmatrix() と popmatrix() 使い 幾何変換と描画命令の組を pushmatrix() と popmatrix() ではさむ 必ず対にする pushmatrix(); translate(120, 120); rotate(radians(10)); ( rect(0, 0, 50, 50); popmatrix(); p 26
void setup() { size(300, 200); 使 例 void draw() { pushmatrix(); translate(40, 40); rotate(radians(0)); rect(0, 0, 50, 50); popmatrix(); pushmatrix(); translate(200, 30); rotate(radians(40)); rect(0, 0, 50, 50); popmatrix(); pushmatrix(); translate(120, 120); rotate(radians(10)); rect(0, 0, 50, 50); popmatrix(); 27
階層的な幾何変換 pushmatrix() と popmatrix() は入れ子構造にすることができる 連動する座標系を扱えるようになる 移動する乗り物やリフトの上でさらに人が移動しているようなシーンや 人やロボットの関節のようにリンク構造を持つ物体においてこのような 法を使う 28
階層的な幾何変換の例 pushmatrix(); translate( ); rotate( ); drawlift(); pushmatrix(); translate( ); rotate( ); drawhumana(); popmatrix(); A B pushmatrix(); translate( ); rotate( ); drawhumanb(); popmatrix(); d H B() A B A B A B popmatrix(); 29
課題 1( スケッチ名 :mouse) マウスカーソル上で大きさ 100x100の正 形が回転するプログラムを作りなさい ただし 正 形の中 がマウスカーソルの位置になるようにすること
課題 2( スケッチ名 :tworects) 画面内に2 個の回転する 100x50の 形を描くプログラムを作りなさい 回転中 は 形の中 とし は時計回りに もう は反時計回りに回転させること
課題 3( スケッチ名 :twocircles) 2つの円が 直径 200の円軌道上を移動するプログラムを作りなさい
応 編 ( スケッチ名 :coffeecup) 余裕のある人は 遊園地にある コーヒーカップ を模したプログラムに挑戦してください カップが乗っている床全体を回転させ なおかつ個々のカップも回転させること Photo from http://ja.wikipedia.org/wiki/ コーヒーカップ _( 遊具 )