Wednesday 16 August 2023

Perlin Noise in Python: Noise Values Compacted, Need Help Forming Sinusoidal Pattern

I'm currently working on a project involving Perlin noise generation in Python. I've implemented the Perlin noise generation using the noise library and generated different types of noise values (cave, land, hill, mountain) within a chunk using a combination of these noise types.

However, I'm facing an issue with the generated noise values. Instead of the noise values forming a smooth, sinusoidal pattern, they seem to be compacted and lacking the desired variation. As a result, the final noise representation doesn't display the expected terrain features I'm aiming for.

Here's a snippet of my code for the block_perlin_noise method:

import numpy as np
import noise
from typing import List, Dict

# ... unsolicited code

# Define a class to represent a Chunk
class Chunk:
    def __init__(self, geometry: List[int] = (16, 16, 16), position: List[int] = (0, 0, 0),
                 rotation: List[int] = (0, 0, 0)):
        # Validate the input parameters
        if not isinstance(geometry, tuple) or len(geometry) != 3 or all(value == 0 for value in geometry):
            raise TypeError("geometry must be a tuple of length 3 with non-zero values.")
        if not all(isinstance(value, int) for value in position) and all(isinstance(value, int) for value in rotation):
            raise TypeError("position must be a tuple of floats.")
        # Initialize instance variables
        self.geometry = geometry
        self.position = position
        self.rotation = rotation

    # Method to generate Perlin noise for different types of blocks in the chunk
    def block_perlin_noise(self) -> np.ndarray:
        chunk_width, chunk_height, chunk_depth = self.geometry

        # Generate noise values for different types of blocks in the chunk
        # and store them in separate 3D arrays
        cave_noise = np.zeros((chunk_width, chunk_height, chunk_depth), dtype=int)
        land_noise = np.zeros((chunk_width, chunk_height, chunk_depth), dtype=int)
        hill_noise = np.zeros((chunk_width, chunk_height, chunk_depth), dtype=int)
        mountain_noise = np.zeros((chunk_width, chunk_height, chunk_depth), dtype=int)
        # Initialize the chunk noise array
        chunk_noise = np.zeros((chunk_width, chunk_height, chunk_depth, 3), dtype=int)

        for x in range(chunk_width):
            for y in range(chunk_height):
                for z in range(chunk_depth):
                    # Generate Perlin noise for caves
                    cave_noise[x, y, z] = int(noise.pnoise3(
                        (x + self.position[0]) / chunk_width,
                        (y + self.position[1]) / chunk_height,
                        (z + self.position[2]) / chunk_depth,
                        octaves=2,
                        persistence=0.8,
                        lacunarity=1.2,
                        repeatx=chunk_width,
                        repeaty=chunk_height,
                        repeatz=chunk_depth,
                        base=1
                    ))

                    # Generate Perlin noise for land blocks
                    land_noise[x, y, z] = int(noise.pnoise3(
                        (x + self.position[0]) / chunk_width,
                        (y + self.position[1]) / chunk_height,
                        (z + self.position[2]) / chunk_depth,
                        octaves=4,
                        persistence=0.5,
                        lacunarity=1.0,
                        repeatx=chunk_width,
                        repeaty=chunk_height,
                        repeatz=chunk_depth,
                        base=0
                    ))

                    # Generate Perlin noise for hills
                    hill_noise[x, y, z] = int(noise.pnoise3(
                        (x + self.position[0]) / chunk_width,
                        (y + self.position[1]) / chunk_height,
                        (z + self.position[2]) / chunk_depth,
                        octaves=6,
                        persistence=0.5,
                        lacunarity=1.5,
                        repeatx=chunk_width,
                        repeaty=chunk_height,
                        repeatz=chunk_depth,
                        base=1
                    ))

                    # Generate Perlin noise for mountains
                    mountain_noise[x, y, z] = int(noise.pnoise3(
                        (x + self.position[0]) / chunk_width,
                        (y + self.position[1]) / chunk_height,
                        (z + self.position[2]) / chunk_depth,
                        octaves=8,
                        persistence=0.5,
                        lacunarity=2.0,
                        repeatx=chunk_width,
                        repeaty=chunk_height,
                        repeatz=chunk_depth,
                        base=1
                    ))

                    # Combine different noise types to get the final chunk noise
                    chunk_noise[x, y, z] = np.sum([
                        cave_noise[x, y, z],
                        land_noise[x, y, z],
                        hill_noise[x, y, z],
                        mountain_noise[x, y, z]
                    ])

        return chunk_noise
    # ... continuation of my previous code

    def render(self):
        figure = plt.figure()
        axes = figure.add_subplot(111, projection='3d')

        chunk_noise = self.block_perlin_noise()
        for x, y, z in np.ndindex(*self.geometry):
            block_x_value, block_y_value, block_z_value = chunk_noise[x, y, z]
            # You can adjust the size of the points based on the noise values
            axes.scatter(x + self.position[0], y + self.position[1], z + self.position[2], marker='o', s=5)

        axes.set_xlabel('X')
        axes.set_ylabel('Y')
        axes.set_zlabel('Z')
        plt.show()

enter image description here

I'm aiming for a Minecraft chunk terrain-like representation with gradual variations similar to a sin wave, but the noise values are not providing that smoothness and appear to be compressed into one place.

Could anyone help me understand why my noise values are compacted and not forming the expected pattern? Are there any adjustments I can make to the Perlin noise generation parameters or my approach to achieve a smoother, sinusoidal-like pattern in my terrain representation?



from Perlin Noise in Python: Noise Values Compacted, Need Help Forming Sinusoidal Pattern

No comments:

Post a Comment