Modular, extensible terrain generation library
Project description
artificial_terrain
A library and script for creating artificial terrains. The library is described in more detail in the following arXiv preprint: arXiv abstract, PDF download. The paper also includes more up-to-date and relevant examples. For now, the README has only been cleaned to remove outdated or incorrect information; further updates are planned.
The script executes an ordered list of specified 'modules', to create and combine terrain buidling blocks to (more or less) realistic terrains.
Use as libary
To use as library (temporary solution until properly published/released on pypi) (only tested in linux)
- Clone this repo
- Navigate the the main folder, and run
pip install .Example of how to construct a simple terrain:
import artificial_terrains as at
settings = [
('Size', 100),
('Basic', {}),
('WeightedSum', {}),
('Print', {}),
('Plot', {}),
('Save', {}),
]
at.run(settings, verbose=True)
terrain = at.get_terrain()
print(f"terrain:{terrain}")
Getting started
The following command creates a terrain with an overall ground-shape generated from a WeightedSum of different simplex noise Octaves. Holes and Rocks of different scale are generated and combined with a Min and Max operation respectivly. The resultant ground, holes, and rocks are Combined with a default Add operation, and the result is Saved and Plotted in the folder Result.
python generate_terrain.py --modules Holes Combine:Min Octaves WeightedSum Rocks Combine:Max Combine Save:Result Plot:Result --save-dir Terrains/test_001a/
Alternativly, the same command can be run by
python generate_terrain.py --settings-file settings.yml
with settings specified in a yaml file,
save-dir: runs/data_001a
modules:
- Holes
- [Combine, Min]
- Octaves
- WeightedSum
- Rocks
- [Combine, Max]
- Combine
- [Save, Result]
- [Plot, Result]
In all runs, a copy of the used settings is saved in settings.yml, and commands and prints are appended to logger.txt.
Modules
The overall setup for creating a terrain is to create 'terrain elements', and combine them in different ways.
We can split the modules in some main categories. Two fundamental such is 'generating' and 'combining'. The 'generating' generate 'terrain elements', and the 'combining' combine these elements into more complex terrains. Some modules alter the general 'settings' (e.g. extent and resolution), and some do 'input/output' (e.g. save terrains and plot).
Pipes
Modules are called in order, and the output of one module is passed as input to the next, as if connected along a 'pipe'. This makes it possible to generate a multitude of terrain of different types and complexities using basic building blocks.
It is also possible to run multiple pipes to generate a number of terrains.
'Primary' and 'temporary' terrain lists
In order to combine basic building blocks to more complex results, and in turn combine these and so on, we utilize two lists for storing sub-results, 'primary' and 'temporary'.
Generated terrain elements are placed in the temporary list.
If a 'combining' module is run, it primarily operates on the content of the 'temporary' list, with the result appended to the 'primary' list.
If the 'temporary' list is empty, the 'combining' module operates on the 'primary' list instead.
Generating from noise
| Technique | Description | Input arguments | Output |
|---|---|---|---|
| Octaves | Generate a list of 'terrain elements' (default=10) from random noise with increasing scale factor. Additionally passes a weights list which can be used by WeightedSum to combine the 'terrain elements' to a more complex terrain. |
num_octaves=10 start=128 persistance=0.6 amplitude_start=10 random_amp=0.5 |
weights=amplitude_list |
| Basic | Generate a list of 3 'terrain elements' with a large, medium, small scale factor from random noise. | ||
| Rocks | Generate a list of 'terrain elements' (default=4) representing rocks from random noise. | rock_size=[0.5,1,2,4] rock_heights=None fraction=0.8 |
|
| Holes | Generate a list of 'terrain elements' (default=4) representing holes from random noise. | size_list=[0.5,1,2,4] fraction=0.8 |
Combining
| Technique | Description | Input arguments | Example input | Output |
|---|---|---|---|---|
| Combine | Combines the (entire by default) content of the 'temporary' list (primarily) or the 'primary' list (secondarily) using a mathematical operation e.g. (add, min, max, prod). | operation='add' last=None |
Combine:add Combine:max Combine:minCombine:prod |
|
| CombineLast | As Combine, but only work on the last 2 terrains in the 'temporary' or primary lists. (note that this is a shortcut, and the option last=X can be passed to Combine for the more general case of combining the last X terrains) |
operation='add' |
||
| WeightedSum | Add the content of the 'temporary' list as a weighted sum. The input weights must match the length of the 'temporary' list. |
weights=[5,8,0.1] |
Other?
| Technique | Description | Image |
|---|---|---|
| Extent | Set the coordinate bounds of the terrain as [x_min, x_max, y_min, y_max]. Determines the physical area covered. | |
| Location | Shifts the terrain’s position in space. Applied as an offset to the Extent. | |
| Size | Set the physical size of the terrain | |
| Resolution | 'resolution', in points per meter. Used to infer the grid-size, if that is not explicitly given | |
| GridSize | Set the 'grid_size', the number of values in each dimension. Overrides the resolution if given. |
|
| Seed | Set random seed | |
| Folder | Set folder, affects eg. 'Save' and 'Plot' and other modules where a 'folder' is given as input | |
| Set | Set parameter value as Set:parameter=value |
|
| SetDistribution | Set distribution as SetDistribution:parameter=distribution[*args]. Both square and rounded parenthesis can be used. In bash, rounded parameter must either be 'escaped' (as SetDistribution:parameter=distribution\(*args\)), or placed within quotation marks (as SetDistribution:'parameter=distribution(*args)' |
Obstacles?
| Technique | Description | Input | Example 1 | Example 2 | Example 3 | Example 4 |
|---|---|---|---|---|---|---|
| LoadObstacles | LoadObstacles | |||||
| SaveObstacles | SaveObstacles | |||||
| Random | Random | number_of_values position_distribution height_distribution yaw_deg_distribution width_distribution aspect_distribution pitch_deg_distribution position_distribution_2d |
Random:10 |
Random:position |
Random:[position,yaw_deg] |
Set:number_of_values=10 Random:[position,yaw_deg] |
Generating from functions
| Technique | Description | Input | Basic output | Combined output |
|---|---|---|---|---|
| Gaussian | Gaussian | position height yaw_deg width aspect pitch_deg |
Gaussian |
Random:10 Gaussian Combine:Max |
| Step | Step | position height yaw_deg widthaspectpitch_deg |
Step |
Random:10 Step Combine:Max |
| Donut | Donut | position height yaw_deg width aspect pitch_deg |
Donut |
Random:10 Donut Combine:Max |
| Plane | Plane | positionheightyaw_deg widthaspect pitch_deg |
Plane |
Random:10 Plane Combine:Max |
| Sphere | Sphere | position height yaw_deg width aspect pitch_deg |
Sphere |
Random:10 Sphere Combine:Max |
| Cube | Cube | position height yaw_deg width aspect pitch_deg |
Cube |
Random:10 Cube Combine:Max |
| SmoothStep | SmoothStep | SmoothStep |
Random:10 SmoothStep Combine:Max |
|
| Sine | Sine | positionheight yaw_deg width aspectpitch_deg |
Sine |
Random:10 Sine Combine:Max |
Modifiers
| Technique | Description | Image |
|---|---|---|
| Negate | Negate | |
| Scale | Scale | |
| Add | Add | |
| Absolute | Absolute | |
| Clip | Clip | |
| Around | Around | |
| Smooth | Smooth | |
| AsProbability | AsProbability | |
| AsLookupFor | AsLookupFor | |
| AsFactor | AsFactor |
Settings
Input/output
| Technique | Description | Input |
|---|---|---|
| Save | Save terrains | folder='Save' (default) filename='terrain.npz' |
| Plot | Plot terrains |
Other
| Technique | Description | Input |
|---|---|---|
| Exit | Exit early | |
| Print information of pipe |
Examples
Examples of different combinations of modules and the resultant terrains. Only the relevant modules are listed in the table, and not the full command to generate the terrain/rendered images. However, these commands can be found below the table. In some cases, alternative (equivalent or almost equivalent) formatting are shown. Most of the terrains/images are generated by a single command, but some might require two or more.
| # | Description | Modules | Output |
|---|---|---|---|
| 1 | Sloped plane with grooves. Adding an angled plane to a sine plane | Set:width=10 Sine Random:1 Plane Combine or Sine:"dict(width=10)" Plane:"dict(pitch_deg=10)" Combine:Add |
|
| 2 | Walls along the perimiter. Negating a large cube. | Set:width=45 Cube Negate or Cube:"dict(width=45)" Negate |
|
| 3 | Moon landscape. Combine multiple 'donuts' using a pointwise max, and adding to a large sphere | Random:20 Donut Combine:Max Set:width=500 Sphere ToPrimary Combine:Add |
|
| 4 | Stone circle. Interpret a large donut as a positional probability, and setup a constant width-distribution. Draw 30 random samples to generate cube-terrains in the temporary list, and combine using pointwise max. | Donut:"dict(width=35)" AsProbability SetDistribution:width=uniform[2,2] Random:30 Cube Combine:Max |
|
| 5 | Stone circle with obj-file stones. Increase resolution to 10 points-per-meter. Make a flat terrain, and use to make a blender-ground. Sample points along a circle as above, and use to add rocks in blender. Generate Depth image and save. | Resolution:10 Plane Ground Donut:"dict(width=35)" AsProbability SetDistribution:width=uniform[2,2] Random:30 AddRocks Depth Save |
|
| 6 | Terrain from noise, combined with step function | Octaves WeightedSum Random:2 Step Combine:Max Combine:Add |
|
| 7 | Load from saved 'octaves' and combine using random weights | Resolution:10 Octaves Save:Octaves then Load:runs/data_030/Octaves Random:weights WeightedSum |
|
| 8 | Load from saved octaves, and add unevenly spaced rocks. We use the combination of some 'Basic' terrains to get a 2d position probability, and add 10 obj-file rocks in blender. | (Assumes first step from 7) Load:runs/data_030/Octaves Random:weights WeightedSum Ground Basic Combine:Add AsProbability Random:10 AddRocks Depth Save |
Full commands to make terrains, plot, and save as numpy npz files
# 1
python generate_terrain.py --save-dir runs/data_030 --settings overwrite:True --modules Sine:"dict(width=10)" Plane:"dict(pitch_deg=10)" Combine:Add Folder:02_angled_sine_plane Plot Save
# 2
python generate_terrain.py --save-dir runs/data_030 --settings overwrite:True --modules Set:width=45 Cube Negate Folder:01_wall Plot Save
# 6
python generate_terrain.py --save-dir runs/data_030 --settings overwrite:True --modules Octaves WeightedSum Random:2 Step Combine:Max Combine:Add Folder:06_terrain_with_step Plot Save
# 7
python generate_terrain.py --save-dir runs/data_030 --settings overwrite:True --modules Resolution:10 Octaves Save:Octaves
python generate_terrain.py --save-dir runs/data_030 --settings overwrite:True --modules Load:runs/data_030/Octaves Random:weights WeightedSum Folder:07_generate_and_load Plot Save
# 8
blender --python generate_terrain.py -- --save-dir runs/data_030 --settings overwrite:True --modules Load:runs/data_030/Octaves Random:weights WeightedSum Ground Basic Combine:Add AsProbability Random:10 AddRocks Folder:08_unevenly_spaced_rocks Resolution:10 Camera:top Depth Save
Full commands to make the above rendered images
# 1
blender --python generate_terrain.py -- --save-dir runs/data_030 --settings overwrite:True --modules Sine:"dict(width=10)" Plane:"dict(pitch_deg=10)" Combine:Add Folder:02_angled_sine_plane Plot Save Ground ColorMap:dimgray Camera:angled Holdout Render Exit
# 2
blender --python generate_terrain.py -- --save-dir runs/data_030 --settings overwrite:True --modules Set:width=45 Cube Negate Folder:01_wall Plot Save Ground ColorMap:dimgray Camera:angled Holdout Render Exit
# 6
blender --python generate_terrain.py -- --save-dir runs/data_030 --settings overwrite:True --modules Octaves WeightedSum Random:2 Step Combine:Max Combine:Add Folder:06_terrain_with_step Plot Save Ground ColorMap:dimgray Camera:angled Holdout Render
# 7
python generate_terrain.py --save-dir runs/data_030 --settings overwrite:True --modules Resolution:10 Octaves Save:Octaves
blender --python generate_terrain.py -- --save-dir runs/data_030 --settings overwrite:True --modules Load:runs/data_030/Octaves Random:weights WeightedSum Folder:07_generate_and_load Plot Save Ground ColorMap:dimgray Camera:angled Holdout Render
# 8
blender --python generate_terrain.py -- --save-dir runs/data_030 --settings overwrite:True --modules Load:runs/data_030/Octaves Random:weights WeightedSum Ground Basic Combine:Add AsProbability Random:10 AddRocks Folder:08_unevenly_spaced_rocks Resolution:10 Camera:top Depth Save
blender --python generate_terrain.py -- --save-dir runs/data_030 --settings overwrite:True --modules Load:runs/data_030/08_unevenly_spaced_rocks/terrain_00000.npz Ground Folder:08_unevenly_spaced_rocksb Plot Save Ground ColorMap:dimgray Camera:angled Holdout Render
Blender
The script generate_terrain.py enables using blender via its python interface. All the above modules work, in additionally a number of specific modules, listed below.
To run the blender script, the following command is used in place of python generate_terrain.py: blender --python generate_terrain.py --. Note the final --, which states that any following arguments are passed to the script generate_terrain.py (and not the actual blender software). An example run, producing an angled plane with sine grooves:
blender --python generate_terrain.py -- --save-dir runs/data_001/ --modules Sine Random Plane Combine Ground
| Technique | Description | Input | Output |
|---|---|---|---|
| Ground | Create grid, using either a terrain from a specified file, or the latest terrain in the primary or temporary heaps | filename=None |
Ground |
| ColorMap | Color heightfield using colormap | cmap='viridis' |
Ground ColorMap |
| AddRocks | Add rocks to scene. | position heightyaw_deg width aspectpitch_deg |
Ground Random:10 AddRocks |
| ImageTexture | Color heightfield using image texture file | filename=None |
Ground ImageTexture:image_texture.png |
| Render | Ground Random:10 AddRocks Render |
||
| RenderSegmentation | Ground Random:10 AddRocks RenderSegmentation |
||
| Depth | Generate depth image. This also returns a 'terrain', but this will only be resonable together with the Camera:top command, see below. |
Ground Random:10 AddRocks Depth |
|
| Camera | Setup camera. Takes either 'angled' or 'top' as input | ... Depth:top |
|
| GenericCamera | |||
| Holdout | Add a large 'holdout plane' at height -100 m, which gives a transparent background in generated images. | ||
| BasicSetup | Clean and setup basic blender scene. NOTE: Runs by default as the first module. |
Dependencies
In order to be able to run, the following python packages should be installed.
python -m pip install numpy
python -m pip install matplotlib
python -m pip install opensimplex
python -m pip install colorcet
python -m pip install PyYaml
python -m pip install scipy
Settings file
The options in the settings can be specified with different formatting. The modules is a list of 2-tuples/lists (module-name, options). The following contains 4 examples of equivalent formatting.
modules
# Version 1, default formatting
- - Donut
- position:
- 10
- 10
height: 5
# Version 2, position list on one line
- - Donut
- position: [10, 10]
height: 5
# Version 3, options as a one line dict
- - Donut
- {position: [10, 10], height: 5}
# Version 4, [name, options] on one line
- [Donut, {position: [10, 10], height: 5}]
In each run, the used settings are saved to <save_dir>/settings.yml.
Extending
The setup is modular and new 'modules' can easiliy be added, as e.g.
class NewModule(Module):
''' A new module '''
@debug_decorator
def __call__(self, terrain=None,
default=None,
overwrite=False,
**_):
This inherits from the Module base class, which sets up e.g. logging and self.save_dir. The new module is setup by defining the __call__ method. As a module is run, this method is executed, with the pipe given as keyword arguments. The default argument is special. If a single value/string is passed as options for the module, e.g. Random:10 or Load:folder/terrain.npz, then this is passed as the 'default' value.
Otherwise the keyword arguments are given py the pipe, or by specifying a dict input to the module, as e.g. Gaussian:"dict(position=[10,10],height=3,width=10)"
The above example takes a terrain keyword as input, with the idea of this being passed in the 'pipe' from a previous module, e.g. Load or some 'generating' module. Anything can be passed between modules in this way, and the names are arbitrary. Some special are the following,
[Note that these are the current names and this might/will change after some clean up]
| Name | Description |
|---|---|
terrain_prim |
The primary list |
terrain_temp |
The temporary list |
position, height, yaw_deg, width, aspect, pitch_deg |
Parameterisation of generation functions, obstacles etc. in a common interface |
extent, resolution |
Parameterisation of the terrain extent and resolution. |
weights |
A list of weights, which is currently used by WeightedSum to combine different basics to a terrain |
The return from a module is collected, in order to allow passing information between modules. The typical return type is a dict. It is used to update the pipe, after which any None type values are removed from the pipe.
Ubuntu
Install blender, and clone the repo. Use a virtual environment for python. If the virtual environment uses the same version of python as blender does, life will be easier. (otherwise the blender script will give some ModuleNotFoundError) Install the following python packages
python -m pip install numpy
python -m pip install matplotlib
python -m pip install opensimplex
python -m pip install colorcet
python -m pip install PyYaml
python -m pip install scipy
Windows
Install git for Windows, install python, and install blender. Clone the repo.
When running blender scripts, this uses a separate python, and the dependencies must be installed there as well. This worked by running the following in git-bash in Windows:
C:\\Program\ Files\\Blender\ Foundation\\Blender\ 4.1\\4.1\\python\\bin\\python.exe -m pip install matplotlib
C:\\Program\ Files\\Blender\ Foundation\\Blender\ 4.1\\4.1\\python\\bin\\python.exe -m pip install opensimplex
C:\\Program\ Files\\Blender\ Foundation\\Blender\ 4.1\\4.1\\python\\bin\\python.exe -m pip install colorcet
C:\\Program\ Files\\Blender\ Foundation\\Blender\ 4.1\\4.1\\python\\bin\\python.exe -m pip install PyYaml
C:\\Program\ Files\\Blender\ Foundation\\Blender\ 4.1\\4.1\\python\\bin\\python.exe -m pip install scipy
(There where some problems with scipy though, for unknown reasons)
If things don't work
There is a script, print_installed_packages.py, which can be used to debug the python environment.
Running it with blender can show the installed packages, and help to understand which python is run (e.g. blender python, system python, or some python environment?).
blender --python print_installed_packages.py --background
This can be compared to running python
python print_installed_packages.py
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file artificial_terrains-0.1.2.tar.gz.
File metadata
- Download URL: artificial_terrains-0.1.2.tar.gz
- Upload date:
- Size: 79.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cedfbe2202ccae1bf6af86c471e804c3b98b91879e07e268361eb9e207f8ef62
|
|
| MD5 |
ce7b62ad32240f022271c97093e7711d
|
|
| BLAKE2b-256 |
800dde85f45495684823d0ca8f3426a1edc1942d227a5a1c3f8c52523d0df36a
|
File details
Details for the file artificial_terrains-0.1.2-py3-none-any.whl.
File metadata
- Download URL: artificial_terrains-0.1.2-py3-none-any.whl
- Upload date:
- Size: 85.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
167ceb1e37759c6107275f4d9ae4649f9fe3c13487badd22812b1df871b8774e
|
|
| MD5 |
e7163c59617bf27d7d67c6253773a569
|
|
| BLAKE2b-256 |
8f5e08127bf366c47c590b4738d9e6ed2932b405dc87cd8f888d08df49aebbd6
|