Skip to content

khritish17/Procedural-3d-terrain-generator

Repository files navigation

Procedural Terrain Generator (PTG)

Download the .zip file (Addon file) from here ⬇️

πŸ’Ύ Download

PTG Addon - Table of Contents

  • 1 PTG Blender-Addon Installation Guide
    • 1.1 Installation Overview
    • 1.2 Install Python: Step 1
    • 1.3 Install Microsoft Visual C++: Step 2
    • 1.4 Install Python library dependencies: Step 3
    • 1.5 Install PTG Addon (in Blender): Step 4
  • 2 Why PTG Blender Addon
    • 2.1 PTG Blender Addon - Pros
  • 3 Perlin Noise: Primer
    • 3.1 Random Noise vs Perlin Noise
      • 3.1.1 Uniform Random Noise
      • 3.1.2 Perlin Noise
    • 3.2 Perlin Noise as Terrain Generator
    • 3.3 Perlin Noise and its "Bell Curve" Tendency
      • 3.3.1 How the - Bell Curve Tendency - is useful in Terrain Generation
  • 4 Perlin Noise Presentation
    • 4.1 Colour Schematic 2D representation
    • 4.2 Terrain Generation 3D (Matplotlib)

PTG Documentation - Table of Contents

Procedural Terrain Generator (PTG) - Blender Addon

1. PTG Blender-Addon Installation Guide

πŸ“Œ Note: The "Procedural Terrain Generator" addon uses the noise Python library for Perlin noise. Since noise is a C extension, it requires Python development headers, which are not included in Blender's embedded Python.

To work around this and keep Blender responsive, we use Inter-Process Communication (IPC). This means:

  • Blender's Python handles the UI and Blender API.
  • A separate, globally installed Python (with the noise library) performs the heavy noise calculations. This offloads computation and prevents Blender from freezing.

To use this addon, you need:

  • Python 3.x (globally installed on your system)
  • Microsoft Visual C++ 14.0 or higher (for Windows, a C++ compiler for noise library compilation)

1.1 Installation Overview

  • Step 1: Install Python in your device
  • Step 2: Install Microsoft Visual C++ 14.0 or greater in your device
  • Step 3: Install the library dependencies
  • Step 4: Install the Blender Addon

1.2 Install Python: Step 1

How to install Python (click to expand)

Python 3.x (globally installed on your system)

Having a global Python installation is crucial for your Blender addon's IPC system.

Steps to install:

For Windows:

  • Download the Installer:
    • Go to the official Python website: https://python.org/downloads/windows/
    • Look for the latest stable Python 3.x.x version (e.g., Python 3.10.x, 3.11.x, or 3.12.x).
    • Download the "Windows installer (64-bit)" executable.
  • Run the Installer:
    • Locate the downloaded .exe file and double-click it to run.
    • Crucial Step: On the first screen of the installer, check the box that says "Add Python X.Y to PATH" (where X.Y is your Python version). This is very important for your addon to find Python.
    • Select "Install Now" (recommended for most users).
    • If prompted by User Account Control (UAC), click "Yes".
  • Complete Installation
    • The installation will proceed. Once finished, you might see a "Setup was successful" message.
    • Click "Close".
  • Verify Installation:
    • Open a new Command Prompt window (search for cmd in Start Menu).
    • Type python --version and press Enter.
    • You should see the installed Python version (e.g., Python 3.10.10).
    • If it says "Python is not recognized...", close the Command Prompt and open a new one. If it still doesn't work, you might need to manually add Python to your PATH or reinstall, ensuring the "Add to PATH" box was checked.

For macOS:

  • Check for Pre-installed Python (and Homebrew):
    • macOS often comes with an older Python 2.x. For Python 3.x, it's highly recommended to use a package manager like Homebrew.
    • Open Terminal (Applications > Utilities > Terminal).
    • Check if Homebrew is installed: brew --version
    • If not installed, install Homebrew:
     /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
     
    

Follow the on-screen instructions, which might include running brew doctor and adding Homebrew to your PATH.

  • Install Python 3 using Homebrew:

    • Once Homebrew is installed, run:
    brew install python
    
    • Homebrew will install the latest Python 3.x and link it correctly.
  • Verify Installation:

    • In the same Terminal window (or open a new one), type python3 --version and press Enter.
    • You should see the installed Python 3.x version (e.g., Python 3.10.10).
    • python --version might still point to an older Python 2.x, but python3 will point to the Homebrew installed version. Your addon's util.py is designed to find python or python3.

For Linux (Ubuntu/Debian-based):

  • Check for Python 3:
    • Most modern Linux distributions come with Python 3 pre-installed.
    • Open Terminal.
    • Type python3 --version and press Enter. You'll likely see a version like Python 3.8.10 or newer.
  • Install if Missing or for Specific Version:
    • If Python 3 is not installed or you need a specific version, use your distribution's package manager.
    • For Ubuntu/Debian-based systems:
       sudo apt update
       sudo apt install python3
       sudo apt install python3-pip # Install pip for Python 3
       sudo apt install python3-dev # Essential for compiling C extensions like 'noise'
      
      • python3-dev (or similar package name like python3-devel on Fedora/RHEL) provides the necessary Python development headers.
  • Verify Installation: - Type python3 --version and pip3 --version to confirm.

1.3 Install Microsoft Visual C++: Step 2

How to install Microsoft Visual C++ (click to expand)

Microsoft Visual C++ 14.0 or greater is required

Steps to install:

  • Download Visual Studio Build Tools:
    • Go to the official Visual Studio downloads page: https://visualstudio.microsoft.com/downloads/
    • Scroll down to the "Tools for Visual Studio" section.
    • Look for "Build Tools for Visual Studio 2022" (or the latest available version, e.g., 2019). Click the Download button next to it.
  • Run the Installer:
    • Once the vs_buildtools__*.exe file is downloaded, run it.
    • The Visual Studio Installer will open.
  • Select Workloads:
    • In the installer, go to the Workloads tab.
    • Crucially, select Desktop development with C++. This workload includes the C++ compilers and libraries that Python needs.
  • Install:
    • Click the Install button. The installation might take some time as it downloads and sets up the components.
  • Restart (Optional but Recommended):
    • After the installation completes, it's a good idea to restart your computer, although it's not always strictly necessary. This ensures all environment variables are correctly set.

πŸ“Œ Alternate to Microsoft Visual C++

MinGW-w64 is a much lighter-weight alternative to installing the full Visual Studio Build Tools. It provides a GCC (GNU Compiler Collection) environment that can compile C/C++ code for Windows.

Pros of MinGW-w64:

  • Smaller Size: Significantly smaller download and installation footprint compared to Visual Studio.
  • Open Source: Fully open-source compiler toolchain.
  • Cross-Platform Familiarity: If you're used to GCC on Linux, MinGW-w64 provides a similar environment on Windows.

Cons of MinGW-w64 (in this context):

  • Setup Can Be Tricky: While smaller, getting MinGW-w64 set up correctly and ensuring pip finds it can sometimes be less straightforward than with MSVC, which Python's official installers are often pre-configured to work with.
  • Potential Compatibility: Very rarely, some C extensions might have specific build flags or code that is more optimized or compatible with MSVC, but for common libraries like noise, GCC usually works fine.

1.4 Install Python library dependencies: Step 3

open your terminal/command prompt and run the following command:

pip install numpy noise

After installing the Python, Microsoft Visual C++ and other library dependencies, download the PTG Blender Addon from here

1.5 Install PTG Addon (in Blender): Step 4

  • Open Blender: Launch your Blender application.
  • Go to Preferences:
    • In Blender, go to Edit (top menu bar) > Preferences....
  • Navigate to Add-ons:
    • In the Blender Preferences window, click on the Add-ons tab on the left sidebar.
  • Click "Install...":
    • At the top right of the Add-ons tab, you'll see a button labeled Install.... Click it.
  • Browse to your Addon Folder:
    • A file browser window will appear. Navigate to the location where you have downloaded the Procedural_Terrain_Generator.zip file.
    • Important: Do NOT unzip the Procedural_Terrain_Generator.zip file
    • Select the Procedural_Terrain_Generator.zip file
    • Click the Install Add-on button in the file browser.
  • Search for the Addon:
    • After clicking "Install Add-on", you'll be returned to the Add-ons tab in Preferences.
    • In the search bar (top left of the Add-ons tab), type Procedural Terrain Generator
  • Activate the Checkbox:
    • The addon, "Procedural Terrain Generator," should appear in the list.
    • Check the checkbox next to its name to enable it.
  • Save the preferences:
    • To ensure the addon remains enabled every time you open Blender, click the ☰ (three-line) icon at the bottom-left of the Preferences window and select Save Preferences.
  • Close Preferences: Close the Blender Preferences window.
  • Open the N-Panel: In the 3D Viewport, press the N key on your keyboard. This will open the sidebar (also known as the N-panel or Properties panel) on the right side of the viewport.
  • Find the "PTG Tools" Tab:
    • Look for a new tab in the N-panel labeled "PTG Tools".
    • Click on this tab.
  • Use the Addon:
    • You should now see the "Terrain Generator Properties" panel with all your sliders and buttons.
    • Click the "Generate Terrain" button to create your first terrain!

2 Why PTG Blender Addon

It's an insightful question that why would someone choose PTG Blender Addon, while Blender does has its own buit-in noise capabilities, primarily exposed through:

  1. mathutils.noise module: A Python module that provides various noise Function (Perlin, Simplex, Voronoi, etc) directly accessaible via Python.
  2. Shader Nodes: These are visual nodes used in Blender's material and geometry node editors, which are highly optimized C/C++ implementations of various noise algorithms. While not directly callable from Python in the same way, they represent Blender's native noise generation.

2.1 PTG Blender Addon - Pros

PTG blender addon's approach offers distinct advantages, particularly for the specific problem of generating large-scale, complex terrain:

  • Access to Specialized, Optimized Libraries:
    • The noise library (which the PTG addon uses) is a dedicated, highly optimized C-extension for Perlin and Simplex noise. It's often faster and more robust for these specific noise types than Blender's more general-purpose mathutils.noise.
    • This allows to leverage cutting-edge or specialized noise algorithms that might not be exposed or implemented in Blender's core API.
  • True Offloading (IPC):
    • This is the biggest advantage. By running the heavy noise computation in a separate Python process, PTG addon prevents Blender's main thread from freezing.
    • When a user drag a slider, Blender's UI remains responsive, even if the external script takes a moment to calculate. This is a massive improvement in user experience for computationally intensive tasks.
    • If one uses mathutils.noise directly in Blender's main Python thread for a 1000x1000 terrain, Blender would likely become unresponsive ("Not Responding") while it computes.
  • Flexibility and Maintainability: (Developers perspective)
    • Separating the core noise logic into an external script makes it more modular. Any developer could potentially swap out the noise library for another (e.g., opensimplex, perlin_noise) without needing to re-architect the Blender addon's core.
    • It decouples the noise generation from Blender's specific Python environment, making it easier to manage dependencies that Blender doesn't natively support.
  • Reproducibility (Precise Noise Algorithm):
    • If a very specific implementation of Perlin or Simplex noise (e.g., for compatibility with other software or specific visual styles) is needed, using a well-defined external library like noise ensures that exact algorithm is used, whereas Blender's internal PERLIN_ORIGINAL or PERLIN_NEW might have subtle differences.

3 Perlin Noise: Primer

Perlin noise is a revolutionary gradient noise function developed by Ken Perlin in 1983. Its primary purpose was to create more natural-looking textures and visual effects in computer graphics, moving away from the rigid, "machine-like" appearance of earlier CGI.

Perlin Noise Algorithm Details

In terrain generation, Perlin noise acts as a heightmap generator, where each point's noise value corresponds to an elevation. Here's why it's so fundamental and how it works:

  1. Smoothness and Coherence: Unlike pure random noise, Perlin noise generates values that transition smoothly from one point to the next. This inherent spatial coherence is crucial for terrain, as it prevents abrupt, unrealistic spikes and creates natural-looking hills, valleys, and plateaus. Imagine real landscapes: elevation changes are generally gradual, not sudden jumps.
  2. Gradient-Based: At its core, Perlin noise defines a grid of random gradient vectors. For any given point in space (e.g., an (x,y) coordinate on a 2D map), the algorithm interpolates between the influence of these surrounding gradient vectors. This interpolation is what ensures the smooth, flowing patterns.
  3. Fractal Brownian Motion (FBM) / Octaves: The true power of Perlin noise for terrain comes from combining multiple layers, or "octaves," of the noise function.
    • Each octave is a Perlin noise function with a different frequency (how "zoomed in" or "zoomed out" the pattern is) and amplitude (how much it contributes to the overall height).
    • By summing these octaves, typically with higher frequencies having lower amplitudes (controlled by persistence), you create fractal detail. This allows for large-scale features like mountain ranges, mid-scale hills and valleys, and fine-scale details like bumps and rocks, all contributing to a realistic, organic appearance.
  4. Parameters for Control: Key parameters allow designers to sculpt the terrain's characteristics:
    • Scale/Frequency: Determines the overall size of features. A small scale (high frequency) creates choppy, detailed terrain; a large scale (low frequency) creates smooth, rolling hills.
    • Octaves: The number of layers of noise added. More octaves generally mean more detail and complexity.
    • Persistence: Controls how quickly the amplitude decreases for each successive octave. Higher persistence creates more rugged, mountainous terrain, while lower persistence results in smoother landscapes.
    • Lacunarity: Dictates how much the frequency increases with each successive octave. A value of 2.0 (common) means each octave's frequency is double the previous one.
    • Seed: A crucial parameter for reproducibility. Using the same seed will always generate the exact same noise pattern, which is vital for persistent game worlds or repeatable experiments.

3.1 Random Noise vs Perlin Noise

Uniform random noise and Perlin noise are both methods for generating random values, but they differ significantly in their characteristics and applications.

3.1.1 Uniform Random Noise

What it is: Uniform random noise generates values where each outcome in a given range has an equal probability of occurring. Imagine rolling a fair die: each number from 1 to 6 has an equal chance of appearing. When visualized, it looks like scattered, unrelated points.

How it works (conceptually): Typically generated by a pseudo-random number generator (PRNG) which produces a sequence of numbers that approximate true randomness.

3.1.2 Perlin Noise

What it is: Perlin noise is a gradient noise that produces a more "natural" or "organic" feel. Instead of abrupt jumps, values transition smoothly from one to another, creating patterns that resemble clouds, fire, or terrain.

How it works (conceptually): It works by defining a grid of random gradient vectors. Then, for any point within the grid, it interpolates (smoothly blends) between the surrounding gradient vectors. This interpolation is what gives Perlin noise its characteristic smoothness.

In essence, Perlin noise provides a robust and computationally efficient way to generate varied, natural-looking landscapes for games, simulations, and visual effects, avoiding the repetitive patterns of tiled textures or the chaotic nature of pure random values.

3.2 Perlin Noise as Terrain Generator

Perlin noise is overwhelmingly preferred for terrain generation due to its ability to create realistic, undulating landscapes:

  • Smooth Transitions: Unlike uniform random noise which creates harsh, disjointed peaks and valleys, Perlin noise generates smooth, gradual changes in elevation. This mimics the natural contours of real-world terrain.
  • Controllable Detail: By combining multiple layers of Perlin noise at different frequencies (octaves), you can achieve varying levels of detail, from large-scale geographical features to small bumps and ripples.
  • Coherence: Perlin noise exhibits spatial coherence, meaning nearby points have similar values. This is crucial for creating continuous mountain ranges, valleys, and plateaus. Uniform random noise lacks this coherence, resulting in a chaotic and unrealistic landscape.

Feature Uniform Random Noise Perlin Noise
Output Disjointed, unpredictable values Smooth, coherent, and continuous patterns
Nature Truly "random" (or pseudo-random) Gradient noise based on interpolation
Spatial Relation No relationship between neighboring points Values are related to their neighbors (coherence)
Appearance "Static" or "snowy" "Organic," "cloud-like," or "fluid"
Use Case Lotteries, statistical sampling Procedural generation, animation, special effects

3.3 Perlin Noise and its "Bell Curve" Tendency

The core Perlin noise function itself, when properly implemented and normalized, typically produces values within a range like [βˆ’1,1] (or [0,1] if remapped). The distribution of these individual values might not be a perfect Gaussian bell curve, but it does tend to concentrate values around the center of its range, with fewer values at the extremes.

The "bell curve" effect becomes more pronounced and useful when you employ a technique called Fractal Brownian Motion (FBM), also known as multi-octave noise.

This involves:

  • Layering multiple Perlin noise functions: Each layer (octave) has a different frequency and amplitude.
    • Frequency: Determines the "scale" of the details. Low frequencies create large, broad features (like major hills). High frequencies create small, fine details (like pebbles or ripples).
    • Amplitude: Determines the "strength" or height of the features.
  • Summing the results: The outputs of these octaves are added together, usually with decreasing amplitude for higher frequencies (a parameter often called "persistence").

When you combine multiple octaves in this way, the central limit theorem starts to come into play. Even if the individual Perlin noise octaves aren't perfectly normal, their sum tends towards a normal distribution.

This means:

  • Most values will be near the "average": In terrain generation, this translates to most of the landscape being at a mid-level elevation.
  • Extreme values (very high peaks or very deep valleys) are less common: This creates a natural distribution of terrain features, where towering mountains and deep abysses are rare, just like in the real world.

3.3.1 How the - Bell Curve Tendency - is useful in Terrain Generation

The tendency of multi-octave Perlin noise to exhibit a near-normal distribution is incredibly useful for creating realistic terrain:

  • Realistic Elevation Distribution: It ensures that you naturally get more mid-level terrain (plains, rolling hills) and fewer extreme features (super-high mountains or impossibly deep canyons). This mirrors the statistical distribution of elevations on Earth.
  • Natural Variety: While the overall distribution tends towards a bell curve, the underlying Perlin noise still provides local variation and coherence. This means you don't get perfectly flat plains, but rather subtle undulations and variations that feel organic.
  • Controllable Features: By adjusting the parameters of FBM (number of octaves, frequency, amplitude, persistence), you can manipulate the "bell curve" to sculpt different types of terrain:
    • High persistence (slow amplitude decay): More jagged, mountainous terrain with a wider range of elevations.
    • Low persistence (fast amplitude decay): Smoother, rolling hills or flatter plains with a narrower range of elevations.
  • Procedural Realism: Without this statistical property, you'd either have overly flat terrain or a chaotic, spiky mess. The quasi-normal distribution helps to create landscapes that look plausible without requiring manual sculpting or complex geological simulations.

4 Perlin Noise Presentation

4.1 Colour Schematic 2D representation

A basic example of procedural terrain generation using Perlin noise. It creates a height map, interprets different height ranges as different terrain features (like water, land, and vegetation), and then visualizes this terrain using colored dots. The parameters of the Perlin noise function allow for significant control over the generated landscape's appearance.

Image generation through matplotlib is costly (heavy time consuming). Hence PIL library in python for image manipulation is used.

4.2 Terrain Generation 3D (Matplotlib)

The code creates a procedural terrain generator. It uses two layers of Perlin noise: a "base noise" for the overall landscape shape and a "height noise" to modulate (influence) the base noise, adding more intricate details and variations to the elevation. The generated height values are then scaled to a specified minimum and maximum height.

The output is a 3D surface plot displayed using Matplotlib. This plot visually represents the generated terrain, with colors typically indicating elevation (e.g., lower areas might be blue, higher area red or yellow, depending on the coolwarm colormap).

It aims to procedurally generate a realistic-looking 3D terrain. By combining multiple Perlin noise functions and carefully controlling their parameters, it simulates the complex and varied topography found in natural landscapes, from subtle undulations to more pronounced peaks and valleys, and then renders this as a 3D surface.

Documentation

1 PTG Blender Addon - Structure

Procedural_Terrain_Generator.zip
└── πŸ“ Procedural_Terrain_Generator/
    └── πŸ“ __init__.py
    └── πŸ“ operators.py
    └── πŸ“ perlin_height_map.py
    └── πŸ“ python_exe_path.txt
    └── πŸ“ ui.py
    └── πŸ“ ui_properties.py
    └── πŸ“ util.py

2 PTG Blender Addon - Documentation

└── πŸ“ __init__.py - Documentation

__init__.py file serves as the entry point and core configuration file for the "Procedural Terrain Generator" Blender addon

  1. File Purpose: The __init__.py file acts as the primary script that Blender executes to register, enable, and disable the addon. It defines the addon's metadata, registers all necessary classes (operators, UI panels, properties), and handles any setup or cleanup routines.

  2. Addon Information (bl_info) The bl_info dictionary contains crucial metadata about the addon, which Blender uses to display information in the Addons preferences and manage its lifecycle.

    • name: "Procedural Terrain Generator"
      • The user-friendly name of the addon displayed in Blender's Addons preferences.
    • author: "Khritish Kumar Behera"
      • The name of the addon's creator.
    • version: (1, 0)
      • A tuple representing the addon's version number (major, minor).
    • blender: (3, 0, 0)
      • The minimum Blender version required for this addon to function correctly.
    • location: "3D View > Sidebar > Terrain Generator Properties"
      • Indicates where the addon's user interface can be found within Blender. In this case, it's a panel in the 3D Viewport's sidebar.
    • description: "To generate infinite terrain seamlessly using Perlin noise."
      • A brief description of the addon's primary functionality.
    • warning: ""
      • An optional field for any warnings or known issues. Currently empty.
    • doc_url: "https://github.com/khritish17/Procedural-3d-terrain-generator/blob/master/README.md"
      • A URL pointing to the addon's documentation or repository.
    • category: "Mesh"
      • The category under which the addon will be listed in Blender's Addons preferences, helping users find it.
  3. Registered Classes (classes) The classes list enumerates all the Python classes that need to be registered with Blender when the addon is enabled. These classes typically define:

    • ui_properties.PTG_Properties: Custom properties specific to the terrain generator, which will be accessible via Blender's data system.
    • ui.PTG_UI: The user interface panel(s) that will appear in the specified location (3D View > Sidebar).
    • operators.PTG_Generate_Operator: The operator(s) that perform actions, such as generating the terrain.
  4. register() Function The register() function is called by Blender when the addon is enabled. It performs all necessary setup tasks.

    • addon_dir = os.path.dirname(bpy.path.abspath(__file__)):
      • This line determines the absolute path to the directory where the addon's __init__.py file is located. This path is crucial for locating other addon files, such as util.py.
    • util.check_and_configure(addon_dir):
      • This call invokes a function from the util module. Its purpose is to ensure that the necessary environment is set up for the addon, specifically by checking for and configuring the path to the global Python executable. This is often required when an addon depends on external Python libraries (like a noise library) that might not be bundled with Blender's internal Python. The path is typically saved to a file (e.g., python_exe_path.txt) for later use.
    • for cls in classes: bpy.utils.register_class(cls):
      • This loop iterates through the classes list and registers each class with Blender. Registration makes these classes available for use within Blender, allowing their UI elements to appear, operators to be called, and properties to be accessible.
    • bpy.types.Scene.ptg_props = bpy.props.PointerProperty(type=ui_properties.PTG_Properties):
      • This line creates a custom pointer property named ptg_props on Blender's Scene data block. This pointer property is of the type ui_properties.PTG_Properties. This allows the addon's custom settings and variables (defined in PTG_Properties) to be stored and accessed globally within the Blender scene, making them persistent and editable through the UI.
  5. unregister() Function The unregister() function is called by Blender when the addon is disabled. It's crucial for cleaning up any resources or registrations made by the addon to prevent conflicts or memory leaks.

    • Timer Unregistration:

      if ui_properties._update_timer_handle is not None:
          try:
              bpy.app.timers.unregister(ui_properties._update_timer_handle)
              ui_properties._update_timer_handle = None
              print("-> PTG log: Unregistered terrain update timer")
          except ValueError:
              pass
      
      • This block checks if a timer handle (_update_timer_handle) exists, which is likely used for periodically updating the terrain (e.g., when properties change). If it exists, the timer is unregistered from Blender's application timers to stop its execution. The try-except block handles cases where the timer might have already been unregistered or is invalid, preventing errors during cleanup.
    • Property Deletion:

      if hasattr(bpy.types.Scene, 'ptg_props'):
      	del bpy.types.Scene.ptg_props
      
      • This checks if the custom ptg_props pointer property was successfully added to the Scene data block. If it exists, it is deleted, removing the addon's custom properties from the scene.
    • Class Unregistration:

      for cls in reversed(classes):
          bpy.utils.unregister_class(cls)
      
      • This loop iterates through the classes list in reverse order and unregisters each class from Blender. Unregistering in reverse order is a common practice to ensure that dependencies are correctly handled (e.g., UI panels that might rely on properties are unregistered before the properties themselves). This removes the addon's UI elements, operators, and property definitions from Blender.
  6. Conclusion The __init__.py file is the backbone of the "Procedural Terrain Generator" addon, orchestrating its integration with Blender. It provides essential metadata, registers all functional components, and manages the addon's lifecycle by handling both setup (register) and cleanup (unregister) operations.

└── πŸ“ util.py - Documentation


The util.py file contains utility functions for the "Procedural Terrain Generator" Blender addon.

  1. File Purpose The util.py file is designed to encapsulate helper functions that perform system-level checks and configurations necessary for the proper functioning of the Blender addon. Its primary role is to locate and store the path to the global Python executable, which is often required when an addon needs to interact with external Python libraries or processes not directly bundled with Blender's Python environment.
  2. Functions
    • check_and_configure(addon_dir)
      • This function checks for the existence of a file named python_exe_path.txt within the addon's directory. If this file does not exist, it attempts to locate the global Python executable and saves its path into the python_exe_path.txt file.

      • Parameters:

        • addon_dir (str): The absolute path to the directory where the addon's files are located. This path is used to construct the full path for python_exe_path.txt.
      • Functionality:

        • Construct File Path: It first constructs the full path to python_exe_path.txt by joining addon_dir with the filename.
        • Check Existence: It checks if python_exe_path.txt already exists.
        • Configuration (if not found):
          • If the file is not found, it prints a log message indicating this.
          • It then calls the get_python_exe() function to attempt to find the global Python executable.
          • If get_python_exe() successfully returns a path, it writes this path into python_exe_path.txt.
          • If get_python_exe() returns None (meaning no Python executable was found), an error message is logged.
        • Logging: Throughout its execution, it prints log messages to the console indicating its progress and any issues encountered.
      • Purpose: This function ensures that the addon has a persistent record of the global Python executable's location, which can be crucial for running external scripts or installing dependencies.

    • get_python_exe()
      • This function attempts to locate the path to a global Python executable on the user's system. It uses system-specific commands (where for Windows, which for macOS/Linux) to find the python or python3 executable.
      • Returns:
        • str: The absolute path to the Python executable if found.
        • None: If no Python executable is found or if the operating system is unsupported.
      • Functionality:
        • Platform Detection: It determines the current operating system using sys.platform.
        • Command Selection:
          • For Windows (win): It sets the command to ["where", "python", "where", "python3"].
          • For macOS (darwin) or Linux (linux): It sets the command to ["which", "python", "which", "python3"].
          • For unsupported platforms, it logs a warning and returns None.
        • Execute Commands: It iterates through the chosen commands (first trying python, then python3).
          • It uses subprocess.run() to execute the command in the system's shell.
          • check=True: Raises an exception if the command returns a non-zero exit code (indicating an error).
          • text=True: Decodes stdout and stderr as text.
          • capture_output=True: Captures stdout and stderr.
          • env=os.environ.copy(): Ensures the command runs with the current environment variables.
        • Process Output: If a command successfully finds a Python executable, its path (stripped of whitespace) is returned immediately.
        • Error Handling: If subprocess.run() encounters an error (e.g., command not found, or check=True fails), it catches the exception, logs an error message, and continues to the next command (if any).
        • No Executable Found: If none of the commands succeed in finding a Python executable, the function returns None.
      • Purpose: This function provides a robust way to programmatically discover the location of the Python interpreter installed on the user's system, which is critical for external process execution.
  3. Conclusion The util.py file plays a vital role in the "Procedural Terrain Generator" addon by handling system-level interactions to ensure that external Python dependencies can be correctly managed and utilized. It centralizes the logic for locating the Python executable, making the addon more self-sufficient and portable across different user environments.

└── πŸ“ ui.py - Documentation


ui.py file defines the user interface (UI) panel for the "Procedural Terrain Generator" Blender addon.

  1. File Purpose

    • The ui.py file is responsible for creating a custom panel within Blender's user interface. This panel allows users to interact with and control the parameters of the procedural terrain generation. It leverages Blender's UI system to display custom properties and trigger addon operations.
  2. Class: PTG_UI

    • The PTG_UI class inherits from bpy.types.Panel, making it a custom UI panel that can be displayed in Blender.
    1. Panel Properties: These class attributes define the behavior and appearance of the UI panel within Blender:
      • bl_label: "Terrain Generator Properties"
        • This string is displayed as the title at the top of the panel in the Blender UI.
      • bl_idname: "PTG_PT_terrain_generator"
        • A unique identifier for this panel. Blender uses this ID to reference the panel internally. It typically follows a convention like ADDON_PREFIX_PT_panel_name.
      • bl_space_type: 'VIEW_3D'
        • Specifies the Blender editor space where this panel will appear. 'VIEW_3D' means it will be visible in the 3D Viewport. Other common values include 'PROPERTIES', 'NODE_EDITOR', etc.
      • bl_region_type: 'UI'
        • Defines the specific region within the bl_space_type where the panel will be placed. 'UI' corresponds to the 'N' panel (the sidebar on the right side of the 3D Viewport). Other regions include 'TOOLS' (for the 'T' panel on the left).
      • bl_category: "PTG Tools"
        • This string determines the name of the tab under which the panel will be grouped in the sidebar (N-panel). Users can select this tab to reveal the "Terrain Generator Properties" panel.
    2. draw(self, context) Method: The draw method is the core of any Blender UI panel. It is automatically called by Blender to render the contents of the panel. Within this method, you define the layout and the UI elements (buttons, properties, labels, etc.) that the user will see.
      • Parameters:

        • self: The instance of the PTG_UI panel itself.
        • context: A bpy.context object, which provides access to Blender's current state, including the active scene, selected objects, and user preferences.
      • Functionality:

        1. Get Layout and Scene:

          • layout = self.layout: Retrieves the layout object, which is used to add UI elements to the panel.
          • scene = context.scene: Gets the current scene data block from the context.
        2. Access Custom Properties:

          • ptg_props = scene.ptg_props: Accesses the custom property group (PTG_Properties) that was registered in __init__.py and attached to the bpy.types.Scene. This provides a convenient way to get and set the addon's specific parameters.
        3. Terrain Dimension / Offsets Section:

          • box = layout.box(): Creates a visually grouped box within the panel for better organization.
          • box.label(text = "Terrain Dimension / Offsets:"): Adds a label to the box.
          • col = box.column(align=True): Creates a column layout within the box, with align=True to align elements neatly.
          • col.prop(ptg_props, "terrain_length"), col.prop(ptg_props, "terrain_width"), col.prop(ptg_props, "offset_x"), col.prop(ptg_props, "offset_y"): These lines add UI controls (properties) to the column. Each prop() call creates an input field or slider linked to the corresponding property defined in ptg_props (which comes from ui_properties.PTG_Properties).
        4. Terrain Base Noise Properties Section:

          • Similar to the dimension section, this creates another box for properties related to the base Perlin noise used for terrain generation.
          • It displays properties like terrain_seed, terrain_scale, terrain_octaves, terrain_persistence, and terrain_lacunarity.
        5. Terrain Height Noise Properties Section:

          • This section focuses on properties for height modulation using another Perlin noise layer.
          • It includes height_seed, height_scale, height_octaves, height_persistence, height_lacunarity, min_height, and max_height.
        6. Generate Button:

          • layout.separator(): Adds a visual separator line for better spacing.
          • row = layout.row(align = True): Creates a row layout for the button.
          • row.scale_y = 1.5: Increases the vertical scale of the button, making it larger and more prominent.
          • row.operator("ptg.generate_terrain", icon='MESH_PLANE'): Adds a button to the row.
            • "ptg.generate_terrain": This is the bl_idname of the operator that will be executed when the button is clicked (this operator is defined in operators.py).
            • icon='MESH_PLANE': Assigns a Blender built-in icon to the button, making it more visually intuitive.
  3. Conclusion The ui.py file is crucial for providing an intuitive and organized interface for the "Procedural Terrain Generator" addon. By defining the PTG_UI panel and its draw method, it exposes all the necessary parameters and actions to the user within Blender's 3D Viewport, enabling easy customization and generation of terrains.

└── πŸ“ ui_properties.py - Documentation


ui_properties.py file defines the custom properties and the update logic for the "Procedural Terrain Generator" Blender addon.

  1. File Purpose

    • The ui_properties.py file is central to managing the data and user-driven updates for the terrain generator. It defines a PropertyGroup to hold all the configurable parameters for terrain generation (like dimensions, noise seeds, scales, etc.). Crucially, it also implements a debounced update mechanism, ensuring that changes to these properties automatically trigger a regeneration of the terrain mesh without excessive calls to the generation operator.
  2. Global Variable: _update_timer_handle

    • _update_timer_handle = None:
      • This global variable is used to store the handle of a Blender application timer. This timer is essential for implementing debouncing. When a property linked to update_terrain_mesh_debounced is changed, a timer is set. If another property is changed before the timer fires, the old timer is unregistered and a new one is set. This prevents the terrain from regenerating immediately and repeatedly with every small adjustment, improving performance and user experience. It's initialized to None to indicate no active timer.
  3. Function: update_terrain_mesh_debounced(self, context)

    • This function serves as a callback for property updates. It implements a debouncing mechanism to prevent the terrain mesh from being regenerated too frequently when multiple properties are adjusted in quick succession.

    • Parameters:

      • self: The instance of the PropertyGroup (PTG_Properties) that triggered the update.
      • context: A bpy.context object, providing access to Blender's current state.
    • Functionality:

      1. Clear Existing Timer:

        global _update_timer_handle
        if _update_timer_handle is not None:
        	try:
        		bpy.app.timers.unregister(_update_timer_handle)
        		_update_timer_handle = None
        	except ValueError:
        		_update_timer_handle = None
        
        • This block first accesses the global _update_timer_handle.
        • If an existing timer is active, it attempts to unregister it. This is the core of debouncing: any previous pending update is cancelled.
        • A try-except ValueError is used to gracefully handle cases where the timer might have already fired or been unregistered, preventing errors.
      2. Check for Existing Terrain Object:

        if "PTG_Terrain_object" in bpy.data.objects and bpy.data.objects["PTG_Terrain_object"].type == 'MESH':
        
        • This condition checks if an object named "PTG_Terrain_object" exists in the scene and if it is a mesh type. This ensures that the terrain generation is only triggered if there's an existing terrain object to update.
      3. Define Inner Update Function:

        def update_terrain_mesh():
        		print("UPdate trigred in ui_properties")
        		bpy.ops.ptg.generate_terrain('INVOKE_DEFAULT')
        		global _update_timer_handle
        		_update_timer_handle = None
        		return None
        
        • An inner function update_terrain_mesh is defined. This function contains the actual logic to be executed after the debounce delay.
        • It prints a log message.
        • bpy.ops.ptg.generate_terrain('INVOKE_DEFAULT'): This is the crucial line that calls the terrain generation operator. 'INVOKE_DEFAULT' ensures the operator runs with its default invocation context.
        • It resets _update_timer_handle to None after the update is triggered, indicating that the timer has fired.
      4. Register New Timer:

        _update_timer_handle = bpy.app.timers.register(update_terrain_mesh, first_interval=0.05)
        
        • A new timer is registered with Blender's application timers.
        • update_terrain_mesh: The function to be called when the timer expires.
        • first_interval=0.05: The delay in seconds before the update_terrain_mesh function is called. This short delay allows for multiple property changes to occur before a single terrain regeneration is triggered.
    • Purpose: To provide a smooth and efficient user experience by preventing constant, immediate terrain regeneration while a user is adjusting multiple parameters.

  4. Class: PTG_Properties

    • The PTG_Properties class inherits from bpy.types.PropertyGroup. This class is a container for all the custom properties that will be exposed in the addon's UI panel. Each property is defined using Blender's property types (IntProperty, FloatProperty) and includes metadata like name, description, default values, min/max ranges, and importantly, an update callback.

    • General Property Attributes: Each property typically includes:

      • name: (str) The label displayed next to the property in the UI.
      • description: (str) A tooltip that appears when the user hovers over the property in the UI. It provides detailed information about the property's purpose and effect.
      • default: The initial value of the property.
      • min: The minimum allowed value for the property.
      • max: The maximum allowed value for the property.
      • step: (For FloatProperty) The increment/decrement step when dragging the slider or using arrow keys.
      • precision: (For FloatProperty) The number of decimal places displayed.
      • update: (function) A callback function that is executed whenever the property's value changes. In this case, update_terrain_mesh_debounced is used for most properties to trigger terrain regeneration.
    • Terrain Dimension / Offsets Properties: These properties control the size and position of the generated terrain.

      • terrain_length: (bpy.props.IntProperty)
        • Name: "Terrain Length"
        • Description: Number of vertices along the X-axis.
        • Default: 100
        • Range: 2 to 1000
      • terrain_width: (bpy.props.IntProperty)
        • Name: "Terrain Width"
        • Description: Number of vertices along the Y-axis.
        • Default: 100
        • Range: 2 to 1000
      • offset_x: (bpy.props.FloatProperty)
        • Name: "Offset X"
        • Description: Shifts the noise pattern horizontally (along X-axis) to generate different sections of the 'infinite' noise landscape.
        • Default: 0.0
        • Range: -10000.0 to 10000.0
        • Update Callback: update_terrain_mesh_debounced
      • offset_y: (bpy.props.FloatProperty)
        • Name: "Offset Y"
        • Description: Shifts the noise pattern vertically (along Y-axis).
        • Default: 0.0
        • Range: -10000.0 to 10000.0
        • Update Callback: update_terrain_mesh_debounced
    • Terrain Base Noise Properties: These properties control the parameters of the primary Perlin noise used to define the overall shape of the terrain.

      • terrain_seed: (bpy.props.IntProperty)

        • Name: "Terrain Seed"
        • Description: An integer seed for reproducible noise patterns.
        • Default: 0
        • Range: -100000 to 100000
        • Update Callback: update_terrain_mesh_debounced
      • terrain_scale: (bpy.props.FloatProperty)

        • Name: "Terrain Scale"
        • Description: Controls the zoom level of noise features. Larger values mean larger, smoother features; smaller values mean smaller, more jagged details.
        • Default: 100.0
        • Range: 1.0 to 1000.0
        • Update Callback: update_terrain_mesh_debounced
      • terrain_octaves: (bpy.props.IntProperty)

        • Name: "Terrain Octaves"
        • Description: The number of noise layers (fractal sum) to add detail. Higher values add more detail but increase computational cost.
        • Default: 6
        • Range: 1 to 10
        • Update Callback: update_terrain_mesh_debounced
      • terrain_persistence: (bpy.props.FloatProperty)

        • Name: "Terrain Persistence"
        • Description: How much each successive octave contributes to amplitude (roughness). 0.5 is common for fractal Brownian motion (fBm).
        • Default: 0.5
        • Range: 0.0 to 1.0
        • Update Callback: update_terrain_mesh_debounced
      • terrain_lacunarity: (bpy.props.FloatProperty)

        • Name: "Terrain Lacunarity"
        • Description: How much the frequency of each successive octave increases. 2.0 is common for fractal-like appearance.
        • Default: 2.0
        • Range: 1.0 to 3.5
        • Update Callback: update_terrain_mesh_debounced
    • Terrain Height Properties (Height Modulation): These properties control a secondary Perlin noise layer used to modulate the height of the terrain, adding more complexity.

      • height_seed: (bpy.props.IntProperty)
        • Name: "Height Seed"
        • Description: An integer seed for the height modulation noise.
        • Default: 0
        • Range: -100000 to 100000
        • Update Callback: update_terrain_mesh_debounced
      • height_scale: (bpy.props.FloatProperty)
        • Name: "Height Scale"
        • Description: Zoom level for height modulation noise features.
        • Default: 100.0
        • Range: 1.0 to 1000.0
        • Update Callback: update_terrain_mesh_debounced
      • height_octaves: (bpy.props.IntProperty)
        • Name: "Height Octaves"
        • Description: Number of noise layers for height modulation.
        • Default: 6
        • Range: 1 to 10
        • Update Callback: update_terrain_mesh_debounced
      • height_persistence: (bpy.props.FloatProperty)
        • Name: "Height Persistence"
        • Description: Amplitude contribution of successive octaves for height modulation.
        • Default: 0.5
        • Range: 0.0 to 1.0
        • Update Callback: update_terrain_mesh_debounced
      • height_lacunarity: (bpy.props.FloatProperty)
        • Name: "Height Lacunarity"
        • Description: Frequency increase of successive octaves for height modulation.
        • Default: 2.0
        • Range: 1.0 to 3.5
        • Update Callback: update_terrain_mesh_debounced
      • min_height: (bpy.props.FloatProperty)
        • Name: "Min Height"
        • Description: The absolute minimum height of the generated terrain mesh.
        • Default: 10.0
        • Range: -1000.0 to 1000.0
        • Update Callback: update_terrain_mesh_debounced
      • max_height: (bpy.props.FloatProperty)
        • Name: "Max Height"
        • Description: The absolute maximum height of the generated terrain mesh.
        • Default: 100.0
        • Range: -1000.0 to 1000.0
        • Update Callback: update_terrain_mesh_debounced
  5. Conclusion The ui_properties.py file is fundamental to the interactivity and configurability of the "Procedural Terrain Generator" addon. By defining a comprehensive set of custom properties and implementing an efficient debouncing mechanism, it allows users to dynamically adjust terrain parameters and see the results updated in real-time within Blender, without performance bottlenecks.

└── πŸ“ operators.py - Documentation


operators.py file contains the core logic for generating the procedural terrain mesh within the Blender addon. It defines a class for handling terrain mesh creation and an operator that integrates this functionality into Blender's UI.

  1. File Purpose

    • The operators.py file is responsible for the heavy lifting of the "Procedural Terrain Generator" addon. It orchestrates the process of:
      • Retrieving the global Python executable path.
      • Communicating with an external Python script (perlin_height_map.py) to compute the terrain's height map using Perlin noise.
      • Constructing or updating a Blender mesh object based on the generated height map.
      • Defining a Blender operator that users can trigger from the UI to initiate terrain generation.
  2. Class: PTG_Generate_Terrain_Mesh: This class encapsulates the functionality related to generating and manipulating the terrain mesh.

    1. __init__(self, addon_dir): The constructor initializes the PTG_Generate_Terrain_Mesh instance.

      • Parameters:
        • addon_dir (str): The absolute path to the addon's directory.
      • Functionality:
        • Stores the addon_dir.
        • Calls self.get_python_exe() to retrieve the path to the global Python executable, storing it in self.PYTHON_EXE. This path is crucial for running the external Perlin noise script.
        • Constructs the full path to the perlin_height_map.py script, storing it in self.PERLIN_FILE.
    2. get_python_exe(self): This method reads the path to the global Python executable from a text file (python_exe_path.txt) located in the addon's directory. This file is expected to have been created and configured by the util.py module during addon registration.

      • Returns:
        • str: The path to the Python executable.
        • None: If the python_exe_path.txt file cannot be found or read, indicating an error in initialization.
      • Functionality:
        • Constructs the full path to python_exe_path.txt.
        • Attempts to open and read the first line from this file.
        • Strips any newline characters from the read path.
        • Includes basic error handling to catch IOError or other exceptions if the file is missing or unreadable, printing an error message to the console.
    3. terrain_mesh_generator(self, height_map_array, obj_name="PTG_Terrain_object"): This method is responsible for creating or updating a 3D mesh object in Blender based on a 2D NumPy array representing a height map.

      • Parameters:
        • height_map_array (numpy.ndarray): A 2D NumPy array where each element represents the Z-coordinate (height) of a vertex.
        • obj_name (str, optional): The desired name for the Blender mesh object. Defaults to "PTG_Terrain_object".
      • Returns:
        • bpy.types.Object: The generated or updated Blender mesh object.
        • None: If an invalid height_map_array is provided.
      • Functionality:
        • Input Validation: Checks if height_map_array is a valid 2D NumPy array.
        • Determine Dimensions: Extracts the number of vertices along X and Y from the height_map_array's shape.
        • Generate Vertices:
          • Iterates through the dimensions to create a list of (x, y, z) tuples for each vertex. The z coordinate is taken directly from the height_map_array.
        • Generate Faces:
          • Iterates through the grid of vertices to create quadrilateral faces. Each quadrilateral is triangulated into two triangles to form the mesh. The indices of the vertices are calculated based on their position in the grid.
        • Retrieve or Create Mesh Object:
          • Checks if an object with obj_name already exists in the scene and is a mesh.
            • If it exists, it retrieves its mesh data for an update.
            • If it does not exist, it creates a new bpy.data.meshes object and a new bpy.data.objects (mesh object), then links it to the current collection.
        • Switch to Object Mode: Ensures Blender is in 'OBJECT' mode before modifying mesh data, which is a common requirement for mesh operations.
        • Clear and Update Mesh Data:
          • mesh_data.clear_geometry(): Clears any existing vertex, edge, and face data from the mesh.
          • mesh_data.from_pydata(vertices, [], faces): Populates the mesh with the newly generated vertices and faces. Edges are automatically calculated.
          • mesh_data.update(calc_edges=True): Updates the mesh data, recalculating edges.
          • mesh_data.validate(): Validates the mesh data for consistency.
        • Select and Activate Object:
          • Deselects all objects, then selects and makes the newly created/updated terrain object active in the viewport.
        • Logging: Prints status messages to the console about mesh creation/update.
    4. ipc_perin_map_computation(self, params): This method handles the Inter-Process Communication (IPC) to execute the perlin_height_map.py script as a separate process. It passes terrain generation parameters to the script and receives the computed height map.

      • Parameters:
        • params (dict): A dictionary containing all the parameters required for Perlin noise computation (e.g., view_height, view_width, terrain_scale, offsets, seeds, octaves, persistence, lacunarity, min_height, max_height).
      • Returns:
        • numpy.ndarray: A 2D NumPy array representing the computed height map.
        • None: If an error occurs during subprocess execution or JSON parsing.
      • Functionality:
        • Serialize Parameters: Converts the params dictionary into a JSON string using json.dumps(). This string is passed as a command-line argument to the external Python script.
        • Construct Command: Creates a list of command-line arguments: the Python executable path, the path to perlin_height_map.py, and the JSON string of parameters.
        • Execute Subprocess:
          • subprocess.run(commands, capture_output=True, text=True, check=True): Executes the external Python script.
            • capture_output=True: Captures the standard output and standard error.
            • text=True: Decodes stdout/stderr as text.
            • check=True: Raises a CalledProcessError if the subprocess returns a non-zero exit code.
        • Parse Output:
          • json.loads(process.stdout): Parses the JSON string received from the subprocess's standard output, which is expected to be a flat list of height values.
          • np.array(height_list, dtype=np.float64).reshape(...): Converts the list into a 2D NumPy array with the correct dimensions (view_height, view_width).
        • Error Handling: Catches any exceptions during subprocess execution or JSON parsing, prints an error message, and returns None.
  3. Class: PTG_Generate_Operator This class defines a Blender operator, which is an action that can be triggered by the user (e.g., by clicking a button in the UI).

    1. Operator Properties
      • bl_idname: "ptg.generate_terrain"
        • A unique identifier for this operator. This is the string used in ui.py to link the "Generate Terrain" button to this operator.
      • bl_label: "Generate Terrain"
        • The human-readable name displayed on the button in the UI.
      • bl_description: "Generates a new procedural terrain mesh."
        • A tooltip that appears when hovering over the operator's button.
      • bl_options: {'REGISTER', 'UNDO'}
        • 'REGISTER': Ensures the operator is registered with Blender.
        • 'UNDO': Makes the operator's action undoable in Blender's history.
    2. execute(self, context) Method This method contains the main logic that is executed when the PTG_Generate_Operator is invoked.
      • Parameters:
        • self: The instance of the operator.
        • context: A bpy.context object, providing access to Blender's current state.
      • Functionality:
        • Access Scene and Properties:
          • scene = context.scene: Gets the current Blender scene.
          • ptg_props = scene.ptg_props: Accesses the custom property group (PTG_Properties) attached to the scene, which holds all the user-defined terrain parameters.
        • Prepare Parameters for IPC:
          • Creates a params dictionary, mapping the ptg_props values to the keys expected by the perlin_height_map.py script. This ensures all necessary parameters are collected.
        • Initialize Terrain Mesh Generator:
          • addon_dir = os.path.dirname(bpy.path.abspath(__file__)): Gets the current addon directory.
          • mesh_generator = PTG_Generate_Terrain_Mesh(addon_dir=addon_dir): Creates an instance of the PTG_Generate_Terrain_Mesh class, passing the addon directory for initialization.
        • Compute Height Map:
          • height_map = mesh_generator.ipc_perin_map_computation(params=params): Calls the IPC method to execute the external script and retrieve the height map.
        • Generate/Update Terrain Mesh:
          • If height_map is not None:
            • mesh_generator.terrain_mesh_generator(height_map_array=height_map, obj_name="PTG_Terrain_object"): Calls the mesh generation method to create or update the Blender object.
            • self.report({'INFO'}, "Terrain generated successfully!"): Reports a success message to Blender's info area.
            • return {'FINISHED'}: Indicates that the operator completed successfully.
          • If height_map is None:
            • Prints an error log message.
            • self.report({'ERROR'}, "Failed to generate terrain height map."): Reports an error message to Blender's info area.
            • return {'CANCELLED'}: Indicates that the operator was cancelled due to an error.
  4. Conclusion The operators.py file is the operational core of the "Procedural Terrain Generator" addon. It brings together the UI properties, external height map computation, and Blender's mesh creation capabilities to provide a seamless and interactive terrain generation experience for the user. By separating the concerns into PTG_Generate_Terrain_Mesh and PTG_Generate_Operator, the code maintains good organization and reusability.

└── πŸ“ perlin_height_map.py - Documentation


perlin_height_map.py file is a standalone Python script designed to generate 2D Perlin noise height maps. This script is intended for Inter-Process Communication (IPC), meaning it's executed by another process (in this case, the Blender addon's operators.py) to perform its computation and return results via standard output.

  1. File Purpose

    • The primary purpose of perlin_height_map.py is to compute a 2D height map using a composite Perlin noise algorithm. It receives configuration parameters as a JSON string via command-line arguments, performs the noise calculation, and then outputs the resulting height map (as a flattened list) to standard output in JSON format. This design allows the Blender addon to leverage external Python libraries (like noise and numpy) without needing to bundle them directly within Blender's Python environment.
  2. Class: Perlin_Height_Map This class encapsulates the logic for generating a 2D Perlin noise height map based on various parameters.

      1. __init__(self, view_height=100, view_width=100): The constructor initializes the Perlin_Height_Map instance with default values for all terrain and height noise parameters.
      • Parameters:
        • view_height (int, optional): The height (number of rows) of the generated height map. Defaults to 100.
        • view_width (int, optional): The width (number of columns) of the generated height map. Defaults to 100.
      • Functionality:
        • Sets the self.shape tuple to (view_height, view_width).
        • Initializes self.offset to (0, 0).
        • Initializes all Perlin noise parameters (scale, octaves, persistence, lacunarity, seed) for both the base terrain noise and the height modulation noise with default values.
        • Initializes min_height and max_height for the final height scaling.
      • Internal Documentation (within code): The docstring for the __init__ method provides a good summary of what each Perlin noise parameter means: shape, scale, octaves, persistence, lacunarity, and seed.
      1. set_parameters(self, ...): This method allows external callers to update all the Perlin noise and terrain dimension parameters after the object has been initialized.
      • Parameters:
        • view_height (int): Height of the terrain map.
        • view_width (int): Width of the terrain map.
        • terrain_scale (float): Scale for the base terrain noise.
        • terrain_octaves (int): Number of octaves for base terrain noise.
        • terrain_persistence (float): Persistence for base terrain noise.
        • terrain_lacunarity (float): Lacunarity for base terrain noise.
        • terrain_seed (int): Seed for base terrain noise.
        • offset_x (float): X-offset for the noise sampling.
        • offset_y (float): Y-offset for the noise sampling.
        • height_scale (float): Scale for the height modulation noise.
        • height_octaves (int): Number of octaves for height modulation noise.
        • height_persistence (float): Persistence for height modulation noise.
        • height_lacunarity (float): Lacunarity for height modulation noise.
        • height_seed (int): Seed for height modulation noise.
        • min_height (float): Minimum final height of the terrain.
        • max_height (float): Maximum final height of the terrain.
      • Functionality:
        • Updates the instance attributes (self.shape, self.offset, self.terrain_scale, etc.) with the provided parameter values. This method is crucial for configuring the noise generation based on user input from the Blender addon.
      1. generate_terrain_map(self): This method computes the 2D height map using a combination of two Perlin noise layers: a base terrain noise and a height modulation noise.
      • Returns:
        • numpy.ndarray: A 2D NumPy array representing the generated height map, with values scaled between min_height and max_height.
      • Functionality:
        • Initialize Viewport Array: Creates a NumPy array view_port filled with zeros, with dimensions defined by self.shape. This array will store the computed height values.
        • Iterate Through Grid: Uses nested loops to iterate over each (x, y) coordinate in the view_port grid.
        • Calculate Normalized Coordinates:
          • new_x = (x + self.offset[0]) / self.terrain_scale
          • new_y = (y + self.offset[1]) / self.terrain_scale
          • These calculations normalize the (x, y) coordinates by the terrain_scale and apply the offset. This ensures that the noise function samples different parts of the infinite Perlin noise field, allowing for seamless, continuous terrain generation as offsets change.
        • Generate Base Perlin Noise:
          • base_noise = noise.snoise2(...): Calls the noise.snoise2 function (from the noise library) to generate 2D Perlin noise for the base terrain.
          • It uses self.terrain_octaves, self.terrain_persistence, self.terrain_lacunarity, and self.terrain_seed for its parameters.
          • repeatx and repeaty are set to self.shape[0] and self.shape[1] respectively, which can be useful for wrapping noise patterns, though for infinite terrain, the primary control is offset.
        • Generate Height Modulation Perlin Noise:
          • height_noise = noise.snoise2(...): Generates a second layer of 2D Perlin noise, specifically for modulating the height.
          • It uses self.height_octaves, self.height_persistence, self.height_lacunarity, and self.height_seed for its parameters.
        • Normalize Height Noise:
          • normalized_height_noise = (height_noise + 1)/2: Perlin noise typically returns values in the range [-1, 1]. This line normalizes the height_noise to the range [0, 1].
        • Modulate Base Noise:
          • modulated_height = base_noise * normalized_height_noise: The base terrain noise is multiplied by the normalized height modulation noise. This allows the second noise layer to influence the amplitude (height) of the first, creating more varied and complex terrain features (e.g., higher mountains in certain areas, flatter plains in others).
        • Linear Interpolation for Final Height:
          • height = self.min_height + (modulated_height + 1) * ((self.max_height - self.min_height)/2): This is a linear interpolation (lerp) formula. The modulated_height (which is still in [-1, 1] range after modulation, assuming normalized_height_noise is [0,1]) is mapped to the desired [min_height, max_height] range.
        • Store Height: The calculated height is assigned to the corresponding (x, y) position in the view_port array.
        • Return Height Map: Returns the fully populated view_port NumPy array.
  3. Function: perlin_height_map_api(json_param)

    • This function serves as the main entry point for external calls to this script, particularly from the Blender addon. It parses input parameters and orchestrates the height map generation.
    • Parameters:
      • json_param (str or None): A JSON string containing all the parameters for terrain generation. If None, default parameters will be used.
    • Returns:
      • list: A flattened list of the generated height map values. This format is suitable for easy transfer via standard output to the calling process.
    • Functionality:
      • Instantiate Perlin_Height_Map: Creates an instance of the Perlin_Height_Map class.
      • Parse Parameters:
        • If json_param is provided (not None), it parses the JSON string into a Python dictionary.
        • It then extracts each parameter from the dictionary and calls PHM.set_parameters() to configure the Perlin_Height_Map instance with these values.
      • Generate Height Map: Calls PHM.generate_terrain_map() to compute the 2D height map.
      • Flatten and Return: Flattens the resulting 2D NumPy array into a 1D list using .flatten().tolist() and returns it.
  4. Main Execution Block (if __name__ == "__main__":) This block is executed when the perlin_height_map.py script is run directly (e.g., via python perlin_height_map.py). It handles command-line arguments and outputs the result.

    • Functionality:
      • Check Command-Line Arguments:
        • if len(sys.argv) > 1:: Checks if any command-line arguments were provided. The first argument (sys.argv[0]) is always the script name itself.
        • If arguments exist, sys.argv[1] (the first actual argument) is assumed to be the JSON string of parameters.
        • If no arguments are provided, json_param is set to None, causing perlin_height_map_api to use default parameters.
      • Call API Function: Calls perlin_height_map_api() with the determined json_param.
      • Output Result:
        • print(json.dumps(height_list)): Converts the returned flattened height map list back into a JSON string and prints it to standard output. This is how the operators.py script in Blender receives the data.
      • Error Handling: Includes a try-except block to catch any exceptions during the process, print an error message to standard error, and exit with a non-zero status code (indicating failure).
  5. Conclusion The perlin_height_map.py script is a crucial component of the "Procedural Terrain Generator" addon, acting as a dedicated, external service for complex Perlin noise computations. Its design for IPC allows the addon to remain lightweight while leveraging powerful Python libraries for mathematical operations, ensuring efficient and customizable terrain generation.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors