载入中...
搜索中...
未找到
CaveHydrology.cpp
浏览该文件的文档.
2
3#include <algorithm>
4#include <cmath>
5
6namespace eve::procgen {
7namespace {
8
9float segmentCapacity(const CaveHydrologyPoint& a, const CaveHydrologyPoint& b, float gradient) {
10 const float dx = b.position.x - a.position.x;
11 const float dy = b.position.y - a.position.y;
12 const float dz = b.position.z - a.position.z;
13 const float length = std::max(1e-5f, std::sqrt(dx * dx + dy * dy + dz * dz));
14 const float gravitySlope = std::max(0.f, -dy / length);
15 const float localGradient = gradient * (0.72f + 0.28f * gravitySlope);
16 const float radius = 0.5f * (a.radius + b.radius);
17 const float velocity = std::pow(radius, 2.f / 3.f) * std::sqrt(localGradient);
18 return velocity * radius * radius;
19}
20
21} // namespace
22
23CaveHydrologyWeights buildCaveHydrology(const std::vector<CaveHydrologyPoint>& trunk,
24 const std::vector<CaveHydrologyBranch>& branches, float erosion, float gradient,
25 float recharge, float focusing, float damkohler, float transportG) {
27 result.trunk.assign(trunk.size() > 1 ? trunk.size() - 1 : 0, 1.f);
28 result.branches.resize(branches.size());
29 for (size_t branch = 0; branch < branches.size(); ++branch)
30 result.branches[branch].assign(branches[branch].points.size() > 1 ? branches[branch].points.size() - 1 : 0,
31 1.f);
32 if (erosion <= 0.f || trunk.size() < 2) return result;
33
34 if (damkohler < 0.0008f)
35 result.dissolutionRegime = "uniform";
36 else if (damkohler < 0.008f)
37 result.dissolutionRegime = "channeling";
38 else
39 result.dissolutionRegime = "wormholing";
40 // Da^-1 is the reactant penetration length relative to the network length.
41 // G raises it when transverse diffusion is too slow to consume reactant near the inlet.
42 result.reactantPenetration = std::clamp((0.002f / damkohler) * std::sqrt(transportG), 0.08f, 8.f);
43
44 std::vector<float> branchInflows(trunk.size(), 0.f);
45 std::vector<std::vector<float>> rawBranches(branches.size());
46 float maximumRaw = 1e-6f;
47 for (size_t branch = 0; branch < branches.size(); ++branch) {
48 const auto& path = branches[branch].points;
49 rawBranches[branch].resize(path.size() > 1 ? path.size() - 1 : 0);
50 float inletFlow = 0.f;
51 for (size_t segment = 0; segment + 1 < path.size(); ++segment) {
52 // Distributed recharge enters the remote branch and accumulates toward its
53 // junction at segment zero. This preserves small abandoned distal passages.
54 const float towardJunction = float(path.size() - 1 - segment) / float(path.size() - 1);
55 const float flow = segmentCapacity(path[segment], path[segment + 1], gradient) * recharge *
56 (0.25f + 0.75f * towardJunction);
57 rawBranches[branch][segment] = flow;
58 inletFlow = std::max(inletFlow, flow);
59 maximumRaw = std::max(maximumRaw, flow);
60 }
61 const size_t anchor = size_t(std::clamp(branches[branch].trunkAnchor, 0, int(trunk.size() - 1)));
62 branchInflows[anchor] += inletFlow;
63 }
64
65 std::vector<float> rawTrunk(result.trunk.size(), 0.f);
66 float accumulatedBranches = 0.f;
67 for (size_t segment = 0; segment + 1 < trunk.size(); ++segment) {
68 accumulatedBranches += branchInflows[segment];
69 const float distributedRecharge = recharge * (0.35f + 0.65f * float(segment + 1) / float(trunk.size() - 1));
70 rawTrunk[segment] =
71 segmentCapacity(trunk[segment], trunk[segment + 1], gradient) * distributedRecharge + accumulatedBranches;
72 maximumRaw = std::max(maximumRaw, rawTrunk[segment]);
73 }
74
75 const float transportCapacity = std::clamp(std::sqrt(gradient / 0.35f) * (0.35f + recharge), 0.25f, 1.45f);
76 const float diffusionLimit = std::clamp(std::log2(transportG + 1.f) / 2.585f, 0.f, 1.f);
77 float channelExponent = 0.55f;
78 if (result.dissolutionRegime == "channeling")
79 channelExponent = 1.55f - 0.45f * diffusionLimit;
80 else if (result.dissolutionRegime == "wormholing")
81 channelExponent = 2.8f - 1.2f * diffusionLimit;
82 auto convert = [&](float raw, float distanceFromInlet) {
83 const float normalized = raw / maximumRaw;
84 const float regimeFlow = std::pow(std::max(normalized, 1e-6f), channelExponent);
85 const float focused = (1.f - focusing) + focusing * regimeFlow;
86 const float penetration = result.dissolutionRegime == "uniform"
87 ? 1.f
88 : 0.35f + 0.65f * std::exp(-distanceFromInlet / result.reactantPenetration);
89 const float reactiveFlow = std::clamp(focused * penetration * transportCapacity, 0.25f, 1.45f);
90 return 1.f + erosion * (reactiveFlow - 1.f);
91 };
92 result.minimum = 1.45f;
93 result.maximum = 0.25f;
94 for (size_t segment = 0; segment < rawTrunk.size(); ++segment) {
95 const float distance = rawTrunk.size() > 1 ? float(segment) / float(rawTrunk.size() - 1) : 0.f;
96 result.trunk[segment] = convert(rawTrunk[segment], distance);
97 result.minimum = std::min(result.minimum, result.trunk[segment]);
98 result.maximum = std::max(result.maximum, result.trunk[segment]);
99 }
100 for (size_t branch = 0; branch < rawBranches.size(); ++branch) {
101 for (size_t segment = 0; segment < rawBranches[branch].size(); ++segment) {
102 const float distance = rawBranches[branch].size() > 1 ? float(rawBranches[branch].size() - 1 - segment) /
103 float(rawBranches[branch].size() - 1)
104 : 0.f;
105 result.branches[branch][segment] = convert(rawBranches[branch][segment], distance);
106 result.minimum = std::min(result.minimum, result.branches[branch][segment]);
107 result.maximum = std::max(result.maximum, result.branches[branch][segment]);
108 }
109 }
110 return result;
111}
112
113} // namespace eve::procgen
float length
Definition CaveMesh.cpp:94
Vec3 anchor
Definition CaveMesh.cpp:90
MeleePoint3 b
Definition MeleeHit.cpp:41
MeleePoint3 a
Definition MeleeHit.cpp:40
float distance
float radius
std::string path
Definition PlayHost.cpp:110
float dz
float dy
float dx
float size
Definition TreeMesh.cpp:156
CaveHydrologyWeights buildCaveHydrology(const std::vector< CaveHydrologyPoint > &trunk, const std::vector< CaveHydrologyBranch > &branches, float erosion, float gradient, float recharge, float focusing, float damkohler, float transportG)
Builds cave hydrology.
CaveHydrologyWeights public API.
std::vector< std::vector< float > > branches