JUNのブログ

JUNのブログ

活動記録や技術メモ

フラクタル((マンデルブロ|ジュリア)集合)生成プログラムを書いた

42の課題でフラクタル(マンデルブロ集合とジュリア集合)を描画する課題があり, それが完了したので感想とか色々.

フラクタルとはなんぞや

Wikipediaによると

図形の部分と全体が自己相似(再帰)になっているものなどをいう。

フラクタル - Wikipedia

らしいです.

以下のようなやつとかですね.

Sierpinski zoom.gif
I, Avenafatua, CC 表示-継承 3.0, リンクによる

まぁ他にもフラクタルはいくつか種類があったり, 数学的な定義とか色々ありますが, まぁズームしていくと終わりが無くどんどん図形が出てくるやつのことです.

So Doge. Much fractal.
imgur.com

マンデルブロ集合

で, マンデルブロ集合 (Mandelbrot set) とはなんぞやという話ですが, マンデルブロ集合とは以下の漸化式が  n \rightarrow {\infty} で発散しない集合のことです.


    \begin{cases}
        {Z_{n+1} = Z_{n}^2 + C}\\
        {Z_0 = 0}
    \end{cases}

ここで  Z C複素数の式  a + bi です. また,  C複素数平面上の座標に対応しています.

マンデルブロ集合のわかりやすい説明は以下の動画とサイトがわかりやすいです.

www.youtube.com

azisava.sakura.ne.jp

で, 実装するときには  n \rightarrow {\infty} が発散するかどうかを判定しようとすると永遠に終わらないので, 適当に  n \rightarrow 100 とかにします. また, 発散するかどうかの判定は  |Z_n|が2を超えなければ集合に入っているということにします.

なんで2にしたかというと, マンデルブロ集合が実数, 虚数共に-2から2の範囲にあるからです.

で, これをコードとして書くと以下のような図が出てくるわけです.

f:id:JUN_NETWORKS:20210612144640p:plain

これを拡大していくと再帰的にどんどん色んな形が描画されていくのです.

https://user-images.githubusercontent.com/26608037/121766483-f454f300-cb8c-11eb-8718-dca049b76985.gif

github.com

ジュリア集合

ジュリア集合は基本的なコンセプトはマンデルブロ集合と同じです. 違う点は,  Z C の扱いで, ジュリア集合では  Z複素平面上の座標に対応させ,  Cが定数となっています.

以下の動画がめっちゃわかりやすいので見ると良いです.

www.youtube.com

たとえば  C=0.4-0.325i とすると以下のような形が出てきます.

f:id:JUN_NETWORKS:20210612145154p:plain
C=0.4-0.325i

 C=-0.8+0.156i だと以下のような形が出る.

f:id:JUN_NETWORKS:20210612145752p:plain
C=-0.8+0.156i

こんな感じで Cを変えると Cの値によって色んな形が出現します.

今回自分はマウスの座標によって Cの値を変えれるようにしました.

https://user-images.githubusercontent.com/26608037/121676176-4ba48600-caef-11eb-901c-ffa427d6c0a3.gif

はい. かっこいい.

バーニングシップ

課題のボーナスで「更にもう一個別のフラクタル作りなはれ」というのがあったのでバーニングシップ(Burning Ship)というのを作りました.

en.wikipedia.org

www.youtube.com

基本的なコンセプトはマンデルブロ集合と同じなのですが, イテレーションごとに行う計算( Z_{n+1}を求める計算)が少し違います.


    \begin{cases}
        {Z_{n+1} = (|Re(Z_n)| + i|Im(Z_n)|)^2 + C}\\
        {Z_0 = 0}
    \end{cases}

イテレーションごとに行う計算でそのまま2乗するのではなく, 絶対値を取るのがマンデルブロ集合との違いです.

これを実装して描画すると以下のような図形が出てきます.

f:id:JUN_NETWORKS:20210612154839p:plain

燃えてる船(Burning Ship)っぽいですね.

これを拡大していくと

https://user-images.githubusercontent.com/26608037/121768051-03d93980-cb97-11eb-9252-adf67edd0b29.gif

再帰的にどんどん船の形が出てきますね! かっこいい!

ただ, バーニングシップに関しては深くズームしまくると途中で行き止まりに当たるんで実装が正しくない可能性があるかも.

色付けに付いて

マンデルブロ集合, ジュリア集合, バーニングシップ は実装自体は難しくないです. ただ, 美しく描画するとなるとむずいんすよね...

今回の課題でも一応 color range shift を実装するという項目があったので, 単純にイテレーション回数に応じてHSVの色相(Hue)を変えるというので実装していて, 綺麗ではあるんですがYouTubeとかに上がっている動画の方みたいに綺麗なものを実装するのはなかなか難しそうです.

f:id:JUN_NETWORKS:20210612162636p:plain
自分の実装

www.youtube.com

JSr07885.gif
By Maxter315 - Own work, CC BY-SA 4.0, Link

Wikipediaマンデルブロ集合の色付けについての記事があったので見てみたのですが, 色付けって奥が深いですね...

en.wikipedia.org

完走した感想

完走した感想ですが, 楽しかったです(小並感).

マンデルブロ集合, ジュリア集合の描画に関しては1日で実装できましが, マウスのカーソルの場所に向かってズームする処理(Google map的なアレ)がくっそむずかったです.

というのも最初はズーム倍率と中心座標を保持してその値を変えることによって実現させようと思ったのですが, まる一日やっても上手くいかず, 結局ggったり他の人のコード読んだりして最終的には描画する左右上下両端の値(min_re, max_re, min_im, max_im)を保持し, それらを使って描画するようにしました. そこにマウスのウィンドウサイズからの相対座標を使って掛けたり割ったりしてうまいことズームしたり平行移動したりするようにしました.

あと, ループ内で変数代入するタイミングをミスってデバッグに1日溶かしました.

とか色々あって大体4日くらいかかりました.

この課題以外にも2Dゲームの課題とかがあったのですが, ジュリア集合のGIFアニメーションがかっこよすぎたのでこの課題にしました.

マウスで Cの値を変動させるというのは課題要件に無いので別にやる必要はなかったのですが, かっこいいを求めてやりました. 結果的にはかっこよくなったので大満足です.

この課題はそこまで重くない課題なので最初は記事を書くモチベはさほどなかったのですが, 実は提出するのをやらかしてLinterに引っかかって0点を食らったので供養のために書いていたりしますw

f:id:JUN_NETWORKS:20210612165431p:plain

ちゃんと課題提出前に確認するのと, 眠い時はちゃんと寝ましょう.

それではまた次の記事でお会いしましょう. ではでは〜👋👋