Worley 雜訊
March 29, 2022如果在指定一個點,每個像素至該點的距離作為灰階值計算來源,畫出來的圖會是越接近該點越黑,越遠離該點越白的圓形圖案。例如:
width = 100;
point = [width, width] / 2;
range = [0:width];
for(x = range, y = range) {
p = [x, y];
dist = norm(p - point);
gray = dist / (width * 0.8); // 調整寬度,只是為了亮一點
color([gray, gray, gray])
translate(p)
square(1);
}
這會產生以下的圖案:
點的勢力範圍
如果有兩個點,每個像素至該兩點的距離取較小者,作為灰階值的計算來源,因為一個點會像是個圓形圖,兩個點的話:
width = 100;
p1 = [width, width] / 4;
p2 = p1 * 3;
range = [0:width];
for(x = range, y = range) {
p = [x, y];
dist1 = norm(p - p1);
dist2 = norm(p - p2);
gray = min(dist1, dist2) / (width * 0.8); // 調整寬度,只是為了亮一點
color([gray, gray, gray])
translate(p)
square(1);
}
就會像是兩個互相擠壓的泡泡:
如果有很多點呢?
width = 100;
n = 5;
cell_points = [for(i = [0:n - 1]) rands(0, width, 2)];
range = [0:width];
for(x = range, y = range) {
p = [x, y];
dists = [for(pt = cell_points) norm(p - pt)];
gray = min(dists) / (width * 0.8); // 調整寬度,只是為了亮一點
color([gray, gray, gray])
translate(p)
square(1);
}
這就會形成像是 Voronoi 圖案的結果:
Voronoi 是勢力均衡下產生的圖案,就方才的範例而言,是以距離作為勢力衡量的依據,也就是範圍中每個座標比較靠近哪個點,就選擇該點勢力作為灰階值計算依據。
每個點就像是細胞核,如果作為細胞核的點是隨機產生,像素的勢力值也會是隨機,基本上就可以作為雜訊來源,只不過這隨機中有規則,才會產生像是 Voronoi 般的圖案,又稱為 Voronoi 雜訊 或 Worley 雜訊,因為它是 Steven Worley 在 1996 年引入的雜訊函式。
nz_cell 函式
dotSCAD 的 nz_cell
,可以指定作為細胞核的隨機點,傳回特定點的 Worley 雜訊,例如:
use <noise/nz_cell.scad>;
width = 100;
n = 10;
cell_points = [for(i = [0:n - 1]) rands(0, width, 2)];
range = [0:width];
for(x = range, y = range) {
p = [x, y];
noise = nz_cell(cell_points, p);
translate(p)
linear_extrude(noise / 2)
square(1);
}
這次得到的雜訊值,是作為擠出的高度,來看看產生了什麼:
這有點像是凹陷的沙地,你也可以使用 width / 4 - noise / 2
作為擠出的高度,看來就像是泡泡擠在一起:
Worley 雜訊的變化
Worley 雜訊不見得是要比較點與點間的直線距離,也可以是其他的距離計算方式,例如,nz_cell
的 dist
還可以使用 "manhattan"
指定〈曼哈頓距離〉、"chebyshev"
指定〈切比雪夫距離〉等,來看看指定了 "manhattan"
時的樣子:
use <noise/nz_cell.scad>;
width = 100;
n = 10;
cell_points = [for(i = [0:n - 1]) rands(0, width, 2)];
range = [0:width];
for(x = range, y = range) {
p = [x, y];
noise = nz_cell(cell_points, p, dist = "manhattan");
gray = noise / (width * 0.75);
color([gray, gray, gray])
translate(p)
linear_extrude(noise / 2)
square(1);
}
繪出的模型做了些著色,這樣比較看得出來邊緣與高度等差異:
如果作為細胞核的點並不是隨機,而是特別經過安排的呢?例如,位於〈黃金螺線〉上的點?
use <noise/nz_cell.scad>;
use <golden_spiral.scad>;
size = [100, 50];
half_size = size / 2;
pts_angles = golden_spiral(
from = 3,
to = 10,
point_distance = 3
);
cell_points = [for(pt_angle = pts_angles) pt_angle[0] + half_size];
for(x = [0:size.x], y = [0:size.y]) {
p = [x, y];
noise = nz_cell(cell_points, p);
gray = noise / size.y;
color([gray, gray, gray])
translate(p)
linear_extrude(noise + 1)
square(1);
}
這會形成漩渦的圖案:
你可以進一步地增加螺線數量,結合〈曲線到曲面〉的 sf_thicken
函式,將雜訊值與座標結合為曲面需要的資料,就可以實現〈Voronoi & Fibonacci 2〉的模型: