You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
69 lines
3.4 KiB
69 lines
3.4 KiB
import torch
|
|
import math
|
|
|
|
def rand_perlin_2d(shape, res, fade = lambda t: 6*t**5 - 15*t**4 + 10*t**3):
|
|
delta = (res[0] / shape[0], res[1] / shape[1])
|
|
d = (shape[0] // res[0], shape[1] // res[1])
|
|
|
|
grid = torch.stack(torch.meshgrid(torch.arange(0, res[0], delta[0]), torch.arange(0, res[1], delta[1])), dim = -1) % 1
|
|
angles = 2*math.pi*torch.rand(res[0]+1, res[1]+1)
|
|
gradients = torch.stack((torch.cos(angles), torch.sin(angles)), dim = -1)
|
|
|
|
tile_grads = lambda slice1, slice2: gradients[slice1[0]:slice1[1], slice2[0]:slice2[1]].repeat_interleave(d[0], 0).repeat_interleave(d[1], 1)
|
|
dot = lambda grad, shift: (torch.stack((grid[:shape[0],:shape[1],0] + shift[0], grid[:shape[0],:shape[1], 1] + shift[1] ), dim = -1) * grad[:shape[0], :shape[1]]).sum(dim = -1)
|
|
|
|
n00 = dot(tile_grads([0, -1], [0, -1]), [0, 0])
|
|
n10 = dot(tile_grads([1, None], [0, -1]), [-1, 0])
|
|
n01 = dot(tile_grads([0, -1],[1, None]), [0, -1])
|
|
n11 = dot(tile_grads([1, None], [1, None]), [-1,-1])
|
|
t = fade(grid[:shape[0], :shape[1]])
|
|
return math.sqrt(2) * torch.lerp(torch.lerp(n00, n10, t[..., 0]), torch.lerp(n01, n11, t[..., 0]), t[..., 1])
|
|
|
|
def rand_perlin_2d_octaves(shape, res, octaves=1, persistence=0.5):
|
|
noise = torch.zeros(shape)
|
|
frequency = 1
|
|
amplitude = 1
|
|
for _ in range(octaves):
|
|
noise += amplitude * rand_perlin_2d(shape, (frequency*res[0], frequency*res[1]))
|
|
frequency *= 2
|
|
amplitude *= persistence
|
|
return noise
|
|
|
|
def perlin_2d(shape, res, seed, fade=lambda t: 6*t**5 - 15*t**4 + 10*t**3):
|
|
delta = (res[0] / shape[0], res[1] / shape[1])
|
|
d = (shape[0] // res[0], shape[1] // res[1])
|
|
|
|
grid = torch.stack(torch.meshgrid(torch.arange(0, res[0], delta[0]), torch.arange(0, res[1], delta[1])), dim=-1) % 1
|
|
base_seed = int(seed)
|
|
frac_seed = seed - base_seed
|
|
|
|
torch.manual_seed(base_seed)
|
|
angles_base = 2 * math.pi * torch.rand(res[0] + 1, res[1] + 1)
|
|
gradients_base = torch.stack((torch.cos(angles_base), torch.sin(angles_base)), dim=-1)
|
|
|
|
torch.manual_seed(base_seed + 1)
|
|
angles_next = 2 * math.pi * torch.rand(res[0] + 1, res[1] + 1)
|
|
gradients_next = torch.stack((torch.cos(angles_next), torch.sin(angles_next)), dim=-1)
|
|
|
|
gradients = (1 - frac_seed) * gradients_base + frac_seed * gradients_next
|
|
|
|
tile_grads = lambda slice1, slice2: gradients[slice1[0]:slice1[1], slice2[0]:slice2[1]].repeat_interleave(d[0], 0).repeat_interleave(d[1], 1)
|
|
dot = lambda grad, shift: (torch.stack((grid[:shape[0], :shape[1], 0] + shift[0], grid[:shape[0], :shape[1], 1] + shift[1]), dim=-1) * grad[:shape[0], :shape[1]]).sum(dim=-1)
|
|
|
|
n00 = dot(tile_grads([0, -1], [0, -1]), [0, 0])
|
|
n10 = dot(tile_grads([1, None], [0, -1]), [-1, 0])
|
|
n01 = dot(tile_grads([0, -1], [1, None]), [0, -1])
|
|
n11 = dot(tile_grads([1, None], [1, None]), [-1, -1])
|
|
t = fade(grid[:shape[0], :shape[1]])
|
|
return math.sqrt(2) * torch.lerp(torch.lerp(n00, n10, t[..., 0]), torch.lerp(n01, n11, t[..., 0]), t[..., 1])
|
|
|
|
|
|
def perlin_2d_octaves(shape, res, seed, octaves=1, persistence=0.5, fade=lambda t: 6*t**5 - 15*t**4 + 10*t**3):
|
|
noise = torch.zeros(shape)
|
|
frequency = 1
|
|
amplitude = 1
|
|
for i in range(octaves):
|
|
noise += amplitude * perlin_2d(shape, (frequency * res[0], frequency * res[1]), seed + i, fade)
|
|
frequency *= 2
|
|
amplitude *= persistence
|
|
return noise |