载入中...
搜索中...
未找到
CaveSediment.cpp
浏览该文件的文档.
2
3#include <algorithm>
4#include <cmath>
5#include <random>
6#include <utility>
7
8namespace eve::procgen {
9namespace {
10
11constexpr float Pi = 3.1415926535f;
12
13float barDistance(float x, float y, float z, const CaveSedimentBar& bar) {
14 const float dx = x - bar.x, dy = y - bar.y, dz = z - bar.z;
15 const float along = dx * bar.flowX + dz * bar.flowZ;
16 const float across = -dx * bar.flowZ + dz * bar.flowX;
17 const float q =
18 std::sqrt((along * along) / (bar.length * bar.length) + (across * across) / (bar.width * bar.width) +
19 (dy * dy) / (bar.thickness * bar.thickness));
20 return (q - 1.f) * std::min({bar.length, bar.width, bar.thickness});
21}
22
23float clastDistance(float x, float y, float z, const CaveSedimentClast& clast) {
24 const float dx = x - clast.x, dy = y - clast.y, dz = z - clast.z;
25 const float across = -dx * clast.flowZ + dz * clast.flowX;
26 const float along = dx * clast.flowX + dz * clast.flowZ;
27 const float c = std::cos(clast.pitch);
28 const float s = std::sin(clast.pitch);
29 const float tiltedAlong = along * c - dy * s;
30 const float tiltedUp = along * s + dy * c;
31 const float q = std::sqrt((across * across) / (clast.longRadius * clast.longRadius) +
32 (tiltedUp * tiltedUp) / (clast.thickRadius * clast.thickRadius) +
33 (tiltedAlong * tiltedAlong) / (clast.shortRadius * clast.shortRadius));
34 return (q - 1.f) * std::min({clast.longRadius, clast.thickRadius, clast.shortRadius});
35}
36
37float parageneticChannelDistance(float x, float y, float z, const CaveSedimentBar& bar, float strength) {
38 const float dx = x - bar.x, dy = y - bar.ceilingY, dz = z - bar.z;
39 const float along = dx * bar.flowX + dz * bar.flowZ;
40 const float clamped = std::clamp(along, -bar.channelHalfLength, bar.channelHalfLength);
41 const float endDistance = along - clamped;
42 const float phase = clamped / std::max(bar.channelHalfLength, 1e-5f);
43 const float meander = std::sin(phase * Pi) * bar.channelMeander * strength;
44 const float across = -dx * bar.flowZ + dz * bar.flowX - meander;
45 const float q =
46 std::sqrt((endDistance * endDistance + across * across) / (bar.channelHalfWidth * bar.channelHalfWidth) +
47 (dy * dy) / (bar.channelLift * bar.channelLift));
48 return (q - 1.f) * std::min(bar.channelHalfWidth, bar.channelLift);
49}
50
51float alluvialNotchDistance(float x, float y, float z, const CaveSedimentBar& bar) {
52 const float dx = x - bar.x, dy = y - bar.palaeofillY, dz = z - bar.z;
53 const float along = dx * bar.flowX + dz * bar.flowZ;
54 const float clamped = std::clamp(along, -bar.notchHalfLength, bar.notchHalfLength);
55 const float endDistance = along - clamped;
56 const float phase = clamped / std::max(bar.notchHalfLength, 1e-5f);
57 const float across = -dx * bar.flowZ + dz * bar.flowX - std::sin(phase * Pi) * bar.channelMeander * 0.45f;
58 const float q = std::sqrt((endDistance * endDistance) / (bar.notchHalfWidth * bar.notchHalfWidth) +
59 (across * across) / (bar.notchHalfWidth * bar.notchHalfWidth) +
60 (dy * dy) / (bar.notchHalfHeight * bar.notchHalfHeight));
61 return (q - 1.f) * std::min(bar.notchHalfWidth, bar.notchHalfHeight);
62}
63
64} // namespace
65
66CaveSedimentSet createCaveSediment(const std::vector<CaveSedimentPathPoint>& path, int barCount, float strength,
67 float paragenesis, uint32_t seed) {
68 CaveSedimentSet result;
69 if (strength <= 0.f || barCount <= 0 || path.size() < 2) return result;
70
71 std::mt19937 rng(seed ^ 0x6c8e9cf5u);
72 std::uniform_real_distribution<float> unit(0.f, 1.f);
73 const float boundedStrength = std::clamp(strength, 0.f, 1.f);
74 result.paragenesisStrength = std::clamp(paragenesis, 0.f, 1.f);
75 float totalPitch = 0.f;
76 float totalChannelWidth = 0.f;
77 float totalPalaeofillRatio = 0.f;
78 float totalNotchThickness = 0.f;
79 result.bars.reserve(size_t(barCount));
80 for (int i = 0; i < barCount; ++i) {
81 const size_t segment = size_t(1 + rng() % uint32_t(path.size() - 1));
82 const auto& start = path[segment - 1];
83 const auto& end = path[segment];
84 float flowX = end.x - start.x;
85 float flowZ = end.z - start.z;
86 const float length = std::sqrt(flowX * flowX + flowZ * flowZ);
87 if (length < 1e-5f) {
88 flowX = 1.f;
89 flowZ = 0.f;
90 } else {
91 flowX /= length;
92 flowZ /= length;
93 }
94 const float t = 0.3f + unit(rng) * 0.4f;
95 const float radius = start.radius + (end.radius - start.radius) * t;
97 bar.x = start.x + (end.x - start.x) * t + (-flowZ) * (unit(rng) * 2.f - 1.f) * radius * 0.22f;
98 bar.z = start.z + (end.z - start.z) * t + flowX * (unit(rng) * 2.f - 1.f) * radius * 0.22f;
99 bar.flowX = flowX;
100 bar.flowZ = flowZ;
101 bar.length = radius * (0.75f + unit(rng) * 0.55f);
102 bar.width = radius * (0.32f + unit(rng) * 0.24f);
103 bar.thickness = radius * (0.08f + boundedStrength * (0.05f + unit(rng) * 0.035f));
104 const float centerY = start.y + (end.y - start.y) * t;
105 const float floorY = centerY - radius * 0.92f;
106 bar.y = floorY + bar.thickness * 0.42f;
107 bar.ceilingY = centerY + radius * 0.84f;
108 bar.passageRadius = radius;
109 if (result.paragenesisStrength > 0.f) {
110 // Cooper & Covington (2020): equilibrium channel width grows with discharge but weakly narrows
111 // with sediment supply. Passage radius is the deterministic discharge proxy used by this recipe.
112 bar.channelHalfLength = std::max(bar.length * 1.8f, length * 0.42f);
113 bar.channelHalfWidth = radius * (0.22f + 0.12f * (1.f - boundedStrength));
114 bar.channelLift = radius * result.paragenesisStrength * (0.07f + 0.11f * boundedStrength);
115 bar.channelMeander = bar.channelHalfWidth * (0.18f + unit(rng) * 0.22f);
116 bar.palaeofillY = centerY + radius * (0.22f + 0.42f * boundedStrength);
117 bar.notchHalfLength = std::max(bar.length * 1.55f, length * 0.36f);
118 bar.notchHalfWidth = radius * (1.02f + 0.1f * result.paragenesisStrength);
119 // Keep the concave notch profile resolvable by the recipe's normal 2x isosurface sampling.
120 bar.notchHalfHeight = radius * result.paragenesisStrength * (0.12f + 0.08f * boundedStrength);
121 ++result.parageneticChannels;
122 result.maximumCeilingLift = std::max(result.maximumCeilingLift, bar.channelLift);
123 result.maximumNotchRetreat = std::max(result.maximumNotchRetreat, bar.notchHalfWidth - bar.passageRadius);
124 totalChannelWidth += bar.channelHalfWidth * 2.f;
125 totalPalaeofillRatio += (bar.palaeofillY - floorY) / (bar.ceilingY - floorY);
126 totalNotchThickness += bar.notchHalfHeight * 2.f;
127 }
128
129 const int clastCount = 3 + int(rng() % 4u);
130 bar.clasts.reserve(size_t(clastCount));
131 for (int clastIndex = 0; clastIndex < clastCount; ++clastIndex) {
132 CaveSedimentClast clast;
133 clast.flowX = flowX;
134 clast.flowZ = flowZ;
135 clast.longRadius = radius * (0.09f + unit(rng) * 0.06f);
136 clast.shortRadius = clast.longRadius * (0.48f + unit(rng) * 0.18f);
137 clast.thickRadius = clast.longRadius * (0.24f + unit(rng) * 0.12f);
138 const float along = (unit(rng) * 2.f - 1.f) * bar.length * 0.72f;
139 const float across = (unit(rng) * 2.f - 1.f) * bar.width * 0.68f;
140 clast.x = bar.x + flowX * along - flowZ * across;
141 clast.z = bar.z + flowZ * along + flowX * across;
142 const float pitchDegrees = 9.f + boundedStrength * (8.f + unit(rng) * 11.f);
143 clast.pitch = -pitchDegrees * Pi / 180.f;
144 clast.y = bar.y + bar.thickness * 0.72f + clast.thickRadius * 0.45f;
145 totalPitch += pitchDegrees;
146 result.depositedVolume += 4.f / 3.f * Pi * clast.longRadius * clast.thickRadius * clast.shortRadius;
147 ++result.clastCount;
148 bar.clasts.push_back(clast);
149 }
150 result.depositedVolume += 4.f / 3.f * Pi * bar.length * bar.width * bar.thickness;
151 result.bars.push_back(std::move(bar));
152 }
153 if (result.clastCount > 0) result.meanImbricationDegrees = totalPitch / float(result.clastCount);
154 if (result.parageneticChannels > 0)
155 result.meanParageneticWidth = totalChannelWidth / float(result.parageneticChannels);
156 if (result.parageneticChannels > 0)
157 result.meanPalaeofillRatio = totalPalaeofillRatio / float(result.parageneticChannels);
158 if (result.parageneticChannels > 0)
159 result.meanNotchThickness = totalNotchThickness / float(result.parageneticChannels);
160 return result;
161}
162
163float carveCaveParagenesis(float x, float y, float z, float current, const CaveSedimentSet& sediment) {
164 if (sediment.paragenesisStrength <= 0.f) return current;
165 for (const CaveSedimentBar& bar : sediment.bars)
166 current = std::min({current, parageneticChannelDistance(x, y, z, bar, sediment.paragenesisStrength),
167 alluvialNotchDistance(x, y, z, bar)});
168 return current;
169}
170
171float addCaveSediment(float x, float y, float z, float current, const CaveSedimentSet& sediment) {
172 for (const CaveSedimentBar& bar : sediment.bars) {
173 current = std::max(current, -barDistance(x, y, z, bar));
174 for (const CaveSedimentClast& clast : bar.clasts) current = std::max(current, -clastDistance(x, y, z, clast));
175 }
176 return current;
177}
178
179bool isCaveSedimentSurface(float x, float y, float z, float tolerance, const CaveSedimentSet& sediment) {
180 for (const CaveSedimentBar& bar : sediment.bars) {
181 if (std::fabs(barDistance(x, y, z, bar)) <= tolerance) return true;
182 for (const CaveSedimentClast& clast : bar.clasts)
183 if (std::fabs(clastDistance(x, y, z, clast)) <= tolerance) return true;
184 }
185 return false;
186}
187
188} // namespace eve::procgen
Duration start
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
float z
Definition AnimClip.cpp:738
const std::string & s
float phase
Definition CaveMesh.cpp:58
float length
Definition CaveMesh.cpp:94
std::array< double, 10 > q
HexVec3 across
std::int32_t c
float radius
std::string path
Definition PlayHost.cpp:110
std::uint32_t seed
Definition PointSet.cpp:807
float t
double current
float dz
float dy
float dx
TacticalUnit * unit
Heightmap sediment
CaveSedimentSet createCaveSediment(const std::vector< CaveSedimentPathPoint > &path, int barCount, float strength, float paragenesis, uint32_t seed)
Create flow-aligned cave sediment bars with upstream-imbricated gravel.
float carveCaveParagenesis(float x, float y, float z, float current, const CaveSedimentSet &sediment)
Carve flow-aligned antigravitative ceiling channels above generated sediment bars.
bool isCaveSedimentSurface(float x, float y, float z, float tolerance, const CaveSedimentSet &sediment)
Test whether a point lies on a generated sediment surface.
float addCaveSediment(float x, float y, float z, float current, const CaveSedimentSet &sediment)
Union sediment bars and imbricated clasts into a cave SDF.
CaveSedimentBar public API.
std::vector< CaveSedimentClast > clasts
CaveSedimentClast public API.
CaveSedimentSet public API.
std::vector< CaveSedimentBar > bars