Skip to main content

Modular, extensible terrain generation library

Project description

artificial_terrains

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 building blocks to (more or less) realistic terrains. The module interface is powerful and highly extensible, but requires some familiarity with the available modules and how they interact. For easier use, the library also provides several preconfigured examples that can be parameterized and run directly without needing to understand the full module system.

It is possible to run the script using blender for visualisation and rendering, but there is otherwise no dependence on blender.

Use as libary

The library is available on pypi for installation using python -m pip install artificial-terrains. Alternativly, one can clone this repo, navigate the the main folder, and run pip install .

Use a pre-configured example

# Python
import artificial_terrains as at

config = at.examples.LoadOrGenerateAndSetSlopeCfg(slope_deg=3)
at.run(config)
terrain = at.get_terrain()

Constuct a custom terrain

import artificial_terrains as at

settings = [
    ('Size', 100),
    ('Basic', {}),
    ('WeightedSum', {}),
    ('Print', {}),
    ('Plot', {}),
    ('Save', {}),
]

at.run(settings, verbose=True)
terrain = at.get_terrain()

Use as script

Installation via pip install makes generate_terrain available as a script, to be run as

# terminal
generate_terrain --save-dir terrain_test --modules Octaves WeightedSum Plot Save

Alternativly, one can clone this repo and run the script from there

cd <artificial-terrains folder>
python generate_terrain.py --save-dir terrain_test --modules Octaves WeightedSum Plot Save

For visualizing or rendering terrains there are modules using blender, and to use these the script must be called using blender in the following way

cd <artificial-terrains folder>
blender --python generate_terrain.py -- --save-dir terrain_test --modules Octaves WeightedSum Plot Save Ground

(note the extra -- to distinguish blender (before) and python (after) arguments.

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:min
Combine: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
width
aspect
pitch_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 position
height
yaw_deg
width
aspect
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 position
height
yaw_deg
width
aspect
pitch_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 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
height
yaw_deg
width
aspect
pitch_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

artificial_terrains-0.14.tar.gz (81.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

artificial_terrains-0.14-py3-none-any.whl (87.9 kB view details)

Uploaded Python 3

File details

Details for the file artificial_terrains-0.14.tar.gz.

File metadata

  • Download URL: artificial_terrains-0.14.tar.gz
  • Upload date:
  • Size: 81.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for artificial_terrains-0.14.tar.gz
Algorithm Hash digest
SHA256 26f2bed91440c0908a0de166d3637c870b1f98d7e4c5d55f36314720ddf4f228
MD5 19e755e50f842d24445f0e42bee96f82
BLAKE2b-256 daf34cd4795e278ce791a9bb2bc4f00b95e30b861b79e9601383aaeea19f5e22

See more details on using hashes here.

File details

Details for the file artificial_terrains-0.14-py3-none-any.whl.

File metadata

File hashes

Hashes for artificial_terrains-0.14-py3-none-any.whl
Algorithm Hash digest
SHA256 92e404c34ce0d2ca8d31e9f69e9e33e616c8a620e13187834c3b65a66fd48490
MD5 1f883c921aa0c85dcbbdbb03c7b5e12f
BLAKE2b-256 95aff461b91f37ad5e9c19a5c471914138cc8933bf1d01d0d4b5ba2f32933e2c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page