see #412, #414
Goal
Add a generic HighMap feature to procedurally generate a set of meaningful / recognizable points from a heightmap.
The objective is not simply to generate random points, but to identify locations that have a particular terrain characteristic and can therefore be used as anchors for subsequent operations.
Typical use cases include:
- placing objects procedurally (trees, rocks, buildings, landmarks, etc.);
- finding good locations for settlements or structures;
- generating viewpoints / landmarks;
- placing features at characteristic terrain locations;
- using the points as inputs for subsequent transformations;
- generating sparse semantic annotations of a terrain.
Examples of meaningful points
The system should be able to identify different types of terrain features, for example:
- Apexes / peaks — local maxima;
- Sinks / depressions — local minima;
- Ridges — locally high and elongated regions;
- Valleys — locally low and elongated regions;
- Saddles — transition points between neighbouring peaks/valleys;
- Cliffs — locations with high slope;
- Flat areas / plateaus — locations with low slope over a sufficiently large neighbourhood;
- Prominent peaks — peaks with a significant elevation prominence relative to their surroundings;
- Isolated hills / mounds;
- Passes between neighbouring high regions;
- Drainage-related points — e.g. locations close to significant streams or confluences;
- Watershed-related points;
- Curvature extrema — strongly convex or concave locations.
The same mechanism could potentially also support more application-oriented criteria such as:
- good viewpoints: high elevation + low obstruction;
- building locations: low/moderate slope + sufficiently large flat neighbourhood;
- tree/vegetation locations: elevation/slope/water-dependent constraints;
- rock locations: high slope and/or high curvature.
Proposed approach
Rather than implementing one algorithm per point type, expose a generic point-selection framework based on scalar fields derived from the heightmap.
A possible workflow is:
-
Compute one or more terrain descriptors:
- elevation;
- slope;
- curvature;
- flow accumulation;
- distance to drainage;
- local relief;
- etc.
-
Compute a score / suitability field describing how well each location matches the requested criterion.
-
Detect candidate points from this field, e.g.:
- local maxima/minima;
- threshold crossings;
- extrema;
- connected components;
- regional maxima.
-
Apply spatial constraints to obtain a useful sparse point set:
- minimum distance between points;
- maximum number of points;
- minimum feature size;
- optional randomization/jitter;
- optional density control.
This would make the system extensible without requiring a completely different point-generation algorithm for every terrain feature.
Important parameters
Possible generic parameters include:
min_distance — minimum distance between generated points;
max_points — maximum number of points;
scale / radius — neighbourhood scale at which terrain features are evaluated;
threshold — minimum score required for a candidate;
prominence — minimum relative importance of a feature;
randomness — controlled random variation in the result;
seed — deterministic generation;
mask — restrict possible points to a given region;
border — prevent points from being generated too close to the heightmap boundary.
The scale parameter is particularly important: a peak should be considered relative to a neighbourhood, rather than only to its immediate neighbours. This allows the same algorithm to find small hills, large mountains, or major landscape features depending on the requested scale.
Output
The primary output should be a set of 2D points, potentially with associated information describing why each point was selected.
For example:
struct PointOfInterest
{
glm::vec2 position;
float score;
float elevation;
float slope;
float curvature;
// optional classification / type
};
A simpler std::vector<glm::vec2> API could also be provided when only positions are required.
Keeping the descriptors attached to the points would be useful for downstream procedural generation, e.g. using elevation to determine object scale or slope to determine orientation.
Potential API
Something along the lines of:
auto points = generate_points_of_interest(
heightmap,
PointOfInterestType::APEX,
{
.radius = 32,
.min_distance = 64,
.prominence = 0.2f,
.max_points = 100
});
However, the API should ideally remain generic enough to support combinations of criteria.
For example:
elevation > threshold
AND
slope < threshold
AND
curvature ≈ 0
AND
local_relief > threshold
This would allow higher-level applications to express concepts such as "large flat areas on elevated terrain" without requiring a dedicated algorithm.
see #412, #414
Goal
Add a generic HighMap feature to procedurally generate a set of meaningful / recognizable points from a heightmap.
The objective is not simply to generate random points, but to identify locations that have a particular terrain characteristic and can therefore be used as anchors for subsequent operations.
Typical use cases include:
Examples of meaningful points
The system should be able to identify different types of terrain features, for example:
The same mechanism could potentially also support more application-oriented criteria such as:
Proposed approach
Rather than implementing one algorithm per point type, expose a generic point-selection framework based on scalar fields derived from the heightmap.
A possible workflow is:
Compute one or more terrain descriptors:
Compute a score / suitability field describing how well each location matches the requested criterion.
Detect candidate points from this field, e.g.:
Apply spatial constraints to obtain a useful sparse point set:
This would make the system extensible without requiring a completely different point-generation algorithm for every terrain feature.
Important parameters
Possible generic parameters include:
min_distance— minimum distance between generated points;max_points— maximum number of points;scale/radius— neighbourhood scale at which terrain features are evaluated;threshold— minimum score required for a candidate;prominence— minimum relative importance of a feature;randomness— controlled random variation in the result;seed— deterministic generation;mask— restrict possible points to a given region;border— prevent points from being generated too close to the heightmap boundary.The scale parameter is particularly important: a peak should be considered relative to a neighbourhood, rather than only to its immediate neighbours. This allows the same algorithm to find small hills, large mountains, or major landscape features depending on the requested scale.
Output
The primary output should be a set of 2D points, potentially with associated information describing why each point was selected.
For example:
A simpler
std::vector<glm::vec2>API could also be provided when only positions are required.Keeping the descriptors attached to the points would be useful for downstream procedural generation, e.g. using elevation to determine object scale or slope to determine orientation.
Potential API
Something along the lines of:
However, the API should ideally remain generic enough to support combinations of criteria.
For example:
This would allow higher-level applications to express concepts such as "large flat areas on elevated terrain" without requiring a dedicated algorithm.