|
|
|
|
|
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 |
|
|
|
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]: ] |
|
|
|
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) |
|
|
|
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)} |
|
|
|
|
|
|