File size: 6,521 Bytes
2571f24 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | # ported from https://github.com/pvigier/perlin-numpy
import os, sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import torch
import numpy as np
from ShapeID.misc import stream_3D
def interpolant(t):
return t*t*t*(t*(t*6 - 15) + 10)
def generate_perlin_noise_3d(
shape, res, tileable=(False, False, False),
interpolant=interpolant, percentile=None,
):
"""Generate a 3D numpy array of perlin noise.
Args:
shape: The shape of the generated array (tuple of three ints).
This must be a multiple of res.
res: The number of periods of noise to generate along each
axis (tuple of three ints). Note shape must be a multiple
of res.
tileable: If the noise should be tileable along each axis
(tuple of three bools). Defaults to (False, False, False).
interpolant: The interpolation function, defaults to
t*t*t*(t*(t*6 - 15) + 10).
Returns:
A numpy array of shape with the generated noise.
Raises:
ValueError: If shape is not a multiple of res.
"""
delta = (res[0] / shape[0], res[1] / shape[1], res[2] / shape[2])
d = (shape[0] // res[0], shape[1] // res[1], shape[2] // res[2])
grid = np.mgrid[0:res[0]:delta[0],0:res[1]:delta[1],0:res[2]:delta[2]]
grid = np.mgrid[0:res[0]:delta[0],0:res[1]:delta[1],0:res[2]:delta[2]]
grid = grid.transpose(1, 2, 3, 0) % 1
# Gradients
theta = 2*np.pi*np.random.rand(res[0] + 1, res[1] + 1, res[2] + 1)
phi = 2*np.pi*np.random.rand(res[0] + 1, res[1] + 1, res[2] + 1)
gradients = np.stack(
(np.sin(phi)*np.cos(theta), np.sin(phi)*np.sin(theta), np.cos(phi)),
axis=3
)
if tileable[0]:
gradients[-1,:,:] = gradients[0,:,:]
if tileable[1]:
gradients[:,-1,:] = gradients[:,0,:]
if tileable[2]:
gradients[:,:,-1] = gradients[:,:,0]
gradients = gradients.repeat(d[0], 0).repeat(d[1], 1).repeat(d[2], 2)
g000 = gradients[ :-d[0], :-d[1], :-d[2]]
g100 = gradients[d[0]: , :-d[1], :-d[2]]
g010 = gradients[ :-d[0],d[1]: , :-d[2]]
g110 = gradients[d[0]: ,d[1]: , :-d[2]]
g001 = gradients[ :-d[0], :-d[1],d[2]: ]
g101 = gradients[d[0]: , :-d[1],d[2]: ]
g011 = gradients[ :-d[0],d[1]: ,d[2]: ]
g111 = gradients[d[0]: ,d[1]: ,d[2]: ]
# Ramps
n000 = np.sum(np.stack((grid[:,:,:,0] , grid[:,:,:,1] , grid[:,:,:,2] ), axis=3) * g000, 3)
n100 = np.sum(np.stack((grid[:,:,:,0]-1, grid[:,:,:,1] , grid[:,:,:,2] ), axis=3) * g100, 3)
n010 = np.sum(np.stack((grid[:,:,:,0] , grid[:,:,:,1]-1, grid[:,:,:,2] ), axis=3) * g010, 3)
n110 = np.sum(np.stack((grid[:,:,:,0]-1, grid[:,:,:,1]-1, grid[:,:,:,2] ), axis=3) * g110, 3)
n001 = np.sum(np.stack((grid[:,:,:,0] , grid[:,:,:,1] , grid[:,:,:,2]-1), axis=3) * g001, 3)
n101 = np.sum(np.stack((grid[:,:,:,0]-1, grid[:,:,:,1] , grid[:,:,:,2]-1), axis=3) * g101, 3)
n011 = np.sum(np.stack((grid[:,:,:,0] , grid[:,:,:,1]-1, grid[:,:,:,2]-1), axis=3) * g011, 3)
n111 = np.sum(np.stack((grid[:,:,:,0]-1, grid[:,:,:,1]-1, grid[:,:,:,2]-1), axis=3) * g111, 3)
# Interpolation
t = interpolant(grid)
n00 = n000*(1-t[:,:,:,0]) + t[:,:,:,0]*n100
n10 = n010*(1-t[:,:,:,0]) + t[:,:,:,0]*n110
n01 = n001*(1-t[:,:,:,0]) + t[:,:,:,0]*n101
n11 = n011*(1-t[:,:,:,0]) + t[:,:,:,0]*n111
n0 = (1-t[:,:,:,1])*n00 + t[:,:,:,1]*n10
n1 = (1-t[:,:,:,1])*n01 + t[:,:,:,1]*n11
noise = ((1-t[:,:,:,2])*n0 + t[:,:,:,2]*n1)
if percentile is None:
return noise
shres = np.percentile(noise, percentile)
mask = np.zeros_like(noise)
mask[noise >= shres] = 1.
noise *= mask
return noise, mask
def generate_fractal_noise_3d(
shape, res, octaves=1, persistence=0.5, lacunarity=2,
tileable=(False, False, False), interpolant=interpolant, percentile=None,
):
"""Generate a 3D numpy array of fractal noise.
Args:
shape: The shape of the generated array (tuple of three ints).
This must be a multiple of lacunarity**(octaves-1)*res.
res: The number of periods of noise to generate along each
axis (tuple of three ints). Note shape must be a multiple of
(lacunarity**(octaves-1)*res).
octaves: The number of octaves in the noise. Defaults to 1.
persistence: The scaling factor between two octaves.
lacunarity: The frequency factor between two octaves.
tileable: If the noise should be tileable along each axis
(tuple of three bools). Defaults to (False, False, False).
interpolant: The, interpolation function, defaults to
t*t*t*(t*(t*6 - 15) + 10).
Returns:
A numpy array of fractal noise and of shape generated by
combining several octaves of perlin noise.
Raises:
ValueError: If shape is not a multiple of
(lacunarity**(octaves-1)*res).
"""
noise = np.zeros(shape)
frequency = 1
amplitude = 1
for _ in range(octaves):
noise += amplitude * generate_perlin_noise_3d(
shape,
(frequency*res[0], frequency*res[1], frequency*res[2]),
tileable,
interpolant
)
frequency *= lacunarity
amplitude *= persistence
if percentile is None:
return noise
shres = np.percentile(noise, percentile)
mask = np.zeros_like(noise)
mask[noise >= shres] = 1.
noise *= mask
return noise, mask
def generate_shape_3d(shape, perlin_res, percentile, device):
pprob, p = generate_perlin_noise_3d(shape, perlin_res, tileable=(True, False, False), percentile=percentile)
return torch.from_numpy(p).to(device), torch.from_numpy(pprob).to(device)
def generate_velocity_3d(shape, perlin_res, V_multiplier, device):
curl_a = generate_perlin_noise_3d(shape, perlin_res, tileable=(True, False, False))
curl_b = generate_perlin_noise_3d(shape, perlin_res, tileable=(True, False, False))
curl_c = generate_perlin_noise_3d(shape, perlin_res, tileable=(True, False, False))
Vx, Vy, Vz = stream_3D(torch.from_numpy(curl_a).to(device),
torch.from_numpy(curl_b).to(device),
torch.from_numpy(curl_c).to(device))
return {'Vx': (Vx * V_multiplier), 'Vy': (Vy * V_multiplier).to(device), 'Vz': (Vz * V_multiplier)}
|