Download the .zip file (Addon file) from here β¬οΈ
- 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
- 3.1 Random Noise vs Perlin Noise
- 4 Perlin Noise Presentation
- 4.1 Colour Schematic 2D representation
- 4.2 Terrain Generation 3D (Matplotlib)
π Note: The "Procedural Terrain Generator" addon uses the
noisePython library for Perlin noise. Sincenoiseis 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)
- 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
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
.exefile 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
cmdin Start Menu).- Type
python --versionand 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 doctorand 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 --versionand press Enter.- You should see the installed Python 3.x version (e.g.,
Python 3.10.10).python --versionmight still point to an older Python 2.x, butpython3will point to the Homebrew installed version. Your addon'sutil.pyis designed to findpythonorpython3.For Linux (Ubuntu/Debian-based):
- Check for Python 3:
- Most modern Linux distributions come with Python 3 pre-installed.
- Open Terminal.
- Type
python3 --versionand press Enter. You'll likely see a version likePython 3.8.10or 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 likepython3-develon Fedora/RHEL) provides the necessary Python development headers.- Verify Installation: - Type
python3 --versionandpip3 --versionto confirm.
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
Downloadbutton next to it.- Run the Installer:
- Once the
vs_buildtools__*.exefile is downloaded, run it.- The Visual Studio Installer will open.
- Select Workloads:
- In the installer, go to the
Workloadstab.- Crucially, select
Desktop development with C++. This workload includes the C++ compilers and libraries that Python needs.- Install:
- Click the
Installbutton. 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.
open your terminal/command prompt and run the following command:
pip install numpy noiseAfter installing the Python, Microsoft Visual C++ and other library dependencies, download the PTG Blender Addon from here
- Open Blender: Launch your Blender application.
- Go to Preferences:
- In Blender, go to
Edit(top menu bar) >Preferences....
- In Blender, go to
- Navigate to Add-ons:
- In the Blender Preferences window, click on the
Add-onstab on the left sidebar.
- In the Blender Preferences window, click on the
- Click "Install...":
- At the top right of the Add-ons tab, you'll see a button labeled
Install.... Click it.
- At the top right of the Add-ons tab, you'll see a button labeled
- Browse to your Addon Folder:
- A file browser window will appear. Navigate to the location where you have downloaded the
Procedural_Terrain_Generator.zipfile. - Important: Do NOT unzip the
Procedural_Terrain_Generator.zipfile - Select the
Procedural_Terrain_Generator.zipfile - Click the Install Add-on button in the file browser.
- A file browser window will appear. Navigate to the location where you have downloaded the
- Search for the Addon:
- After clicking "Install Add-on", you'll be returned to the
Add-onstab in Preferences. - In the search bar (top left of the Add-ons tab), type
Procedural Terrain Generator
- After clicking "Install Add-on", you'll be returned to the
- 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 selectSave Preferences.
- To ensure the addon remains enabled every time you open Blender, click the
- Close Preferences: Close the Blender Preferences window.
- Open the N-Panel: In the 3D Viewport, press the
Nkey 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!
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:
- mathutils.noise module: A Python module that provides various noise Function (Perlin, Simplex, Voronoi, etc) directly accessaible via Python.
- 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.
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
noiselibrary (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-purposemathutils.noise. - This allows to leverage cutting-edge or specialized noise algorithms that might not be exposed or implemented in Blender's core API.
- The
- 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.noisedirectly 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
noiseensures that exact algorithm is used, whereas Blender's internalPERLIN_ORIGINALorPERLIN_NEWmight have subtle differences.
- 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
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:
- 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.
- 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.
- 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.
- 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.
Uniform random noise and Perlin noise are both methods for generating random values, but they differ significantly in their characteristics and applications.
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.
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.
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 |
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.
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.
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.
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.

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
__init__.pyfile serves as the entry point and core configuration file for the "Procedural Terrain Generator" Blender addon
-
File Purpose: The
__init__.pyfile 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. -
Addon Information (
bl_info) Thebl_infodictionary 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.
-
Registered Classes (
classes) Theclasseslist 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.
-
register()Function Theregister()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__.pyfile is located. This path is crucial for locating other addon files, such asutil.py.
- This line determines the absolute path to the directory where the addon's
util.check_and_configure(addon_dir):- This call invokes a function from the
utilmodule. 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.
- This call invokes a function from the
for cls in classes: bpy.utils.register_class(cls):- This loop iterates through the
classeslist 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.
- This loop iterates through the
bpy.types.Scene.ptg_props = bpy.props.PointerProperty(type=ui_properties.PTG_Properties):- This line creates a custom pointer property named
ptg_propson Blender'sScenedata block. This pointer property is of the typeui_properties.PTG_Properties. This allows the addon's custom settings and variables (defined inPTG_Properties) to be stored and accessed globally within the Blender scene, making them persistent and editable through the UI.
- This line creates a custom pointer property named
-
unregister()Function Theunregister()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. Thetry-exceptblock handles cases where the timer might have already been unregistered or is invalid, preventing errors during cleanup.
- This block checks if a timer handle (
-
Property Deletion:
if hasattr(bpy.types.Scene, 'ptg_props'): del bpy.types.Scene.ptg_props- This checks if the custom
ptg_propspointer property was successfully added to theScenedata block. If it exists, it is deleted, removing the addon's custom properties from the scene.
- This checks if the custom
-
Class Unregistration:
for cls in reversed(classes): bpy.utils.unregister_class(cls)- This loop iterates through the
classeslist 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.
- This loop iterates through the
-
-
Conclusion The
__init__.pyfile 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.
The
util.pyfile contains utility functions for the "Procedural Terrain Generator" Blender addon.
- File Purpose
The
util.pyfile 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. - Functions
check_and_configure(addon_dir)-
This function checks for the existence of a file named
python_exe_path.txtwithin the addon's directory. If this file does not exist, it attempts to locate the global Python executable and saves its path into thepython_exe_path.txtfile. -
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 forpython_exe_path.txt.
-
Functionality:
- Construct File Path: It first constructs the full path to
python_exe_path.txtby joiningaddon_dirwith the filename. - Check Existence: It checks if
python_exe_path.txtalready 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 intopython_exe_path.txt. - If
get_python_exe()returnsNone(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.
- Construct File Path: It first constructs the full path to
-
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 (
wherefor Windows,whichfor 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.
- For Windows (
- 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.
- It uses
- 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, orcheck=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.
- This function attempts to locate the path to a global Python executable on the user's system. It uses system-specific commands (
- 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.pyfile defines the user interface (UI) panel for the "Procedural Terrain Generator" Blender addon.
-
File Purpose
- The
ui.pyfile 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.
- The
-
Class:
PTG_UI- The PTG_UI class inherits from bpy.types.Panel, making it a custom UI panel that can be displayed in Blender.
- 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.
- A unique identifier for this panel. Blender uses this ID to reference the panel internally. It typically follows a convention like
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.
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:
-
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.
-
Access Custom Properties:
ptg_props = scene.ptg_props: Accesses the custom property group (PTG_Properties) that was registered in__init__.pyand attached to thebpy.types.Scene. This provides a convenient way to get and set the addon's specific parameters.
-
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. Eachprop()call creates an input field or slider linked to the corresponding property defined inptg_props(which comes fromui_properties.PTG_Properties).
-
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, andterrain_lacunarity.
-
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, andmax_height.
-
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.
-
-
-
Conclusion The
ui.pyfile is crucial for providing an intuitive and organized interface for the "Procedural Terrain Generator" addon. By defining thePTG_UIpanel and itsdrawmethod, 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 file defines the custom properties and the update logic for the "Procedural Terrain Generator" Blender addon.
-
File Purpose
- The
ui_properties.pyfile is central to managing the data and user-driven updates for the terrain generator. It defines aPropertyGroupto 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.
- The
-
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_debouncedis 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 toNoneto indicate no active timer.
- 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
-
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 thePropertyGroup(PTG_Properties) that triggered the update.context: Abpy.contextobject, providing access to Blender's current state.
-
Functionality:
-
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 ValueErroris used to gracefully handle cases where the timer might have already fired or been unregistered, preventing errors.
- This block first accesses the global
-
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.
-
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_meshis 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_handletoNoneafter the update is triggered, indicating that the timer has fired.
- An inner function
-
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 theupdate_terrain_meshfunction 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.
-
-
Class: PTG_Properties
-
The
PTG_Propertiesclass inherits frombpy.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, anupdatecallback. -
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: (ForFloatProperty) The increment/decrement step when dragging the slider or using arrow keys.precision: (ForFloatProperty) 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_debouncedis 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:
2to1000
terrain_width: (bpy.props.IntProperty)- Name: "Terrain Width"
- Description: Number of vertices along the Y-axis.
- Default:
100 - Range:
2to1000
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.0to10000.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.0to10000.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:
-100000to100000 - 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.0to1000.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:
1to10 - 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.0to1.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.0to3.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:
-100000to100000 - 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.0to1000.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:
1to10 - 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.0to1.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.0to3.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.0to1000.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.0to1000.0 - Update Callback:
update_terrain_mesh_debounced
-
-
Conclusion The
ui_properties.pyfile 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 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.
-
File Purpose
- The
operators.pyfile 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.
- The
-
Class:
PTG_Generate_Terrain_Mesh: This class encapsulates the functionality related to generating and manipulating the terrain mesh.-
__init__(self, addon_dir): The constructor initializes thePTG_Generate_Terrain_Meshinstance.- 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.pyscript, storing it inself.PERLIN_FILE.
- Stores the
- Parameters:
-
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 thepython_exe_path.txtfile 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
IOErroror other exceptions if the file is missing or unreadable, printing an error message to the console.
- Constructs the full path to
- Returns:
-
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 invalidheight_map_arrayis provided.
- Functionality:
- Input Validation: Checks if
height_map_arrayis 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. Thezcoordinate is taken directly from theheight_map_array.
- Iterates through the dimensions to create a list of
- 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_namealready 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.meshesobject and a newbpy.data.objects(mesh object), then links it to the current collection.
- Checks if an object with
- 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.
- Input Validation: Checks if
- Parameters:
-
ipc_perin_map_computation(self, params): This method handles the Inter-Process Communication (IPC) to execute theperlin_height_map.pyscript 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
paramsdictionary into a JSON string usingjson.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 aCalledProcessErrorif 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.
- Serialize Parameters: Converts the
- Parameters:
-
-
Class:
PTG_Generate_OperatorThis 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).- Operator Properties
bl_idname:"ptg.generate_terrain"- A unique identifier for this operator. This is the string used in
ui.pyto link the "Generate Terrain" button to this operator.
- A unique identifier for this operator. This is the string used in
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.
execute(self, context)Method This method contains the main logic that is executed when thePTG_Generate_Operatoris invoked.- Parameters:
self: The instance of the operator.context: Abpy.contextobject, 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
paramsdictionary, mapping theptg_propsvalues to the keys expected by theperlin_height_map.pyscript. This ensures all necessary parameters are collected.
- Creates a
- 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 thePTG_Generate_Terrain_Meshclass, 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_mapis notNone: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_mapisNone:- 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.
- If
- Access Scene and Properties:
- Parameters:
- Operator Properties
-
Conclusion The
operators.pyfile 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 intoPTG_Generate_Terrain_MeshandPTG_Generate_Operator, the code maintains good organization and reusability.
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.
-
File Purpose
- The primary purpose of
perlin_height_map.pyis 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 (likenoiseandnumpy) without needing to bundle them directly within Blender's Python environment.
- The primary purpose of
-
Class:
Perlin_Height_MapThis class encapsulates the logic for generating a 2D Perlin noise height map based on various parameters.-
__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.shapetuple to(view_height, view_width). - Initializes
self.offsetto(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_heightandmax_heightfor the final height scaling.
- Sets the
- 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, andseed.
-
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.
- Updates the instance attributes (
-
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 betweenmin_heightandmax_height.
- Functionality:
- Initialize Viewport Array: Creates a NumPy array
view_portfilled with zeros, with dimensions defined byself.shape. This array will store the computed height values. - Iterate Through Grid: Uses nested loops to iterate over each
(x, y)coordinate in theview_portgrid. - Calculate Normalized Coordinates:
new_x = (x + self.offset[0]) / self.terrain_scalenew_y = (y + self.offset[1]) / self.terrain_scale- These calculations normalize the
(x, y)coordinates by theterrain_scaleand apply theoffset. 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 thenoise.snoise2function (from thenoiselibrary) to generate 2D Perlin noise for the base terrain.- It uses
self.terrain_octaves,self.terrain_persistence,self.terrain_lacunarity, andself.terrain_seedfor its parameters. repeatxandrepeatyare set toself.shape[0]andself.shape[1]respectively, which can be useful for wrapping noise patterns, though for infinite terrain, the primary control isoffset.
- 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, andself.height_seedfor 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. Themodulated_height(which is still in[-1, 1]range after modulation, assumingnormalized_height_noiseis[0,1]) is mapped to the desired[min_height, max_height]range.
- Store Height: The calculated
heightis assigned to the corresponding(x, y)position in theview_portarray. - Return Height Map: Returns the fully populated
view_portNumPy array.
- Initialize Viewport Array: Creates a NumPy array
-
-
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(strorNone): A JSON string containing all the parameters for terrain generation. IfNone, 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 thePerlin_Height_Mapclass. - 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 thePerlin_Height_Mapinstance 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.
- Instantiate
-
Main Execution Block (
if __name__ == "__main__":) This block is executed when the perlin_height_map.py script is run directly (e.g., viapython 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_paramis set toNone, causingperlin_height_map_apito use default parameters.
- Call API Function: Calls
perlin_height_map_api()with the determinedjson_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 theoperators.pyscript in Blender receives the data.
- Error Handling: Includes a
try-exceptblock to catch any exceptions during the process, print an error message to standard error, and exit with a non-zero status code (indicating failure).
- Check Command-Line Arguments:
- Functionality:
-
Conclusion The
perlin_height_map.pyscript 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.



