網格 Worley 雜訊

March 31, 2022

為了建立〈Worley 雜訊〉,指定範圍中每個位置,必須跟全部的細胞核求得距離,然後取最接近的細胞核,如果細胞核越多,要比較的次數也越多,這會是很沉重的運算。

鄰近的細胞

如果指定範圍內的細胞核,大致上是均勻分佈,那麼某位置跟遠處細胞核的距離求取及比較,基本上是沒有意義,若能事先排除太遠處的細胞核,就可以省下不少計算的時間,只不過細胞核又要有隨機性,如何能事先排除太遠處的細胞核?

如果想產生的 Worley 雜訊,每個細胞的大小不至於相差太大的話,可以在指定範圍內分割網格,然後在每個網格中隨機散佈一個細胞核。

網格 Worley 雜訊

就網格中某個位置來說,跟它有可能是最近距離的細胞核,就是其所處的網格九宮格內,因此只要針對九個細胞核計算就可以了。

dotSCAD 的 nz_worley2 函式,可以基於網格來產生 Worley 雜訊,只要指定座標位置、隨機種子以及範圍,它會自動分割網格,在每個網格中隨機散佈一個細胞核,然後計算該座標位置的 Worley 雜訊:

use <noise/nz_worley2.scad>

size = [100, 50];
grid_w = 10;
seed = 51;

points = [
    for(y = [0:size.y - 1], x = [0:size.x - 1]) 
    [x, y]
];

cells = [for(p = points) nz_worley2(p.x, p.y, seed, grid_w)];

max_dist = max([for(c = cells) c[2]]);
for(i = [0:len(cells) - 1]) {
    c = cells[i][2] / max_dist;
    color([c, c, c])
    linear_extrude(cells[i][2])
    translate(points[i])
        square(1);
}

nz_worley2 傳回 [x, y, noise],表示某座標位置是在細胞核 [x, y] 的勢力範圍內,雜訊值 noise,從上往下看模型的話,會是長這樣:

網格 Worley 雜訊

如果你事先已經有一組座標,可以直接使用 nz_worley2s 函式,例如,若只使用細胞核 [x, y] 與所在網格原點的距離為高度:

use <noise/nz_worley2s.scad>

size = [100, 50];
grid_w = 10;
seed = 51;

points = [
    for(y = [0:size.y - 1], x = [0:size.x - 1]) 
    [x, y]
];

cells = nz_worley2s(points, seed, grid_w);

for(i = [0:len(cells) - 1]) {
    h = norm([cells[i].x, cells[i].y]) % grid_w;
    color([h, h, h] / grid_w)
    linear_extrude(h)
    translate(points[i])
        square(1);
}

可以形成以下的模型:

網格 Worley 雜訊

三維的 Worley 雜訊

Worley 雜訊〉的做法,也可以擴展到三維,不過計算量龐大;網格的 Worley 雜訊做法,也可以擴展到三維,dotSCAD 的 nz_worley3 函式就是實現。

例如,來做個熔岩球:

use <voxel/vx_sphere.scad>
use <noise/nz_worley3.scad>

grid_w = 10;
radius = grid_w * 2;
seed = 51;

points = vx_sphere(radius);

cells = [for(p = points) nz_worley3(p.x, p.y, p.z, seed, grid_w)];

max_dist = max([for(c = cells) c[3]]);
for(i = [0:len(cells) - 1]) {
    c = cells[i][3] / max_dist * 1.5;
    color([c > 1 ? 1 : c, 0, 0])
    translate(points[i])
        cube(1);
}

dotSCAD 的 voxel 中,提供了一些建立體素(voxel)資料的函式,vx_sphere 是其中之一,簡單來說,可以想像成用方塊堆出一顆球,不過 vx_sphere 傳回的是座標資料,你不一定要用方塊來堆就是了;以上的程式會產生:

網格 Worley 雜訊

如果你已經有一組座標了,那麼可以使用 nz_worley3s,例如:

use <voxel/vx_sphere.scad>
use <noise/nz_worley3s.scad>

grid_w = 10;
radius = grid_w * 2;
seed = 51;

points = vx_sphere(radius);
cells = nz_worley3s(points, seed, grid_w);

for(i = [0:len(cells) - 1]) {
    c = (norm([cells[i][0], cells[i][1], cells[i][2]]) % radius) / radius;
    color([c, c, c])
    translate(points[i])
        cube(1);
}

這會產生以下的模型:

網格 Worley 雜訊

在〈Worley 雜訊〉談過,計算雜訊的依據不一定要是直線距離,也可以是曼哈頓距離或切比雪夫距離等,這邊提及的網格 Worley 雜訊相關函式,都支援 dist 參數,可以指定 "manhattan""chebyshev" 等值。

那麼,你有辦法用 Worley 雜訊,做出〈Worley vase〉嗎?

網格 Worley 雜訊

分享到 LinkedIn 分享到 Facebook 分享到 Twitter