载入中...
搜索中...
未找到
TerrainLegacyThermal.cpp
浏览该文件的文档.
3
4#include <array>
5
6namespace eve::procgen {
9 using namespace raster_detail;
10 if (!validRaster(heights) || !std::isfinite(settings.minimumThreshold) ||
11 !std::isfinite(settings.maximumThreshold) || settings.minimumThreshold < 0 ||
12 settings.maximumThreshold > 1 || settings.minimumThreshold >= settings.maximumThreshold ||
14 return invalid("terrain.legacyDistributedErosion: finite thresholds in [0,1], minimum below maximum, "
15 "nonnegative iterations and finite terrain required");
16 if (settings.iterations == 0 || heights.getWidth() < 3 || heights.getHeight() < 3)
17 return Result<int>::success(0);
18 const int width = heights.getWidth(), depth = heights.getHeight();
19 auto current = heights.data();
20 std::vector<double> diff(current.size(), 0);
21 const auto at = [width](int x, int z) { return size_t(z) * size_t(width) + size_t(x); };
22 for (int iteration = 0; iteration < settings.iterations; ++iteration) {
23 for (int x = 1; x < width - 1; ++x)
24 for (int z = 1; z < depth - 1; ++z) {
25 const size_t source = at(x, z);
26 const std::array<size_t, 4> neighbor = {at(x, z + 1), at(x - 1, z), at(x + 1, z), at(x, z - 1)};
27 std::array<double, 4> drop{};
28 double maximum = -std::numeric_limits<float>::max(), total = 0;
29 for (int i = 0; i < 4; ++i) {
30 drop[i] = double(current[source]) - current[neighbor[i]];
31 if (drop[i] > 0) {
32 total += drop[i];
33 maximum = std::max(maximum, drop[i]);
34 }
35 }
36 if (maximum < settings.minimumThreshold || maximum > settings.maximumThreshold) continue;
37 const double movement = maximum * 0.5, factor = movement / total;
38 diff[source] -= movement;
39 for (int i = 0; i < 4; ++i)
40 if (drop[i] > 0) diff[neighbor[i]] += factor * drop[i];
41 }
42 for (size_t i = 0; i < current.size(); ++i) {
43 const double value = double(current[i]) + diff[i];
45 return invalid("terrain.legacyDistributedErosion: output exceeds finite float range");
46 current[i] = float(value);
47 diff[i] = 0;
48 }
49 }
50 return publish(heights, std::move(current));
51}
52
53namespace {
54double pcgNormalizedSample(const Heightmap& map, double u, double v) {
55 const double x = u * map.getWidth(), z = v * map.getHeight();
56 const int x0 = std::min(int(x), map.getWidth() - 1), z0 = std::min(int(z), map.getHeight() - 1);
57 const int x1 = std::min(x0 + 1, map.getWidth() - 1), z1 = std::min(z0 + 1, map.getHeight() - 1);
58 const double tx = x - x0, tz = z - z0;
59 return (1 - tx) * (1 - tz) * map.height(x0, z0) + (1 - tx) * tz * map.height(x0, z1) +
60 tx * (1 - tz) * map.height(x1, z0) + tx * tz * map.height(x1, z1);
61}
62} // namespace
63
66 using namespace raster_detail;
67 const auto unit = [](float value) { return value >= 0 && value <= 1; };
68 if (!validRaster(heights) || !validRaster(hardness) ||
69 !std::all_of(hardness.data().begin(), hardness.data().end(), unit) ||
70 !std::isfinite(settings.talusMinimum) || !std::isfinite(settings.talusMaximum) ||
71 settings.talusMinimum < 0 || settings.talusMaximum > 1 ||
72 settings.talusMinimum > settings.talusMaximum || settings.iterations < 0)
73 return invalid("terrain.legacySteepestErosion: finite terrain, normalized hardness/talus bounds and "
74 "nonnegative iterations required");
75 if (settings.iterations == 0 || heights.getWidth() < 3 || heights.getHeight() < 3)
76 return Result<int>::success(0);
77 const int width = heights.getWidth(), depth = heights.getHeight();
78 auto result = heights.data();
79 const Heightmap hardnessInput = hardness;
80 const auto at = [width](int x, int z) { return size_t(z) * size_t(width) + size_t(x); };
81 for (int iteration = 0; iteration < settings.iterations; ++iteration)
82 for (int x = 1; x < width - 1; ++x)
83 for (int z = 1; z < depth - 1; ++z) {
84 const size_t source = at(x, z);
85 const std::array<size_t, 4> neighbor = {at(x, z + 1), at(x - 1, z), at(x + 1, z), at(x, z - 1)};
86 double maximum = 0;
87 int selected = -1;
88 for (int i = 0; i < 4; ++i) {
89 const double drop = double(result[source]) - result[neighbor[i]];
90 if (drop > maximum) maximum = drop, selected = i;
91 }
92 if (maximum < settings.talusMinimum || maximum > settings.talusMaximum || selected < 0) continue;
93 const double resistance = pcgNormalizedSample(hardnessInput, double(x) / width, double(z) / depth);
94 const double movement = maximum * (1 - resistance) * 0.5;
95 const double sourceValue = double(result[source]) - movement;
96 const double targetValue = double(result[neighbor[selected]]) + movement;
97 if (!isRepresentable(sourceValue) || !isRepresentable(targetValue))
98 return invalid("terrain.legacySteepestErosion: output exceeds finite float range");
99 result[source] = float(sourceValue);
100 result[neighbor[selected]] = float(targetValue);
101 }
102 return publish(heights, std::move(result));
103}
104} // namespace eve::procgen
double value
float x
Definition AnimClip.cpp:738
float z
Definition AnimClip.cpp:738
float maximum[3]
float u
Definition Grass.cpp:233
float v
std::uint32_t width
double current
TacticalUnit * unit
TerrainThermalSettings settings
const UnitySourceAsset & source
std::uint32_t depth
std::size_t at
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
In-memory terrain heightmap: a dense float grid (row-major, index = y * width + x) materialized from ...
Definition Heightmap.h:21
int getHeight() const
Returns the height.
Definition Heightmap.cpp:17
const std::vector< float > & data() const
Data.
Definition Heightmap.h:48
int getWidth() const
Returns the width.
Definition Heightmap.cpp:16
Result< int > publish(Heightmap &target, std::vector< float > candidate)
Publish.
bool validRaster(const Heightmap &map)
Valid raster.
Result< int > invalid(std::string message)
Invalid.
bool isRepresentable(double value)
True when representable.
EVENGINE_API_DOMAINS Result< int > applyTerrainLegacyDistributedErosion(Heightmap &heights, const TerrainLegacyDistributedErosionSettings &settings)
Apply Pcg HeightMap.Erode's synchronous four-neighbor material redistribution.
EVENGINE_API_DOMAINS Result< int > applyTerrainLegacySteepestErosion(Heightmap &heights, const Heightmap &hardness, const TerrainLegacySteepestErosionSettings &settings)
Apply Pcg HeightMap.ErodeThermal's ordered steepest-cardinal transport with hardness.
Thresholds and iteration count for Pcg HeightMap.Erode's synchronous cardinal transport.
Thresholds and iteration count for Pcg HeightMap.ErodeThermal's in-place steepest transport.