Terrain
Various tools for generating random terrains using datalackeytools.
All inputs and outputs are JSON objects with indicated keys. Each object must be in a single line, as the programs read input one line at a time and produce output for each line before reading the next line.
YAML inside code blocks is used by specificjson, extracted using edicta, to produce source code that handles I/O. See repositories parallel to this one.
Usage
generatechanges
Program generates and array of coordinates and change radius and offset magnitude pairs. Coordinates are in [0, 1] range.
Radius is in [0, 1] range and represents a radius of a circle in plane. Values can be modified using radius_min, radius_range, and radius_max.
Offset is in range [-1, 1] and represents change in height. Values can be modified using offset_min, offset_range, and offset_max.
Limiting radius allows you to generate rough terrain by using small values for radius. Smooth terrain can be generated using large radiuses.
The last row and column of the 2-dimensional arrays are used for edges. If you plan to render the changes as wrap-around map, the first row should match the last row and the first column should match the last column or you risk having a visible discontinuity. Due to random nature of the process as long as the first and last row/column are close enough the output should be ok.
The array minimum size is 1x1. Row sizes can vary row to row. Each array is treated independently so they can be of different size. Bi-linear interpolation is used to obtain the value.
Output:
- changes: Array of number arrays containing x, y, radius, and offset.
---
generate_io:
namespace: io
types:
GenerateIn:
count:
description: Change count.
format: UInt32
radius_min:
description: |
Map of minimum radius values. Minimum size is 2x2 and inner vectors
are rows, as with other maps. Default is [[0,0],[0,0]]
format: [ ContainerStdVector, StdVector, Float ]
required: false
radius_max:
description: Map of maximum radius values. Default is [[1,1],[1,1]].
format: [ ContainerStdVector, StdVector, Float ]
required: false
radius_range:
description: |
Map of radius value range. Ignored if both radius_min and radius_max
have been given. Default is [[1,1],[1,1]].
format: [ ContainerStdVector, StdVector, Float ]
required: false
radius_histogram:
description: |
Distribution of radius values within the radius range as histogram.
See description of offset_histogram.
format: [ StdVector, Float ]
required: false
offset_min:
description: Map of minimum offset values. Default is [[-1,-1],[-1,-1]].
format: [ ContainerStdVector, StdVector, Float ]
required: false
offset_max:
description: Map of maximum offset values. Default is [[1,1],[1,1]].
format: [ ContainerStdVector, StdVector, Float ]
required: false
offset_range:
description: |
Map of offset value ranges. Ignored if both offset_min and offset_max
have been given. Default is [[2,2],[2,2]].
format: [ ContainerStdVector, StdVector, Float ]
required: false
offset_histogram:
description: |
Distribution of offset values within the offset range as histogram.
Values are divided by the sum to get relative amount of values that
end up in each bin. Defaults to uniform distribution: [1]. To only
get values near offset minimum or maximum, use [1,0,0,...,0,1].
To exclude values near zero, use value like [1,1,1,0,1,1,1]. Using
zero at the end effective shrinks range.
format: [ StdVector, Float ]
required: false
seed:
description: Seed for random number generator.
format: UInt32
required: false
generate:
GenerateIn:
parser: true
...
renderchanges
Outputs height field as array of rows of height values in JSON object under key “heightfield”. Renders the changes to a square height field.
---
render_io:
namespace: io
types:
RenderChangesIn:
size:
description: Side length of the height field.
format: UInt32
changes:
description: Array of arrays of x, y, radius, and offset.
format: [ ContainerStdVector, StdVector, Double ]
left:
description: Crop area low x-index, included. Defaults to 0.
format: UInt32
required: false
right:
description: Crop area high x-index, not included. Defaults to size.
format: UInt32
required: false
low:
description: Crop area low y-index, included. Defaults to 0.
format: UInt32
required: false
high:
description: Crop area high y-index, not included. Defaults to size.
format: UInt32
required: false
generate:
RenderChangesIn:
parser: true
...
examples/simplecolormap
Takes color map name and outputs an array containing arrays of threshold followed by 1 or 3 color component values depending on map name.
Run the script without arguments to display brief help.
heightfield2model
Takes a height field and produces an array of XYZ vertices and triangle strips as indexes to the array.
---
heightfield2model_io:
namespace: io
types:
HeightField2ModelIn:
heightfield:
description: Input height field.
format: [ ContainerStdVectorEqSize, StdVector, Float ]
width:
description: |
Length in units of the StdVector for coordinates, in [0.0, width].
Defaults to width of the heightfield - 1.
format: Float
required: false
range:
description: Height range length. Defaults to same as height field.
format: Float
required: false
colormap:
description: |
Array of arrays of relative value in [0, 1] range and the color-value
to use. If not given, colors are not produced.
format: [ ContainerStdVectorEqSize, StdVector, Float ]
required: false
HeightField2ModelOut:
vertices:
description: Array of vertices.
format: [ ContainerStdVector, StdVector, Float ]
accessor: vertices
colors:
description: Array of RGB colors, present if colormap was given.
format: [ ContainerStdVector, StdVector, Float ]
required: false
accessor: colors
checker: "colors.size() != 0"
tristrips:
description: Array of arrays of triangle strip indexes.
format: [ ContainerStdVector, StdVector, UInt32 ]
accessor: tristrips
generate:
HeightField2ModelIn:
parser: true
HeightField2ModelOut:
writer: true
...
heightfield2color
Takes a height field and produces a matching image with height value mapped to given value vector.
---
heightfield2color_io:
namespace: io
types:
HeightField2ColorIn:
heightfield:
description: Input height field. Any array of arrays of floats will do.
format: [ ContainerStdVector, StdVector, Float ]
colormap:
description: |
Array of arrays of relative value in [0, 1] range and the color-value
to use to replace height values with.
format: [ ContainerStdVectorEqSize, StdVector, Float ]
HeightField2ColorOut:
image:
description: |
Image with inner-most vector having as many components as the
colormap with threshold omitted.
format: [ ContainerStdVector, ContainerStdVector, StdVector, Float ]
accessor: image
generate:
HeightField2ColorIn:
parser: true
HeightField2ColorOut:
writer: true
...
heightfield2texture
Takes a height field and produces matching texture coordinates and a texture given value vector.
---
heightfield2texture_io:
namespace: io
types:
HeightField2TextureIn:
heightfield:
description: Input height field. Any array of arrays of floats will do.
format: [ ContainerStdVector, StdVector, Float ]
colormap:
description: |
Array of arrays of relative value in [0, 1] range and the color-value
to use to replace height values with.
format: [ ContainerStdVectorEqSize, StdVector, Float ]
HeightField2TextureOut:
texture:
description: An image that represents the colormap.
format: [ ContainerStdVector, ContainerStdVector, StdVector, Float ]
accessor: texture
coordinates:
description: Texture coordinates for the height values.
format: [ ContainerStdVector, StdVector, Float ]
accessor: coordinates
generate:
HeightField2TextureIn:
parser: true
HeightField2TextureOut:
writer: true
...
Examples
Under directory examples, there are subdirectories. You need to have installed
https://github.com/ismo-karkkainen/datalackey
https://github.com/ismo-karkkainen/fileio
gem install datalackeytools
In the subdirectories, the example can be run by running the run.sh script.
If you want to see how the execution proceeds, arguments to the script are passed to datalackey-make, so for example “–follow 3” will show you the rule names and commands that are executed.
Building
For unit tests, https://github.com/onqtam/doctest has been included via git subtree.
You need edicta to extract the input and output specifications from this file. You need specificjson to generate source code from the specifications.
gem install edicta
gem install specificjson
You need cmake and a C++ compiler that supports 2017 standard. Assuming a build directory parallel to the terrain directory, you can use:
cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug ../terrain
cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release ../terrain
cmake -G Xcode -DCMAKE_BUILD_TYPE=Release ../terrain
To specify the compiler, set for example:
CXX=clang++
CXX=g++
To build, assuming Unix Makefiles, run:
make
make test
sudo make install
To run unit tests and to see the output you can “make unittest” and then run the resulting executable.
License
Copyright © 2020-2021 Ismo Kärkkäinen
Licensed under Universal Permissive License. See License.txt.
Build Results
Source code repository.
4f4cc0da533af6b8cdba13f1635f261c89095e9a 2021-12-30T22:06:01+02:00 Use convenience scripts added to cloud-sdk image.
Results: