Created
July 12, 2025 11:21
-
-
Save celeron55/3de43f6871fd150dd9e970ef231ae5c1 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import numpy as np | |
| import matplotlib.pyplot as plt | |
| from mpl_toolkits.mplot3d import Axes3D # For 3D projection | |
| # Perlin noise functions from pvigier's implementation | |
| def generate_perlin_noise_2d(shape, res, seed=0): | |
| np.random.seed(seed) | |
| def f(t): | |
| return 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 = 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))) | |
| g00 = gradients[0:-1, 0:-1].repeat(d[0], 0).repeat(d[1], 1) | |
| g10 = gradients[1:, 0:-1].repeat(d[0], 0).repeat(d[1], 1) | |
| g01 = gradients[0:-1, 1:].repeat(d[0], 0).repeat(d[1], 1) | |
| g11 = gradients[1:, 1:].repeat(d[0], 0).repeat(d[1], 1) | |
| # Ramps | |
| n00 = np.sum(grid * 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) | |
| # Interpolation | |
| t = f(grid) | |
| 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) | |
| def generate_fractal_noise_2d(shape, res, octaves=1, persistence=0.5, seed=0): | |
| np.random.seed(seed) | |
| noise = np.zeros(shape) | |
| frequency = 1 | |
| amplitude = 1 | |
| for i in range(octaves): | |
| noise += amplitude * generate_perlin_noise_2d(shape, (frequency * res[0], frequency * res[1]), seed + i) | |
| frequency *= 2 | |
| amplitude *= persistence | |
| return noise | |
| # Generate grid (for plotting, x and y range from 0 to 1 for simplicity) | |
| size = 512 | |
| xx, yy = np.meshgrid(np.linspace(0, 1, size), np.linspace(0, 1, size)) | |
| # Generate fractal noise; adjust base_res for number of base features (lower = larger features) | |
| base_res = (4, 4) # Reverted for larger features | |
| native = generate_fractal_noise_2d((size, size), base_res, octaves=6, persistence=0.5, seed=0) | |
| # Normalize to [0, 1] | |
| native = (native - native.min()) / (native.max() - native.min()) | |
| # Adjust native for ~50% water relative to blue threshold (0.25), preserving variation in lows | |
| blue_th = 0.25 | |
| sea_level = np.percentile(native, 50) | |
| adjusted_native = native.copy() | |
| water_mask = native < sea_level | |
| land_mask = ~water_mask | |
| # Scale water to [0, blue_th] preserving variation | |
| if np.any(water_mask): | |
| water_min = native.min() | |
| water_max = sea_level | |
| adjusted_native[water_mask] = (native[water_mask] - water_min) / (water_max - water_min) * blue_th | |
| # Scale land to [blue_th, 1] | |
| if np.any(land_mask): | |
| land_min = sea_level | |
| land_max = native.max() | |
| adjusted_native[land_mask] = (native[land_mask] - land_min) / (land_max - land_min) * (1.0 - blue_th) + blue_th | |
| # Define interpolated table with flats for oceans and plains (11 points) | |
| x_points = np.array([0.0, 0.15, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]) | |
| y_points = np.array([0.0, 0.0, 0.05, 0.1, 0.2, 0.35, 0.35, 0.35, 0.5, 0.75, 1.0]) # Flats at 0 (oceans) and 0.35 (plains) | |
| # Apply interpolation for modified | |
| modified = np.interp(native, x_points, y_points) | |
| # Create figure with 2 rows, 2 columns | |
| fig = plt.figure(figsize=(12, 10)) | |
| # 3D plot for adjusted native | |
| ax1 = fig.add_subplot(2, 2, 1, projection='3d') | |
| ax1.plot_surface(xx, yy, adjusted_native, cmap='terrain', rstride=8, cstride=8, antialiased=True, shade=True, linewidth=0) | |
| ax1.set_title('Adjusted Native (3D View)') | |
| ax1.set_zlim(0, 1) | |
| # Histogram for adjusted native | |
| ax2 = fig.add_subplot(2, 2, 3) | |
| ax2.hist(adjusted_native.flatten(), bins=20, color='blue', alpha=0.7) | |
| ax2.set_title('Adjusted Native Height Distribution') | |
| # 3D plot for modified | |
| ax3 = fig.add_subplot(2, 2, 2, projection='3d') | |
| ax3.plot_surface(xx, yy, modified, cmap='terrain', rstride=8, cstride=8, antialiased=True, shade=True, linewidth=0) | |
| ax3.set_title('Modified (3D View)') | |
| ax3.set_zlim(0, 1) | |
| # Histogram for modified | |
| ax4 = fig.add_subplot(2, 2, 4) | |
| ax4.hist(modified.flatten(), bins=20, color='green', alpha=0.7) | |
| ax4.set_title('Modified Height Distribution') | |
| plt.tight_layout() | |
| plt.savefig('terrain_comparison_3d.png') # Save the image | |
| plt.show() # Display interactively |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment