コンテンツコンテンツ メディア・メディア...
TRANSCRIPT
コンテンツ・メディアコンテンツ メディアプログラミング実習Ⅰ
コンピュータグラフィックス編①コンピュ タグラフィックス編①幾何学的変換
橋本 直橋本 直
今日大事なのは…今日大事なのは…
プログラムをじっくり読んで「なぜそうなるか?」を考えようを考えよう。
書かれ 命令によ 起き とを頭 中書かれている命令によって起きていることを頭の中でイメージできるようになろう。
2
本題の前に確認本題の前に確認がProcessingでは画面の【左上隅】が原点 (0, 0)
x軸の正方向は【右】y軸の正方向は【下】
x軸
左上隅が原点: (0, 0)y軸
3
幾何学的変換幾何学的変換
4
幾何学的変換とは幾何学的変換とは(Geometric Transformation)
図形の位置や姿勢、変形を表現する変換のこと◦ 平⾏移動、回転、拡⼤縮⼩、反転など◦ CGはもちろん、ゲーム、画像計測、VR/AR、ロボティクスな
どの分野で必須どの分野で必須
今 次 幾何学的変換 扱今日は2次元の幾何学的変換を扱います。◦ 3次元の幾何学的変換は「CG基礎」や「コンピュータビジョ
ン」 講義ン」の講義で。
平⾏移動平⾏移動⾏移動 命令平⾏移動の命令
translate( x方向の移動量, y方向の移動量 );( 移動 , y 移動 );
void setup() {size(300, 200);
}150
100}
void draw() {t l t ( 150 100 ) ①translate( 150, 100 );ellipse( 0, 0, 80, 80 );
}
①②
① x方向に150、y方向に100 平行移動 Q 何が起きている?6
y② (0, 0)を中心に幅80, 高さ80の円を描画 Q. 何が起きている?
回転回転回転 命令回転の命令rotate( 回転角度 );( );◦ 原点中⼼に時計回りの回転。角度の単位はラジアンで指定。
void setup() {size(300, 200); 10°size(300, 200);
}
void draw() {
10
void draw() {rotate( radians(10) );rect( 0, 0, 150, 100 );
} 幅150高さ100の四角形①②
} 幅 高 角形
① 時計回りに10度回転
7Q. 図形の回転中心はどこ?
① 時計回りに10度回転② (0,0)に幅150、高さ100の四角形を描画
拡大・縮小拡大・縮小拡⼤ 縮⼩ 命令拡⼤・縮⼩の命令scale( x方向の拡⼤率, y方向の拡⼤率 );( , y );◦ 拡⼤率は1.0で等倍。
void setup() {size(300 200);size(300, 200);
}
id d () {void draw() {scale( 2.0, 1.0 );rect( 50, 50, 80, 80 );
①②
}
Q 位置もずれている?① x方向を2倍に拡大
②
8
Q. 位置もずれている?なぜこうなる?
① x方向を2倍に拡大② (50, 50)に幅80、高さ80の四角形を描画
反転(鏡映)反転(鏡映)反転は scale() に負の値を指定することで⾏う反転は 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. なぜ平行移動させている?
せん断せん断せん断の命令せん断の命令shearX(α); … x方向にせん断(αは角度)( );shearY(β); … y方向にせん断(βは角度)
◦ 角度はラジアン単位で指定。◦ shearX()とshearY()はProcessing2 0以降の機能◦ shearX()とshearY()はProcessing2.0以降の機能。
xx
β
α
10yy
せん断せん断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
ここで起きていることここで起きていること図形が個別に移動 変形しているわけではない図形が個別に移動・変形しているわけではない。描画の基準となる「座標系」が移動・変形している。
x
yx
y
キャンバスの上に格子状の枠が置かれている様子を想像してみよう。この絵描きは 格子を基準に絵を描こうとするので 格子がずれていたり 傾
12
絵描きは、格子を基準に絵を描こうとするので、格子がずれていたり、傾いていたり、歪んでいたりすると、それが結果に影響する。
すなわちすなわちtranslate() … 座標系を平⾏移動rotate() … 座標系を回転rotate() … 座標系を回転scale() … 座標系を拡⼤・縮⼩・反転shearX() … 座標系をx方向に歪ませるshearY() … 座標系をy方向に歪ませるshearY() … 座標系をy方向に歪ませる
もう⼀度個々のプログラムを⾒てみよう
13
幾何学的変換の組み合わせ
14
幾何学的変換のルール幾何学的変換のルール①変換を⾏った後でさらに変換を⾏うと効果が組み合
わさる。
②変換の順番によって処理結果が異なる場合がある。「回転してから平⾏移動」≠「平⾏移動してから回転」
③CGのプログラムでは⼀般的に 幾何学的変換を⾏う③CGのプログラムでは⼀般的に、幾何学的変換を⾏うと、特に指定がない限りはその効果が継続し、それ以降に⾏うすべての図形描画処理に影響を及ぼす以降に⾏うすべての図形描画処理に影響を及ぼす。
15
連続的な平⾏移動連続的な平⾏移動f 文 連続的に l ()をや 例を⾒ ようfor文で連続的にtranslate()をやる例を⾒てみよう。なぜこのような結果になるのだろうか?
void setup() {size(400 400);size(400, 400);
}
id d () {void draw() {background(150);
for (int i=0; i<10; i++) {fill(i*20, 0, 0);rect(0, 0, 30, 30);ect(0, 0, 30, 30);translate(40, 40);
}}
16
}
解説解説for文で⾏われる処理を丁寧に追ってみよう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);
translate()した後でさらにtranslate()すると、座() ()標系がどんどん移動していく。四角形を(0, 0)に描いてるつもりでも、座標系が動四角形を( , )に描 てる もりでも、座標系が動いてるので、実際の描画位置はずれていく。
translate(40, 40)
i=0のとき
translate(40, 40)
l ( )
i=1のとき
translate(40, 40)
i=2のとき
translate(40, 40)i=3のとき
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);rect(0, 0, 40, 40);rotate(radians(30));translate(60, 0);
} Q 最初に描かれる四角形は
19
}}
Q. 最初に描かれる四角形はどれだろうか?
解説解説「座標系を30度回転させた後でx方向に60平⾏移動」を「座標系を30度回転させた後でx方向に60平⾏移動」を繰り返しながら四角形を描いている。
① translate(200, 50)
② rotate(radians(30))
③
translate(60, 0)
③
( )
20
「回転してから平⾏移動」と回転してから平⾏移動」と「平⾏移動してから回転」は 異なる
結果を比較してみよう
回転してから平行移動 平行移動してから回転
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
} }
幾何学的変換の効果はいつまで幾何学的変換の効果はいつまで保持される?保持される?
Processingにおいて 幾何学的変換の効果が保持さProcessingにおいて、幾何学的変換の効果が保持されるのはdraw()の最後の⾏まで。
次にdraw()が実⾏される時に、前回までの幾何学的変換の効果はリセットされる。的変換の効果はリセットされる。
すなわち、draw()の開始時点において、座標系の()原点は左上隅にあり、平⾏移動や回転はされていない状態になる。
22
数学的な話数学的な話
23
線形変換線形変換右式で表わされる変換 ⎟
⎞⎜⎛⎟⎞
⎜⎛
⎟⎞
⎜⎛ ′ xbax右式で表わされる変換
⾏列のパラメータの置き方によって効果が異なる
⎟⎟⎠
⎞⎜⎜⎝
⎛⎟⎟⎠
⎞⎜⎜⎝
⎛=⎟⎟
⎠
⎞⎜⎜⎝
⎛′ y
xdcba
yx
によって効果が異なる ⎠⎝⎠⎝⎠⎝ yyこの式は「座標値(点)を動かしている」と解釈することもできるが、
ここでは「座標系を変形させている」と考えよう。
⎞⎛ 0 ⎞⎛ θθ i拡大・縮小 回転 y軸対称
⎞⎛ 01 ⎞⎛ 01x軸対称
⎟⎟⎠
⎞⎜⎜⎝
⎛
y
x
ss0
0⎟⎟⎠
⎞⎜⎜⎝
⎛ −θθθθ
cossinsincos
⎟⎟⎠
⎞⎜⎜⎝
⎛−1001
⎟⎟⎠
⎞⎜⎜⎝
⎛−1001
⎠⎝ y ⎠⎝ θθ cossin ⎠⎝ 10 ⎠⎝ 10
x方向のせん断 y方向のせん断x方向のせん断 y方向のせん断
⎟⎟⎞
⎜⎜⎛ tan1 α
⎟⎟⎞
⎜⎜⎛ 01
24
⎟⎟⎠
⎜⎜⎝ 10 ⎟⎟
⎠⎜⎜⎝ 1tan β
平⾏移動平⾏移動次式 表わされ 変換次式で表わされる変換
⎟⎟⎞
⎜⎜⎛
+⎟⎟⎞
⎜⎜⎛
=⎟⎟⎞
⎜⎜⎛ ′ xtxx
⎟⎟⎠
⎜⎜⎝
+⎟⎟⎠
⎜⎜⎝
=⎟⎟⎠
⎜⎜⎝ ′ ytyy
この式についても「座標値(点)を動かしている」と解釈することもき が は「座標系を移動さ と考 よできるが、ここでは「座標系を移動させている」と考えよう。
25
アフィン変換アフィン変換任意 線形変換と平⾏移動を組 合わせた任意の線形変換と平⾏移動を組み合わせた変換
⎞⎛⎞⎛⎞⎛⎞⎛ ′ tb⎟⎟⎠
⎞⎜⎜⎝
⎛+⎟⎟⎠
⎞⎜⎜⎝
⎛⎟⎟⎠
⎞⎜⎜⎝
⎛=⎟⎟
⎠
⎞⎜⎜⎝
⎛′′ x
tt
yx
dcba
yx
⎟⎠
⎜⎝
⎟⎠
⎜⎝⎟⎠
⎜⎝
⎟⎠
⎜⎝ ytydcy
平⾏移動線形変換 平⾏移動(拡⼤・縮⼩、回転、反転、
せん断など)
26
さらにまとめるとさらにまとめると
⎤⎡⎤⎡⎤⎡ ′ xtbax
⎥⎥⎤
⎢⎢⎡
⎥⎥⎤
⎢⎢⎡
=⎥⎥⎤
⎢⎢⎡′ y
xtdctba
yx
y
x
⎥⎥⎦⎢
⎢⎣⎥⎥⎦⎢
⎢⎣⎥
⎥⎦⎢
⎢⎣ 11001
yy y
◦ 次元が1つ増えているが、これは同次座標表現と呼ばれる形。この
⎦⎣⎦⎣⎦⎣次元が1つ増えているが、これは同次座標表現と呼ばれる形。この形のおかげで平⾏移動も含めたすべての変換を1つの⾏列で表現できる。
◦ CGの世界では、座標系の状態は「⾏列」という単位で管理される。◦ 現在の⾏列 (current matrix) =現在の座標系の状態を表わす⾏列
27
「現在の⾏列」の中⾝を⾒てみる「現在の⾏列」の中⾝を⾒てみるi i ()printMatrix()
◦ 実⾏時点の座標系の状態を表わす⾏列の要素をコンソールに表示する(2次元の場合は⾏列の1〜2⾏目のみ表示)
void setup() {size(300, 200);
}
001.0000 000.0000 100.0000000.0000 001.0000 200.0000
}
void draw() {t l t (100 200)
000.7071 -000.7071 100.0000000.7071 000.7071 200.0000
translate(100,200);printMatrix();rotate( radians(45) ); ⎤⎡⎤⎡⎤⎡ ′ xtbaxprintMatrix();
}⎥⎥⎥
⎦
⎤
⎢⎢⎢
⎣
⎡
⎥⎥⎥
⎦
⎤
⎢⎢⎢
⎣
⎡=
⎥⎥⎥
⎦
⎤
⎢⎢⎢
⎣
⎡′
11001yx
tdctba
yx
y
x
28
⎥⎦⎢⎣⎥⎦⎢⎣⎥⎦⎢⎣ 11001
合成変換合成変換平⾏移動し そ 後回転し さらにそ 後に平⾏移動して、その後回転して、さらにその後に拡⼤して…というような連続的な変換の過程は、数式上は⾏列のかけ算として表わされる数式上は⾏列のかけ算として表わされる。
「現在の⾏列」に後ろからかけていく
⎥⎤
⎢⎡
⎥⎤
⎢⎡
⎥⎤
⎢⎡ −
⎥⎤
⎢⎡
⎥⎤
⎢⎡ ′ 000sincos01 xstx xx θθ
⎥⎥⎥
⎦⎢⎢⎢
⎣⎥⎥⎥
⎦⎢⎢⎢
⎣⎥⎥⎥
⎦⎢⎢⎢
⎣⎥⎥⎥
⎦⎢⎢⎢
⎣
=⎥⎥⎥
⎦⎢⎢⎢
⎣
′
110000
1000cossin
10010
1ysty yy θθ⎥⎦⎢⎣⎥⎦⎢⎣⎥⎦⎢⎣⎥⎦⎢⎣⎥⎦⎢⎣ 11001001001
①x方向にtx
②θだけ回転
③x方向をsx倍x方向にtx,
y方向にty平⾏移動
θだけ回転 x方向をsx倍、y方向をsy倍に拡⼤
29⾏列は掛け算の順序で結果が異なる場合がある → 幾何変換の順序で結果が変わることがある
⾏列スタック⾏列スタック
30
座標系を前の状態に戻したい座標系を前の状態に戻したいCGの世界では 幾何学的変換を⾏うことで座標系CGの世界では、幾何学的変換を⾏うことで座標系の状態を操り、CGを任意の場所に配置したり、変形したりする形したりする。
座標系の状態を「前の状態」に戻したい!という座標系の状態を 前の状態」に戻したい ということがたびたび出てくる。
例)①
例)平⾏移動と回転によって座標系を②の位置に動かした。
②③そこから平⾏移動して③の位置
に物体Aを配置した。物体Bを配置するにあたり ②の物体Bを配置するにあたり、②の座標系を基準として移動・回転したいので、いったん②の状態
31
に戻りたい(③からの相対的な移動を考えるのは面倒)
⾏列スタック⾏列スタックオブジ クト群に対す 幾何学的変換を階層的に表現オブジェクト群に対する幾何学的変換を階層的に表現できる「⾏列スタック」と呼ばれる手法を使う。◦ 幾何学的変換の情報は内部的に「⾏列」で管理されている。それ
を「スタック」というデータ構造で管理しているのでこう呼ぶ。
⾏列スタックの命令pushMatrix()pushMatrix()◦ 実⾏すると、その時点の⾏列(座標系の状態)をスタックに保存
する 現在の⾏列の内容は現状維持する。現在の⾏列の内容は現状維持。
popMatrix()p p ()◦ pushMatrix()で保存した時点の⾏列をスタックから取り出し、そ
れを現在の⾏列とする。
32
pushMatrix()とpopMatrix()pushMatrix()とpopMatrix()使 方使い方◦ 幾何学的変換と描画命令の組をpushMatrix()とp ()
popMatrix()ではさむ。これらは必ず対にする。
pushMatrix(); ① この時点での座標系の状態(行列)を保存する
p ()translate(120, 120);rotate(radians(10)); ② 幾何学的変換
状態(行列)を保存する
rect(0, 0, 50, 50);popMatrix();
③ 描画命令④ さきほど保存した座標系の状態(行列)を復活させる状態(行列)を復活させる
※字下げはしなくてもよいが したほうが構造がわかりやすくなる
33
※字下げはしなくてもよいが、したほうが構造がわかりやすくなる。
void setup() {size(300, 200);
} 使⽤例}
void draw() {
使⽤例
pushMatrix();translate(40, 40);rotate(radians(0));rect(0, 0, 50, 50);
popMatrix();popMatrix();
pushMatrix();translate(200 30);translate(200, 30);rotate(radians(40));rect(0, 0, 50, 50);
popMat i () いずれの物体も スクリ ンの左上popMatrix();
pushMatrix();
いずれの物体も、スクリーンの左上端を起点とした位置に個別に配置できている。
translate(120, 120);rotate(radians(10));rect(0, 0, 50, 50);
ゲームプログラムにおいて、フィールド内にいろいろなオブジェクトを
34
( , , , );popMatrix();
}配置する際に必要なるテクニック。
階層的な変換階層的な変換pushMatrix()とpopMatrix()は入れ子構造にすることができる。 ⇒ 連動する座標系を扱えるようになる。
移動する乗り物やリフトの上でさらに人が移動しているようなシ ンや 人やロボ トの関節のようにリンるようなシーンや、人やロボットの関節のようにリンク構造を持つ物体においてこのような方法を使う。
35ゲームによくある「動く床」 多関節のロボット
階層的な変換の例階層的な変換の例
pushMatrix();translate( … );translate( );rotate( … );drawLift(); BApushMatrix();
translate( … );rotate( … ); 動く床drawHumanA();
popMatrix();
pushMatrix();translate( … );rotate( … );d H B() 床 人A 人Bがそれぞれ座標系をdrawHumanB();
popMatrix();
popMatrix();
床、人A、人Bがそれぞれ座標系を持っている。床が回転すると、人Aと人Bはその影響を受ける。
36
popMatrix(); と人Bはその影響を受ける。
課題1(スケッチ名:mouse)課題1(スケッチ名:mouse)ウ カ ル上 ⼤きさ 正方形が回マウスカーソル上で⼤きさ100x100の正方形が回
転するプログラムを作りなさい。ただし、正方形の中⼼がマウスカーソルの位置になるようにすること。translate()とrotate()をう
組 合まく組み合わせよう。
課題2(スケッチ名:tworects)課題2(スケッチ名:tworects)画面内に 個 回転す ⻑方形を描くプ グ画面内に2個の回転する100x50の⻑方形を描くプログラムを作りなさい。回転中⼼は⻑方形の中⼼とし、⽚方は時計回りに、もう⼀方は反時計回りに回転させること。
時計回り 反時計回り時計回り 反時計回り
課題3(スケッチ名:twocircles)課題3(スケッチ名:twocircles)グ2つの円が、直径200の円軌道上を移動するプログラ
ムを作りなさい。移動する円は軌道上で点対称な位置(反対側) 置く と(反対側)に置くこと。
円軌道
応⽤①(スケッチ名:coffeecup)応⽤①(スケッチ名:coffeecup)
余裕 あ 人は 遊園地にあ 「 ヒ カ プ」を模余裕のある人は、遊園地にある「コーヒーカップ」を模したプログラムに挑戦してください。カップが乗っている床全体を回転させ、なおかつ個々のカップも回転させること。
コーヒーカップ
人Photo from http://ja.wikipedia.org/wiki/コーヒーカップ_(遊具)
応⽤②(スケッチ名:symmetry)応⽤②(スケッチ名:symmetry)
対称構造を持 幾何学模様を簡単に描け プ グ ム対称構造を持つ幾何学模様を簡単に描けるプログラムを作ってみよう。
◦ イラスト用のドローソフトでは「対称定規」という名前でこの「対称定規」という名前でこの機能が搭載されていることも。
◦ translate() rotate() scale()◦ translate(), rotate(), scale()をうまく組み合わせて対称な位置に線を引こう。どこを中⼼と
値 がする座標値を扱うかが肝。
◦ ヒント:pmouseX, pmouseYp pを使うと、前フレームのマウスカーソル座標が得られて線を引くのに便利
41
くのに便利。