用Opengl畫Buddhabrot碎形

經過上次成功畫出 Mandelbrot set 後我就開始找有沒有其他好玩的碎形,結果就找到了這個變種,跟一般的碎形不同,它的圖案十分朦朧,也沒有甚麼清楚的邊界,就像太空中拍攝的星雲照片一般。

這次也順便作為 Compute shader 初體驗 ///,試著用它寫了畫圖的主要部份。

Buddhabrot

Buddhabrot 是由 Melinda Green 發現的渲染方法,並由 Lori Gardi 命名。其實就是畫 Mandelbrot set 的另一種方法,將計算 Mandelbrot set 時會發散的 iteration 走到的點記錄下來,不斷疊加而得到的圖形。

Compute Shader

在這之前就想要學 Compute Shader 了,但不知道該拿來做甚麼,一直到發現用 fragment shader 無法實現 更改 gl_Fragcoord 以外的位置的值,才開始摸 Compute Shader。

之後有空再補補 Compute Shader 的一些概念。

Speed up

如果每次都要檢查這個 iteration 是否發散,會浪費很多時間。所以事先將會收斂的區域渲染到一張圖片上,接下來的 iteration 如果在開始時就發現自己在 Mandelbrot set 中,反正已經知道它會收斂了,就直接取消不計算。

Innocent Mandelbrot set

加上這個判斷有另一個好處,因為會開始走的 iteration 都會發散,也就是說我們不需要保留 buffer 來存走過的值,在更新的當下就可以直接把值畫到圖上。

Random Starting Points

拿圖片像素座標來作為起始點的話,畫出來的結果並不精細,因此我另外加了一個 compute shader 來產生亂數作為起始點。

因為圖片有四個通道(channel),剛好可以將兩個 vec2 塞進 vec4 裡面,所以每次 render 時都可以直接做兩次 iteration。

It’s just noise

Results

因為對 compute shader 還不是很熟,這次只有畫出 512 x 512 的結果,累積點也是直接增加圖片的亮度,沒有真的去數,然後除掉最大值。

下面是目前最滿意的結果,但儘管用了亂數作為起始位置,還是可以看出有許多的網格…

Here’s Buddha

目前有想到兩個可能的原因:

  1. 亂數不夠亂,經過多次 draw call 後開始出現重複或相近的值
  2. 統計數值的時候是取最近的像素,其實可以用內插讓點的位置更精確

其實看著它慢慢 update 還滿療育的(每格是 100 次的 draw call)

Convergence of Buddhabrot

另外如果蒐集會收斂的 iteration , 能得到下面的結果

Inverse of Buddhabrot

Future works

  1. 修改亂數方法
  2. 試著內差點的位置
  3. 更改 Bail-out 看有甚麼影響
  4. 嘗試上色,或想想有甚麼地方可作為上色的參數
  5. 使用真正 計數 的 buffer,而不是直接增加亮度值
  6. 嘗試 render 局部區域
  7. 嘗試 render 更高解析度的結果

參考資料

  1. Melinda Green - The Buddhabrot Technique
  2. Lori Gardi - Buddhabrot
  3. Paul Bourke - The Buddhabrot