|
| 1 | +import numpy as np |
| 2 | + |
| 3 | +def generate_perlin_noise_3d(shape, res): |
| 4 | + def f(t): |
| 5 | + return 6*t**5 - 15*t**4 + 10*t**3 |
| 6 | + |
| 7 | + delta = (res[0] / shape[0], res[1] / shape[1], res[2] / shape[2]) |
| 8 | + d = (shape[0] // res[0], shape[1] // res[1], shape[2] // res[2]) |
| 9 | + grid = np.mgrid[0:res[0]:delta[0],0:res[1]:delta[1],0:res[2]:delta[2]] |
| 10 | + grid = grid.transpose(1, 2, 3, 0) % 1 |
| 11 | + # Gradients |
| 12 | + theta = 2*np.pi*np.random.rand(res[0]+1, res[1]+1, res[2]+1) |
| 13 | + phi = 2*np.pi*np.random.rand(res[0]+1, res[1]+1, res[2]+1) |
| 14 | + gradients = np.stack((np.sin(phi)*np.cos(theta), np.sin(phi)*np.sin(theta), np.cos(phi)), axis=3) |
| 15 | + g000 = gradients[0:-1,0:-1,0:-1].repeat(d[0], 0).repeat(d[1], 1).repeat(d[2], 2) |
| 16 | + g100 = gradients[1: ,0:-1,0:-1].repeat(d[0], 0).repeat(d[1], 1).repeat(d[2], 2) |
| 17 | + g010 = gradients[0:-1,1: ,0:-1].repeat(d[0], 0).repeat(d[1], 1).repeat(d[2], 2) |
| 18 | + g110 = gradients[1: ,1: ,0:-1].repeat(d[0], 0).repeat(d[1], 1).repeat(d[2], 2) |
| 19 | + g001 = gradients[0:-1,0:-1,1: ].repeat(d[0], 0).repeat(d[1], 1).repeat(d[2], 2) |
| 20 | + g101 = gradients[1: ,0:-1,1: ].repeat(d[0], 0).repeat(d[1], 1).repeat(d[2], 2) |
| 21 | + g011 = gradients[0:-1,1: ,1: ].repeat(d[0], 0).repeat(d[1], 1).repeat(d[2], 2) |
| 22 | + g111 = gradients[1: ,1: ,1: ].repeat(d[0], 0).repeat(d[1], 1).repeat(d[2], 2) |
| 23 | + # Ramps |
| 24 | + n000 = np.sum(np.stack((grid[:,:,:,0] , grid[:,:,:,1] , grid[:,:,:,2] ), axis=3) * g000, 3) |
| 25 | + n100 = np.sum(np.stack((grid[:,:,:,0]-1, grid[:,:,:,1] , grid[:,:,:,2] ), axis=3) * g100, 3) |
| 26 | + n010 = np.sum(np.stack((grid[:,:,:,0] , grid[:,:,:,1]-1, grid[:,:,:,2] ), axis=3) * g010, 3) |
| 27 | + n110 = np.sum(np.stack((grid[:,:,:,0]-1, grid[:,:,:,1]-1, grid[:,:,:,2] ), axis=3) * g110, 3) |
| 28 | + n001 = np.sum(np.stack((grid[:,:,:,0] , grid[:,:,:,1] , grid[:,:,:,2]-1), axis=3) * g001, 3) |
| 29 | + n101 = np.sum(np.stack((grid[:,:,:,0]-1, grid[:,:,:,1] , grid[:,:,:,2]-1), axis=3) * g101, 3) |
| 30 | + n011 = np.sum(np.stack((grid[:,:,:,0] , grid[:,:,:,1]-1, grid[:,:,:,2]-1), axis=3) * g011, 3) |
| 31 | + n111 = np.sum(np.stack((grid[:,:,:,0]-1, grid[:,:,:,1]-1, grid[:,:,:,2]-1), axis=3) * g111, 3) |
| 32 | + # Interpolation |
| 33 | + t = f(grid) |
| 34 | + n00 = n000*(1-t[:,:,:,0]) + t[:,:,:,0]*n100 |
| 35 | + n10 = n010*(1-t[:,:,:,0]) + t[:,:,:,0]*n110 |
| 36 | + n01 = n001*(1-t[:,:,:,0]) + t[:,:,:,0]*n101 |
| 37 | + n11 = n011*(1-t[:,:,:,0]) + t[:,:,:,0]*n111 |
| 38 | + n0 = (1-t[:,:,:,1])*n00 + t[:,:,:,1]*n10 |
| 39 | + n1 = (1-t[:,:,:,1])*n01 + t[:,:,:,1]*n11 |
| 40 | + return ((1-t[:,:,:,2])*n0 + t[:,:,:,2]*n1) |
| 41 | + |
| 42 | +def generate_fractal_noise_3d(shape, res, octaves=1, persistence=0.5): |
| 43 | + noise = np.zeros(shape) |
| 44 | + frequency = 1 |
| 45 | + amplitude = 1 |
| 46 | + for _ in range(octaves): |
| 47 | + noise += amplitude * generate_perlin_noise_3d(shape, (frequency*res[0], frequency*res[1], frequency*res[2])) |
| 48 | + frequency *= 2 |
| 49 | + amplitude *= persistence |
| 50 | + return noise |
| 51 | + |
| 52 | +if __name__ == '__main__': |
| 53 | + import matplotlib.pyplot as plt |
| 54 | + import matplotlib.animation as animation |
| 55 | + |
| 56 | + np.random.seed(0) |
| 57 | + noise = generate_fractal_noise_3d((32, 256, 256), (1, 4, 4), 4) |
| 58 | + |
| 59 | + fig = plt.figure() |
| 60 | + images = [[plt.imshow(layer, cmap='gray', interpolation='lanczos', animated=True)] for layer in noise] |
| 61 | + animation = animation.ArtistAnimation(fig, images, interval=50, blit=True) |
| 62 | + plt.show() |
0 commit comments