From a29c29ecefef6770ce005b9ac186de916755aaa2 Mon Sep 17 00:00:00 2001 From: David Li Date: Fri, 21 Apr 2023 11:33:10 -0400 Subject: [PATCH 1/2] Enable arbitrary resolution in 2D noise --- perlin_numpy/perlin2d.py | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/perlin_numpy/perlin2d.py b/perlin_numpy/perlin2d.py index 2dde627..5e820c4 100644 --- a/perlin_numpy/perlin2d.py +++ b/perlin_numpy/perlin2d.py @@ -14,8 +14,7 @@ def generate_perlin_noise_2d( shape: The shape of the generated array (tuple of two ints). This must be a multple of res. res: The number of periods of noise to generate along each - axis (tuple of two ints). Note shape must be a multiple of - res. + axis (tuple of two ints). tileable: If the noise should be tileable along each axis (tuple of two bools). Defaults to (False, False). interpolant: The interpolation function, defaults to @@ -27,10 +26,6 @@ def generate_perlin_noise_2d( Raises: ValueError: If shape is not a multiple of res. """ - delta = (res[0] / shape[0], res[1] / shape[1]) - d = (shape[0] // res[0], shape[1] // res[1]) - grid = np.mgrid[0:res[0]:delta[0], 0:res[1]:delta[1]]\ - .transpose(1, 2, 0) % 1 # Gradients angles = 2*np.pi*np.random.rand(res[0]+1, res[1]+1) gradients = np.dstack((np.cos(angles), np.sin(angles))) @@ -38,18 +33,24 @@ def generate_perlin_noise_2d( gradients[-1,:] = gradients[0,:] if tileable[1]: gradients[:,-1] = gradients[:,0] - gradients = gradients.repeat(d[0], 0).repeat(d[1], 1) - g00 = gradients[ :-d[0], :-d[1]] - g10 = gradients[d[0]: , :-d[1]] - g01 = gradients[ :-d[0],d[1]: ] - g11 = gradients[d[0]: ,d[1]: ] + grid = np.stack(np.meshgrid( + np.arange(0, shape[1]) * res[1] / shape[1], + np.arange(0, shape[0]) * res[0] / shape[0], + )[::-1], axis=-1) + grid_floor = np.floor(grid).astype(int) + grid_ceil = np.ceil(grid).astype(int) + g00 = gradients[grid_floor[:,:,0], grid_floor[:,:,1]] + g10 = gradients[grid_ceil[:,:,0], grid_floor[:,:,1]] + g01 = gradients[grid_floor[:,:,0], grid_ceil[:,:,1]] + g11 = gradients[grid_ceil[:,:,0], grid_ceil[:,:,1]] + grid_frac = grid - grid_floor # Ramps - n00 = np.sum(np.dstack((grid[:,:,0] , grid[:,:,1] )) * g00, 2) - n10 = np.sum(np.dstack((grid[:,:,0]-1, grid[:,:,1] )) * g10, 2) - n01 = np.sum(np.dstack((grid[:,:,0] , grid[:,:,1]-1)) * g01, 2) - n11 = np.sum(np.dstack((grid[:,:,0]-1, grid[:,:,1]-1)) * g11, 2) + n00 = np.sum(np.dstack((grid_frac[:,:,0] , grid_frac[:,:,1] )) * g00, 2) + n10 = np.sum(np.dstack((grid_frac[:,:,0]-1, grid_frac[:,:,1] )) * g10, 2) + n01 = np.sum(np.dstack((grid_frac[:,:,0] , grid_frac[:,:,1]-1)) * g01, 2) + n11 = np.sum(np.dstack((grid_frac[:,:,0]-1, grid_frac[:,:,1]-1)) * g11, 2) # Interpolation - t = interpolant(grid) + t = interpolant(grid_frac) n0 = n00*(1-t[:,:,0]) + t[:,:,0]*n10 n1 = n01*(1-t[:,:,0]) + t[:,:,0]*n11 return np.sqrt(2)*((1-t[:,:,1])*n0 + t[:,:,1]*n1) From dafecb3d46d3bde48c20e562b71401ddd351c2ea Mon Sep 17 00:00:00 2001 From: David Li Date: Sun, 23 Jul 2023 00:04:09 +0000 Subject: [PATCH 2/2] Same fix for 3d --- perlin_numpy/perlin3d.py | 48 +++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/perlin_numpy/perlin3d.py b/perlin_numpy/perlin3d.py index 5df701a..d00f130 100644 --- a/perlin_numpy/perlin3d.py +++ b/perlin_numpy/perlin3d.py @@ -26,11 +26,6 @@ def generate_perlin_noise_3d( 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) @@ -44,26 +39,33 @@ def generate_perlin_noise_3d( 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]: ] + grid = np.stack(np.meshgrid( + np.arange(0, shape[1]) * res[1] / shape[1], + np.arange(0, shape[0]) * res[0] / shape[0], + np.arange(0, shape[2]) * res[2] / shape[2], + ), axis=-1)[...,[1,0,2]] + grid_floor = np.floor(grid).astype(int) + grid_ceil = np.ceil(grid).astype(int) + g000 = gradients[grid_floor[...,0], grid_floor[...,1], grid_floor[...,2]] + g100 = gradients[ grid_ceil[...,0], grid_floor[...,1], grid_floor[...,2]] + g010 = gradients[grid_floor[...,0], grid_ceil[...,1], grid_floor[...,2]] + g110 = gradients[ grid_ceil[...,0], grid_ceil[...,1], grid_floor[...,2]] + g001 = gradients[grid_floor[...,0], grid_floor[...,1], grid_ceil[...,2]] + g101 = gradients[ grid_ceil[...,0], grid_floor[...,1], grid_ceil[...,2]] + g011 = gradients[grid_floor[...,0], grid_ceil[...,1], grid_ceil[...,2]] + g111 = gradients[ grid_ceil[...,0], grid_ceil[...,1], grid_ceil[...,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) + grid_frac = grid - np.floor(grid) + n000 = np.sum(np.stack((grid_frac[:,:,:,0] , grid_frac[:,:,:,1] , grid_frac[:,:,:,2] ), axis=3) * g000, 3) + n100 = np.sum(np.stack((grid_frac[:,:,:,0]-1, grid_frac[:,:,:,1] , grid_frac[:,:,:,2] ), axis=3) * g100, 3) + n010 = np.sum(np.stack((grid_frac[:,:,:,0] , grid_frac[:,:,:,1]-1, grid_frac[:,:,:,2] ), axis=3) * g010, 3) + n110 = np.sum(np.stack((grid_frac[:,:,:,0]-1, grid_frac[:,:,:,1]-1, grid_frac[:,:,:,2] ), axis=3) * g110, 3) + n001 = np.sum(np.stack((grid_frac[:,:,:,0] , grid_frac[:,:,:,1] , grid_frac[:,:,:,2]-1), axis=3) * g001, 3) + n101 = np.sum(np.stack((grid_frac[:,:,:,0]-1, grid_frac[:,:,:,1] , grid_frac[:,:,:,2]-1), axis=3) * g101, 3) + n011 = np.sum(np.stack((grid_frac[:,:,:,0] , grid_frac[:,:,:,1]-1, grid_frac[:,:,:,2]-1), axis=3) * g011, 3) + n111 = np.sum(np.stack((grid_frac[:,:,:,0]-1, grid_frac[:,:,:,1]-1, grid_frac[:,:,:,2]-1), axis=3) * g111, 3) # Interpolation - t = interpolant(grid) + t = interpolant(grid_frac) n00 = n000*(1-t[:,:,:,0]) + t[:,:,:,0]*n100 n10 = n010*(1-t[:,:,:,0]) + t[:,:,:,0]*n110 n01 = n001*(1-t[:,:,:,0]) + t[:,:,:,0]*n101