Julia 和 Mandelbrot 集合/景觀圖片
如果在三維座標系中,我們將帶有 Mandelbrot 或 Julia 集合的平面想象成 *x,y*-平面,並在 *z*-方向上繪製距離函式,我們將得到一個看起來像景觀的曲面,我們可以從側面觀察它。這樣的圖片必須從上往下(在螢幕上)繪製,並且從遠處到近處(在景觀中)繪製,這樣某些東西就會生長並隱藏之前繪製的內容。
距離函式可能存在奇點,這意味著曲面在某些點處會無限增長。由於這些強勁的上升如果數量眾多且占主導地位則會不美觀,因此我們必須修改距離函式(第三幅圖)。我們也可以修改它來創造一個更有趣的景觀(第二幅圖)。
我們可以讓光線是“自然的”,就像來自太陽的光線。然後我們想象光線是平行的(並且由兩個角度給出),並且我們讓曲面上一個點的顏色由這個方向與該點曲面斜率之間的角度決定。強度(在地球上)與距離無關,但由於大氣,光線會變得更白,有時地面看起來像是被一層薄霧籠罩(第二幅圖)。我們也可以讓光線是“人造的”,就像來自觀察者手中燈籠發出的光線一樣。在這種情況下,顏色必須隨著距離而變暗(第三幅圖)。
我們從一個向下傾斜的角度觀察景觀,繪圖視窗以這條線為中心的法線。繪圖視窗中的垂直線(畫素)對應於具有分形的基平面中的線。對於這些線中的每一條,我們從最遠點開始,向觀察者前進,在視窗的相應垂直線中以以下方式給畫素著色:如果 p 是基平面中線上的一個點,我們計算 p 處距離函式的值。如果從曲面上的這個點到眼睛的線與視窗相交,我們將給這個畫素著色。我們透過計算距離函式在 p 附近兩個非常接近的點(x 方向和 y 方向)的值,來計算該點處曲面的斜率。由三個值跨越的小三角形位於曲面上。我們取三角形法向量(單位向量)與光線方向(單位向量)的標量積 - 在人造光的情況下,這是從眼睛到點的方向向量。
這個數字(乘以密度)可以與其他決定顏色的因素相結合:例如,地面上方的高度或到觀察者的距離。
從曲面法向量(單位向量)與觀察者方向向量的標量積,我們可以近似計算出為了給相鄰畫素(分別對應於景觀在觀察者方向上的上升或下降)著色,我們必須朝觀察者前進的距離。由於這種計算不可能精確,因此可能必須將步驟減小一個因子。當我們離觀察者足夠近時,視窗的這條垂直線的底部畫素被著色,我們將停止繪製這條線 - 如果有東西在觀察者附近長出來,我們可能還會繼續繪製,因為我們希望看到這一點。我們可以在轉到下一條垂直線之前完成一條垂直線的繪製,而是透過在朝觀察者前進的每一步中轉到下一條垂直線,使繪製看起來更迷人,這樣繪製看起來就像從上往下波動一樣。
曲面主要由與距離函式成正比的函式構成,但程式應該被設計成可以處理這個函式。在第一步中,奇點應該透過選擇一個相對最大高度 *hm0* 來變為有限。這個數字乘以截面的寬度是景觀中的最大高度 *hm*,我們可以用 *hm * arctan(h/hm)* 來代替高度 *h*,例如。但是,數字 *hm*(常數)應該透過將其除以與實迭代次數的指數函式成正比的數字來改變,以便在邊界附近降低最大高度。我們也可以簡單地將奇點截斷,而不是將它們變為有限,方法是將 *h* 替換為 *hm*,當 *h* > *hm* 時。我們也可以透過將 *h* 除以 來調節 *h*,例如,或者我們可以透過將 *h* 替換為 來將奇點轉換為隕石坑,當 *h* > *hm* 時。
此外,可以透過將 *h* 乘以(例如)數字 來使曲面變得平滑,其中 *s* 是曲面的斜率,*a* 和 *b* 是決定效果的引數。
對於自然光,我們可以透過根據這個數字(在 [0, 1] 區間內)將顏色與灰色或黑色混合,來使顏色隨著距離和高度變得更白(霧)或更暗:,其中 *a, b, c* 和 *d* 是決定效果的引數。
對於人造光,我們可以透過根據數字 與黑色混合來使顏色隨著距離變暗,其中 *s* 是從眼睛到斜率(單位向量)的方向向量的標量積,*l* 和 *e* 是決定效果的引數。
-
在具有自然光線的普通 Mandelbrot 集合的海馬谷中
-
對於 的 Julia 集合,具有自然光線和霧
-
曼德勃羅集的一部分,對於 ,帶人造光
更詳細的繪製
[edit | edit source]我們必須首先選擇一個比例,我們將它應用於視窗和景觀,即透過將距離 gg 分配給視窗(或圖片)的寬度 ww(以畫素為單位)。然後,一個畫素的寬度是 hh = gg/ww,在以中心為原點的視窗座標系中,距離左邊界 i 個畫素的直線具有橫座標 xs = -gg/2 + i×hh。
從 z 軸上具有 z 座標 z0 的點觀察景觀,沿著方向為(正)y 軸的直線 lc,該直線與 y 軸交於一個縱座標為 yc 的點。將分形圖案平移,使得基平面中的該點 (0, yc) 成為分形圖案的中心:如果分形圖案的實際中心是 (x1, y1),則在計算高度和斜率時,我們將 (x1, y1) 加到 x-y 系中的座標集。
從 z0 到 lc 的正交線(在 y-z 平面上)與 y 軸相交於一個縱座標為 -yv(yv 為正)的點,這個點是消失點(對觀察者來說似乎無限遠)。我們令 d (= yc+yv) 為消失點到基點 yc 的距離。如果 m 是 lc(從觀察者到基點的距離)除以從觀察者到視窗的距離,則視窗中具有橫座標 xs 的垂直線對應於基平面中經過消失點 (0, -yv) 和點 (m×xs, yc) 的線。並且這條線上具有縱座標 y 的點,其橫座標為 m×xs×(d + y - yc)/d。
現在我們選擇視窗中的一條垂直線(距離左側 i 個畫素,因此具有橫座標 xs = -gg/2 + i×hh),我們將在基平面上沿著對應的線從遠到近對這條線進行著色。假設我們在這條線上到達了具有縱座標 y 的點。這個點的橫座標是 m×xs×(d + y - yc)/d,我們將計算具有橫座標 x1 + m×xs×(d + y - yc)/d 和縱座標 y1 + y - yc 的點的表面高度 z 和斜率 s。在 y-z 平面上,我們有從觀察者 (0, z0) 到 (y, z) 的線段 lz。要著色的視窗中的畫素(距離左側 i 個畫素)距離頂部 j 個畫素,其中 j 是 wh/2 - wj×tan(acz) 的整數部分,這裡 wh 是視窗的高度(以畫素為單位),wj 是從觀察者到視窗的距離,也以畫素為單位,acz 是 lc 到 lz 的角度。
在對這個畫素進行著色後,我們必須估計我們要向前移動(沿著負 y 軸方向)以對下一個(相鄰)畫素(上方或下方)進行著色的步長 dy 的縱座標。在 y-z 平面上,我們有從觀察者 (0, z0) 到 (y, 0) 的線段 ly。我們令 ay 為從(負)z 軸到 ly 的角度,令 ayz 為從 ly 到 lz 的角度。如果我們設定
- ,
dy 由以下公式給出
- ,
也就是說,新的 y 是 y - dy。
由於這只是一個估計值(透過微積分得到的),我們必須安排程式,以便我們可以將步長 dy 乘以一個因子 r < 1。
當最後一個畫素被繪製(距離頂部 wh 個畫素)並且當新的 y 小於某個 y 值時,視窗中垂直線的繪製就完成了,該 y 值取決於視窗下邊界的狀況、視角以及景觀是向上還是向下(當表面位於基平面下方且視角較小時,這個 y 值可能位於視窗下邊界相當遠的地方)。
迭代帶之間的間隙
[edit | edit source]有一種情況可能會使我們需要以更小的步長前進,那就是迭代帶之間出現間隙的趨勢,尤其是在公式中出現了較大的冪次。在接近邊界時,距離函式的值會越來越小,但在迭代次數增加 1 的曲線處,計算得到的距離往往比實際值略小。原因是,用於計算距離估計的迭代次數必須非常大,這預設了逃逸半徑非常小(或對迭代到無窮大來說非常大),但是如果逃逸半徑像它應該的那樣小,那麼迭代帶之間的著色就會變得不乾淨,因為斜率的計算是不確定的——就像當我們放大很多倍時,分形圖片總是變得不乾淨一樣:計算機的精度不再足夠了。
插值
[edit | edit source]我們可以透過應用插值來解決迭代帶之間的間隙問題:如果(在向下繪製中,即繪製表面的視覺側)下一個繪製的畫素不是下面緊鄰的畫素,我們可以透過對顏色值進行插值來填補間隙。使用這種技術,我們總是可以生成沒有明顯缺陷的圖片。此外,這種技術意味著,如果我們令縮小因子 r 大於 1,我們就可以快速繪製出足夠好的圖片,以便選擇圖案和顏色(比通常的分形圖片更快,因為精細的分形圖案不太容易辨認)。
逐畫素繪製
[edit | edit source]上面的繪製方法相當有效,因為我們事先估計了下一個要繪製畫素的情況。但是,每次有東西生長起來並隱藏之前繪製的畫素時,就會再次繪製畫素。此外,不規則的繪製方式意味著一個運作良好的程式會相當複雜(插值和計算景觀中從頂部開始繪製到底部結束的位置)。可以建立一個更簡單的程式,其中影像以畫素到畫素的方式規律繪製,這意味著每個畫素只被著色一次,但之後每個畫素都需要進行多次計算。對於螢幕上的一個給定畫素,我們沿著從觀察者穿過該畫素的直線逐步前進,當計算表明我們位於地表下方時,我們就停止。原則上,我們可以讓步長的大小相同,但這將要求步長非常小,計算次數將隨之變得非常大。幸運的是,我們有一個工具可以調整步長,使它們一開始比較大,然後以合適的速率變小,即用於構建景觀的距離估計。但這種方法需要(或者說效果最好)當景觀向下傾斜時,即在地平面以下而不是以上形成,因為我們可以從觀察者直線與地平面相交的點開始逐步逼近,並且可以使所有步長(的水平範圍)都由距離估計決定。
從觀察者直線與地平面相交的點開始,我們依次向前邁出步長,其在地平面上的投影為估計距離的一半,例如。在每一步中,我們計算步長點(在線上)的高度和地表(在這個點下方或上方)的高度,並繼續前進,只要第一個高度小於第二個高度。當不再是這種情況時,我們就位於地表下方,然後必須向後退並可能再次向前。這些步長也必須由距離估計決定,因為它們必須在邊界附近更小。我們可以使步長為 *e×d×dist*,其中 *dist* 是距離估計,*e* = ±1 表示步長點位於地表上方/下方,*d* 是一個因子,最初固定為給定的一個小數(例如 0.5),並且每次 *e* 的符號改變時除以 2。我們執行逐步逼近,直到兩個高度之間的差值小於給定的一個小數,*或* 直到達到最大迭代次數或邊界,或者執行的操作次數大於給定的一個大數,以確保過程停止。如果在表面上找到的點對應於複數 *z*(在地平面內),我們計算表面在 *z* 附近兩個點(在 *x* 和 *y* 方向上)的高度,以找到表面的斜率。
陰影效果
[edit | edit source]我們可以(如下面的圖片所示)透過繪製陰影(在自然光或來自觀察者的光的情況下)使景觀看起來更逼真:如果從表面上的一個點指向光源方向的直線在地表下方有一個點,那麼該點就在陰影中,因此會變暗。這種方法在向下傾斜的景觀情況下最有效,但即使在這種情況下,也可能需要對景觀可見部分之外的點執行計算(除非光源位於景觀可見部分之上)。