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,
32 if (erosion <= 0.f || trunk.size() < 2)
return result;
34 if (damkohler < 0.0008f)
36 else if (damkohler < 0.008f)
42 result.
reactantPenetration = std::clamp((0.002f / damkohler) * std::sqrt(transportG), 0.08f, 8.f);
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) {
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);
61 const size_t anchor = size_t(std::clamp(branches[branch].trunkAnchor, 0,
int(trunk.size() - 1)));
62 branchInflows[
anchor] += inletFlow;
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));
71 segmentCapacity(trunk[segment], trunk[segment + 1], gradient) * distributedRecharge + accumulatedBranches;
72 maximumRaw = std::max(maximumRaw, rawTrunk[segment]);
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;
79 channelExponent = 1.55f - 0.45f * diffusionLimit;
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;
89 const float reactiveFlow = std::clamp(focused * penetration * transportCapacity, 0.25f, 1.45f);
90 return 1.f + erosion * (reactiveFlow - 1.f);
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;
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)
105 result.
branches[branch][segment] = convert(rawBranches[branch][segment],
distance);
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.