根据this blog post,有几种方法可以使voronoi细胞更具动感。我感兴趣的是他们提到的第一个:
上面的图示与上面的图示是相同的Voronoi图,只是现在,Perlin噪声已用于扭曲哪些点属于哪个单元格。这在单元格之间创建了一些更有趣的边界。 只要您使用最接近的voronoi原点的逐像素(或逐区块)分配,这就很容易实现,因为您可以非常简单地用Perlin噪声抵消像素的实际坐标-与失真的Perlin噪声密切相关。
我见过其他地方提到过类似的想法,但是没有实际的代码显示Perlin噪声是如何“扭曲”或“添加”到voronoi图的。我已经尝试通过猜测来应用它,但是没有运气。我的代码的编写方式是,点之间的距离为数百,而perlin噪声值仅为0到1,因此添加或减去噪声实际上并没有多大作用。乘法似乎破坏了voronoi。我曾尝试将voronoi距离值缩放到0到1或-1到1之间,然后应用于噪声,但这也不起作用。
下面是我正在生成的voronoi图和perlin噪声的示例。我将不胜感激任何反馈或有能力为我指出正确的方向。
from PIL import Image
import random
import math
import numpy as np
import noise
wid = 500
hei = 250
image = Image.new("RGB",(wid,hei))
world_test = np.zeros(image.size)
scale = 100 # Number that determines at what distance to view the noisemap
octaves = 6 # the number of levels of detail you want you perlin noise to have
persistence = 0.5 # number that determines how much detail is added or removed at each octave (adjusts frequency)
lacunarity = 2.0 # number that determines how much each octave contributes to the overall shape (adjusts amplitude)
# Creates perlin noise
for x in range(wid):
for y in range(hei):
world_test[x][y] = ((noise.pnoise2(x/100,
y/100,
octaves = octaves,
persistence = persistence,
lacunarity = lacunarity,
repeatx = wid,
repeaty = hei,
base = 0)))
def generate_voronoi_diagram(width, height, num_cells):
image = Image.new("RGB", (width, height))
putpixel = image.putpixel
imgx, imgy = image.size
nx = []
ny = []
nr = []
ng = []
nb = []
#Go through number of cells
for i in range(num_cells):
#creat a point (x,y) and give it a specific color value
nx.append(random.randrange(imgx))
ny.append(random.randrange(imgy))
nr.append(random.randrange(256))
ng.append(random.randrange(256))
nb.append(random.randrange(256))
#go through each pixel in the image
for y in range(int(imgy)):
for x in range(int(imgx)):
dmin = math.hypot(imgx-1, imgy-1)
j = -1
#go through each cell
for i in range(num_cells):
# d is distance from each voronoi starting point
d = math.hypot((nx[i]-x), (ny[i]-y))
# apply perlin distort to d
d += world_test[x][y]
#if distance is less than the current min distance,
#set that point as the owner of this pixel and the new dmin
if d < dmin:
dmin = d
j = i
putpixel((x, y), (nr[j], ng[j], nb[j]))
image.save("Voronoi_example.png", "PNG")
image.show()
generate_voronoi_diagram(wid, hei, 30)