コンテンツ メディアコンテンツ・メディア...
Post on 06-Jun-2020
6 Views
Preview:
TRANSCRIPT
コンテンツ メディアコンテンツ・メディアプログラミング実習Ⅰプログラミング実習Ⅰ
コンピュータグラフィックス編②ンピュ タグラフィックス編②ベジェ曲線とフラクタル
橋本 直橋本 直
1
今日大事なのは…今日大事なのは…難しい数式が出てきたら◦ 落ち着いて式のつくりを分析しよう◦ 落ち着いて式のつくりを分析しよう。◦ 数式の意味を完全に理解できていなくても、プ
ログラムを書くことはできるログラムを書くことはできる。
難しいアルゴリズムが出てきたら◦ 落ち着いて、順番に1⾏ずつ何が起こるか丁寧落ち着いて、順番に1⾏ずつ何が起こるか丁寧
にトレース(追跡)していこう。
2
1 ベジェ曲線1. ベジェ曲線
3
滑らかな曲線を描くアルゴリズム滑らかな曲線を描くアルゴリズムいろいろな曲線◦ ベジェ曲線◦ ファーガソン曲線◦ Bスプライン曲線◦ 有理ベジェ曲線◦ NURBS曲線
CADソフトやドローソフトには大抵なんらかの曲線CADソフトやドロ ソフトには大抵なんらかの曲線アルゴリズムが入っている。◦ Illustrator, Photoshop, PowerPoint, ペイント, …Illustrator, Photoshop, PowerPoint, ペイント,
4
例: Inkscapeの曲線機能例: Inkscapeの曲線機能
IllustratorやInkscapeに搭載されている曲線機能を実際に使ってみよう実際に使ってみよう。
5
ベジェ曲線とはベジェ曲線とは「制御点」と呼ばれる複数の点に基づいて定義される多項式曲線多項式曲線。
フランス ⾃動⾞メ カ ルノフランスの⾃動⾞メーカー、ルノー社のエンジニアだったピエール
ベジ が考案(1962)・ベジェが考案(1962)
CADの開発を⾏ ていたCADの開発を⾏っていた。
Pierre Bézier(1910-1999)
6Image from http://luc.devroye.org/fonts-36362.html
ベジェ曲線はこんな線ベジェ曲線はこんな線
P1 P2
P3P0
点 P P P P を制御点と呼ぶ点 P0, P1, P2, P3 を制御点と呼ぶ。n次のベジェ曲線には n+1 個の制御点がある。◦ 3次のベジェ曲線 ⇒ 4個の制御点◦ 2次のベジェ曲線 ⇒ 3個の制御点
7
アニメーションで⾒るベジェ曲線アニメーションで⾒るベジェ曲線
2次ベジェ曲線 3次ベジェ曲線次 ジェ曲線 3次 ジェ曲線
8Image from http://en.wikipedia.org/wiki/B%C3%A9zier_curve
ベジェ曲線の形状ベジェ曲線の形状制御点の位置を変えることによ て曲げ方を変える制御点の位置を変えることによって曲げ方を変えることができる。
9
ベジェ曲線の性質① 端点一致性ベジェ曲線の性質① 端点一致性
P1 P2 P0 P2
P0 P3P P3P1 P3
曲線の両端は制御点P0、Pnに一致する。また P0 P1 と Pn-1 Pn が曲線の接ベクトルとなるまた、P0 P1 と Pn-1 Pn が曲線の接ベクトルとなる。
10
ベジェ曲線の性質② 凸包性ベジェ曲線の性質② 凸包性PP1
P2
P P0
P2
PP30 P3
P0 P1
ベジェ曲線は制御点によって定義される凸包の中に完全に内包される完全に内包される。
凸包(とつほう)凸包(と ほう)◦ 与えられた点群を含む最小の凸形状のこと。◦ ピン群に輪ゴムをかけたときにできる図形。ピン群に輪ゴムをかけたときにできる図形。
11
ベジェ曲線の数式表現ベジェ曲線の数式表現制御点 があ き 次制御点 P0, P1, P2, P3 があるとき、3次のベジェ曲線は次式で表わされる。
10,)()()()()( 333
322
311
300 ≤≤+++= ttBPtBPtBPtBPtP
ここで は3次のバーンスタイン基底関数)(3 tBi
,)()()()()( 33221100
ここで は3次のバ ンスタイン基底関数)(tBi
)(30 tB )(3
3 tB330 )1()( ttB −= この関数は、制御点の)(0 tB
)(31 tB )(3
2 tB
)(3 tB
231
0
)1(3)(
)1()(
tttB
ttB
−=
この関数は、制御点の位置情報をどのようにブレンドするかの配合比を表わす)(1 tB )(2 tB
33
232
)(
)1(3)( tttB −=比を表わす。
t=0.0~1.0
12
333 )( ttB =
実装のために数式を読む①実装のために数式を読む①まずは式の形を把握する
)()()()()( 3333 BPBPBPBPP
どうやったらプログラムに落とし込めそうかよく考える
)()()()()( 333
322
311
300 tBPtBPtBPtBPtP +++=
◦ どうやったらプログラムに落とし込めそうかよく考える◦ 例えば微積分や総和、ノルム、最大値などの計算は入っている?
「t って何だ?」◦ 媒介変数表示(パラメータ表示)◦ この式に t=0, t=0.1, t=0.2, … t=1.0 と代入していくと、曲
線を構成する点群になる線を構成する点群になる。◦ すなわち、for文で t=0〜1.0 の範囲で値を入れていけばよい!
13
実装のために数式を読む②実装のために数式を読む②変数の形(データ構造)を把握する◦ スカラー? ベクトル? ⾏列?◦ プログラムで表現しやすい形に式を変形しよう。
)()()()()( 333
322
311
300 tBPtBPtBPtBPtP +++=
Pは2次元の点を示す座標値なので、とおいて変形),( yxP =
)()()()()( 3333 tBxtBxtBxtBxtx +++=
),( y
)()()()()( 33221100 tBxtBxtBxtBxtx +++=)()()()()( 3
333
223
113
00 tBytBytBytByty +++=
14
実装をイメージしよう(1)実装をイメ ジしよう(1)
for (float t=0; t<1.0; t+=0.01) {33 )1()( ttB
231
330
)1(3)(
)1()(
tttB
ttB
−=
−= ① 媒介変数による式表現は、for文によって表現することができる。
232
1
)1(3)(
)1(3)(
tttB
tttB
−=33
3 )( ttB =
)()()()()( 3333 BPBPBPBPPpoint( );
)()()()()( 333
322
311
300 tBPtBPtBPtBPtP +++=)(tP
})(
15
実装をイメージしよう(2)実装をイメ ジしよう(2)
for (float t=0; t<1.0; t+=0.01) {33 )1()( ttB −=
231
0
)1(3)(
)1()(
tttB
ttB
−=
=
3
232 )1(3)( tttB −= ② P(t)はすべて2次元の座標値を示す
ベクトルなので、xとyを使って表現する
)()()()()( 3333 tBxtBxtBxtBxtx +++=
333 )( ttB = る。
)()()()()( 33221100 tBxtBxtBxtBxtx +++=)()()()()( 3
333
223
113
00 tBytBytBytByty +++=point( , );
}
)()()()()( 33221100 yyyyy)(tx )(ty
16
}
実装をイメージしよう(3)実装をイメ ジしよう(3)
for (float t=0; t<1.0; t+=0.01) {33 )1( tB −=
231
0
)1(3
)1(
ttB
tB
−=
=
③ よりプログラムに近い、平易な形で表
3
232 )1(3 ttB −=
現するとこうなる。これらの数式を代入によってさらにまとめてしまってもよい。
3333 BxBxBxBxx +++=
333 tB =
33221100 BxBxBxBxx +++=3
333
223
113
00 ByByByByy +++=point( , );
}
33221100 yyyyyx y
17
}
課題① bezierCurve1課題① bezierCurve1
前述の数式を用いて、3次ベジェ曲線を描くプログラムを作成せよラムを作成せよ。
制御点の例◦ P0 : (75, 260)◦ P1 : (170, 120)◦ P2 : (350 90)P2 : (350, 90)◦ P3 : (500, 200)
18
課題② bezierCurve2課題② bezierCurve2各制御点をマウスカ ソルでひ ぱ て移動できるよ各制御点をマウスカーソルでひっぱって移動できるように改良し、制御点の配置とベジェ曲線の関係(前述の性質)について確認せよの性質)について確認せよ。
点の近くでマウスボタンを押して、そのままドラッグすると点が移動。
19
点の近くで ウスボタンを押して、そのままドラッグすると点が移動。好きな場所でマウスボタンを離すと、そこで点が留まる。
ヒントヒント点をマウスで移動できるようにするには?点をマウスで移動できるようにするには?◦ まずは「点の近くにカーソルがあって、マウスボタンが押され
ている」状態を判定できるようにしよう その状態のときにている」状態を判定できるようにしよう。その状態のときに、カーソルに点がついていくようにすれば良い。
◦ マウスボタン押下状態は mousePressed というboolean型のマウス タ 押下状態変数(true/false)で判定できる。これを使うと以下のように書ける。
if ( mousePressed == true ) {// マウスボタンが押されていたら
}
よりエレガントな書き方はこう↓
}
り ガ トな書 方 う↓
if ( mousePressed ) {// マウスボタンが押されていたら
20
}
2 フラクタル2. フラクタル
21
フラクタルとはフラクタルとはフラクタル(Fractal)◦ ⾃己相似性を持つ図形のこと◦ ⾃己相似性を持つ図形のこと
自己相似性自己相似性◦ 縮尺を変えても全体と部分の形状が相似の関係
にあること。◦ 「⾃分の中に⾃分がいて、さらにその中にも⾃「⾃分の中に⾃分がいて、さらにその中にも⾃
分が…」という構造
22
有名なフラクタル図形有名なフラクタル図形
マンデルブロ集合 シェルピンスキーの三角形三角形
コ ホ曲線コッホ曲線
23Image from http://ja.wikipedia.org/wiki/マンデルブロ集合
自然界に潜むフラクタル自然界に潜むフラクタル海岸線(リアス式海岸)海岸線(リアス式海岸)毛細血管毛細血管植物の葉や茎
ロマネスコシダ植物
24(カリフラワーの一種)
Image from http://ja.wikipedia.org/wiki/シダ植物, http://ja.wikipedia.org/wiki/ロマネスコ
フラクタルの応⽤例フラクタルの応⽤例F t l C dFractal Codes◦ ⾃己相似性を持つ2次元コード⾃己相似性を持 次元 ド◦ 近くから⾒ても遠くから⾒ても認識できる!◦ 一部分が⼿などで隠れていても認識できる!◦ 部分が⼿などで隠れていても認識できる!
25綾塚 祐二, “Fractal Codes: ⾃己相似的に配置される二次元コード”, WISS2006, pp.101-106
フラクタルを描くには?フラクタルを描くには?クタ は「⾃分 中 ⾃分が とフラクタルは「⾃分の中に⾃分がいる」と
いう再帰的な構造を持っている。
⇒ 再帰的アルゴリズムを使う!
ある三角形の中に小さな三角形を3つ描いて それぞれの三角を3つ描いて、それぞれの三角形の中にもさらに小さな三角形を3つ描いて、さらにその三角形の中にも という構造をし形の中にも… という構造をしている。
26
再帰的アルゴリズムとは再帰的アルゴリズムとはあ 関数f 中 f⾃⾝を実⾏す 仕組 を「再ある関数fの中で、f⾃⾝を実⾏する仕組みを「再帰呼び出し」といい、再帰呼び出しを用いたアルゴリズムを「再帰的アルゴリズム」と呼ぶリズムを「再帰的アルゴリズム」と呼ぶ。
void sample(…) {
…… sample()の中でsample()
が実行され またそ 中sample(…);
}
が実行され、またその中でsample()が実行され…と延々繰り返される} 延々繰り返される
27
再帰的アルゴリズムの例再帰的アルゴリズムの例このプログラムでは l ()このプログラムでは、sample()という関数の中でsample()⾃⾝が呼び出されている。
void setup() {sample(100);
} が呼び出されている。
なぜこのような実⾏結果になるのか考えてみよう
}
void draw() { } のか考えてみよう。void sample(float d) {
println("start"); 実行結果
if ( d < 10 ) {println("return");
tstartd 100 0
実行結果
return;} println( "d=" + d );sample( d/5 );
d=100.0startd=20.0startsample( d/5 );
println("end");}
startreturnendend
28
} end
void setup() {sample(100);
}
d=100 start … ①d=100.0 … ②
} void sample(float d) {println("start”); ①
if ( d < 10 ) {
start … ③d=20.0 … ④start … ⑤if ( d < 10 ) {
println("return");return;
} println( "d=" + d ); ②
d=20
return … ⑥end … ⑦end … ⑧
println( d= + d ); ②sample( d/5 );
println("end"); ⑧}
void sample(float d) {println("start”); ③
if ( d 10 ) {
実行結果
} if ( d < 10 ) {println( "return" );return;
} d=4println( "d=" + d ); ④sample( d/5 );
println("end"); ⑦
void sample(float d) {println("start"); ⑤
d 4
p ( );} if ( d < 10 ) {
println("return"); ⑥return;
}} println( "d=" + d );sample( d/3 );
println("end”);関数の処理が最終行まで至る、もしくは途中で
29
println( end );}return すると、呼び出し元の次の行に帰ってくる。
void setup() {sample(100);
}d=100 startstart
d=100.0startd=100.0startd=100.0startd=100.0startd=100.0startd=100.0startd=100.0
} void sample(float d) {println("start”);
if ( d < 10 ) {
startstartd=20.0startd=20.0start
startd=20.0start
startd=20.0start
startd=20.0startif ( d < 10 ) {
println("return");return;
} println( "d=" + d );
d=20
returnreturnendreturnendend
println( d= + d );sample( d/5 );
println("end");}
void sample(float d) {println("start”);
if ( d 10 ) {
実行結果
} if ( d < 10 ) {println( "return" );return;
} d=4println( "d=" + d );sample( d/5 );
println("end");
void sample(float d) {println("start");
d 4
p ( );} if ( d < 10 ) {
println("return");return;
}} println( "d=" + d );sample( d/3 );
println("end”);
30
println( end );}
再帰呼び出しで絵を描く再帰呼び出しで絵を描く以下のプログラムでは 再帰呼び出しを使って「円の中に⾃分と以下のプログラムでは、再帰呼び出しを使って「円の中に⾃分と半分のサイズの円を描く」を繰り返している。
void setup() {size(400, 400);
}
void draw() {background(200);translate( width/2 height/2 );translate( width/2, height/2 );drawCircle(400);
}
void drawCircle(float d) { if ( d < 10 ) {
return;return;}ellipse( 0, 0, d, d );drawCircle(d/2);
31
drawCircle(d/2);}
再帰的アルゴリズムでの注意点再帰的アルゴリズムでの注意点再帰において重要なのはループの終了処理!◦ 終了条件がととのったときに return で脱出させる。◦ これがきちんと仕掛けられてないと無限ループに陥ってしまう。
void drawCircle(float d) {
if ( d < 10 ) {return;
これが再帰ループの終了処理。円の直径が10未満になったら、そのタイミングでreturnで関数}
ellipse( 0, 0, d, d );
そのタイミングでreturnで関数から脱出させている。
ellipse( 0, 0, d, d );drawCircle(d/2);
}
32
再帰的アルゴリズムでフラクタルを再帰的アルゴリズムでフラクタルを描くときの秘伝テクニック描くときの秘伝テク ック
①まずは繰り返しの基本要素を⾒つけて その基本①まずは繰り返しの基本要素を⾒つけて、その基本要素だけを描く関数を作る
②その関数に再帰構造を組み込む
③終了条件を設定する
33
例題:フラクタルな⽊例題:フラクタルな⽊下図の木を再帰的アルゴリズムで描いてみよう
34
1 基本要素を⾒つける1. 基本要素を⾒つけるまずは繰り返しになっている最小単位を⾒つける。
これが最小単位
35
2 基本要素を描く方法を考える2. 基本要素を描く方法を考える
①原点から上方向に⻑さLの線を描く。②座標系をy方向に Lだけ平⾏移動させる
+40°-40°
②座標系をy方向に-Lだけ平⾏移動させる。③その位置で座標系を+40度回転させた
後 そこを起点に⻑さL/2の線を描く
③④後、そこを起点に⻑さL/2の線を描く。
④その位置で座標系を-40度回転させた後、そこを起点に⻑さL/2の線を描く。 ② 座標系をy方
向に-L移動⻑さ:L後 点 / く
①
向に L移動
①
スタ ト地点の座標値から各線の端点の座標値を計算する方スタート地点の座標値から各線の端点の座標値を計算する方法でも良いが、ここでは前回学んだtranslate()やrotate()を使って描画する方法で考えよう。
36
使って描画する方法で考えよう。
3 基本要素だけを描く関数を作る3. 基本要素だけを描く関数を作るここでは再帰構造のことは意識せずに「基本要素だけを描く関数」ここでは再帰構造のことは意識せずに「基本要素だけを描く関数」を作る。要素の大きさを引数で指定できるようにするのが重要。
void drawTree(float L) {
line( 0 0 0 -L );line( 0, 0, 0, -L );translate(0, -L);
pushMatrix();pushMatrix();rotate(radians(40));line( 0, 0, 0, -L/2 );
popMatrix();popMatrix();
pushMatrix();rotate(radians(-40));( ( ));line( 0, 0, 0, -L/2 );
popMatrix(); }
37当然だが、この関数単体での動作を確認するためにsetup()とdraw()も書こう。
4 再帰構造にする4. 再帰構造にする先ほど作 た関数内で⾏われている描画処理のうち 再帰的先ほど作った関数内で⾏われている描画処理のうち、再帰的な分割処理が発⽣する部分を再帰呼び出しに置き換える。
void drawTree(float L) { void drawTree(float L) {
line( 0, 0, 0, -L );translate(0, -L);
line( 0, 0, 0, -L );translate(0, -L);
pushMatrix();rotate(radians(40));line( 0, 0, 0, -L/2 );
pushMatrix();rotate(radians(40));drawTree( L/2 );line( 0, 0, 0, L/2 );
popMatrix();
pushMatrix();
drawTree( L/2 );popMatrix();
pushMatrix();p ();rotate(radians(-40));line( 0, 0, 0, -L/2 );
popMatrix();
p ();rotate(radians(-40));drawTree( L/2 );
popMatrix();
38
} }
5 再帰の終了条件を設定する5. 再帰の終了条件を設定するこのままでは再帰処理が無限に⾏われてしまうので、それを防ぐために「要素の大きさが一定
void drawTree(float L) {ぐために「要素の大きさが一定値以下になったら再帰を脱出する」という仕組みを加える。
if ( L < 1 ) {return;
}
ここでは「枝の⻑さが1未満になったら終了」としている
}
line( 0, 0, 0, -L );translate(0, -L);なったら終了」としている。pushMatrix();
rotate(radians(40));d T ( L/2 )drawTree( L/2 );
popMatrix();
pushMatrix();pushMatrix();rotate(radians(-40));drawTree( L/2 );
popMatrix();
39
popMatrix(); }
6 完成したプログラム6. 完成したプログラムvoid setup() {
size(400, 400);strokeWeight(2);
void drawTree(float L) {if ( L< 1 ) {
return;strokeWeight(2);}
void draw() {
return;}
line( 0 0 0 -L);void draw() {translate( width/2, height );drawTree(200);
}
line( 0, 0, 0, L);translate(0, -L);
pushMatrix();} pushMatrix();rotate(radians(40));drawTree( L/2 );
popMatrix();p p ();
pushMatrix();rotate(radians(-40));drawTree( L/2 );
popMatrix(); }
40
課題③ SierpinskiTriangle課題③ SierpinskiTriangleシェルピンスキーの三角形を描くプログラムを作成せよ。
◦ 再帰的アルゴリズムを使って作成し、最も小さな三角形の一辺の⻑さが10ピクセル以上になるようにすることル以上になるようにすること。
◦ 正三角形の中に1/2のサイズの正三角形が3 収ま た構造にな ることにが3つ収まった構造になっていることに注目。
◦ 点(x1, y1), (x2, y2), (x3, y3)を頂点とする三角形を描くにはt i l ( 1 1 2 2 3 3)triangle( x1, y1, x2, y2, x3, y3);
41
おまけ課題 KochCurveおまけ課題 KochCurveホ曲線を描くプ グ ムを作成せよコッホ曲線を描くプログラムを作成せよ。
42※こういうルールで描かれているが、アニメーションさせる必要はない。
ヒントヒント
④⑥⑤ ⑦
①
④⑩
⑦
①
② ③⑧
③
⑨L/3 ⑨
L43
top related