载入中...
搜索中...
未找到
CaveKnickpoint.cpp
浏览该文件的文档.
2
3#include <algorithm>
4#include <cmath>
5
6namespace eve::procgen {
7namespace {
8
9CaveHydrologyVec3 subtract(CaveHydrologyVec3 a, CaveHydrologyVec3 b) { return {a.x - b.x, a.y - b.y, a.z - b.z}; }
10
11CaveHydrologyVec3 add(CaveHydrologyVec3 a, CaveHydrologyVec3 b) { return {a.x + b.x, a.y + b.y, a.z + b.z}; }
12
13CaveHydrologyVec3 multiply(CaveHydrologyVec3 value, float scale) {
14 return {value.x * scale, value.y * scale, value.z * scale};
15}
16
17float dot(CaveHydrologyVec3 a, CaveHydrologyVec3 b) { return a.x * b.x + a.y * b.y + a.z * b.z; }
18
19float length(CaveHydrologyVec3 value) { return std::sqrt(dot(value, value)); }
20
21CaveHydrologyVec3 normalize(CaveHydrologyVec3 value) {
22 const float magnitude = length(value);
23 return magnitude > 1e-6f ? multiply(value, 1.f / magnitude) : CaveHydrologyVec3{1.f, 0.f, 0.f};
24}
25
26float smoothstep(float lo, float hi, float value) {
27 const float t = std::clamp((value - lo) / std::max(hi - lo, 1e-6f), 0.f, 1.f);
28 return t * t * (3.f - 2.f * t);
29}
30
31float downwardSlope(const CaveHydrologyPoint& a, const CaveHydrologyPoint& b) {
32 const CaveHydrologyVec3 delta = subtract(b.position, a.position);
33 return std::max(0.f, -delta.y / std::max(length(delta), 1e-6f));
34}
35
36} // namespace
37
38std::vector<CaveKnickpointSite> createCaveKnickpointSites(const std::vector<CaveHydrologyPoint>& trunk,
39 const std::vector<float>& hydraulicWeights,
40 float sedimentLoad) {
41 std::vector<CaveKnickpointSite> sites;
42 if (trunk.size() < 4 || sedimentLoad <= 0.f) return sites;
43 const float toolAvailability = smoothstep(0.025f, 0.28f, sedimentLoad);
44 const float coverProtection = std::clamp(sedimentLoad * sedimentLoad * 0.68f, 0.f, 0.68f);
45 const float toolsAndCover = toolAvailability * (1.f - coverProtection);
46 for (size_t i = 1; i + 1 < trunk.size(); ++i) {
47 const float incomingSlope = downwardSlope(trunk[i - 1], trunk[i]);
48 const float outgoingSlope = downwardSlope(trunk[i], trunk[i + 1]);
49 const float slopeBreak = std::max(0.f, outgoingSlope - incomingSlope);
50 const float drop = std::max(0.f, trunk[i].position.y - trunk[i + 1].position.y);
51 const float radius = 0.5f * (trunk[i].radius + trunk[i + 1].radius);
52 if (outgoingSlope < 0.28f || slopeBreak < 0.12f || drop < radius * 0.25f) continue;
53
54 const CaveHydrologyVec3 tangent = normalize(subtract(trunk[i + 1].position, trunk[i].position));
55 CaveHydrologyVec3 lateral = normalize({-tangent.z, 0.f, tangent.x});
56 if (std::fabs(tangent.y) > 0.94f) lateral = {0.f, 0.f, 1.f};
57 const float hydraulicIntensity = i < hydraulicWeights.size() ? hydraulicWeights[i] : 1.f;
58 const float erosionPotential = smoothstep(0.12f, 0.65f, slopeBreak) * toolsAndCover *
59 std::pow(std::clamp(hydraulicIntensity, 0.25f, 1.6f), 1.15f);
60 const float poolScale = radius * (0.9f + std::min(drop / std::max(radius, 1e-6f), 1.2f) * 0.35f);
61 CaveHydrologyVec3 poolCenter = add(trunk[i + 1].position, multiply(tangent, radius * 0.28f));
62 poolCenter.y -= radius * 0.52f;
63 CaveHydrologyVec3 headwallCenter = add(trunk[i].position, multiply(tangent, radius * 0.18f));
64 headwallCenter.y -= radius * 0.24f;
65 sites.push_back({trunk[i].position, poolCenter, headwallCenter, tangent, lateral, poolScale * 1.65f,
66 poolScale * 0.92f, poolScale * 1.05f, slopeBreak, drop, erosionPotential});
67 }
68 return sites;
69}
70
72 const std::vector<CaveKnickpointSite>& sites) {
74 for (size_t i = 0; i < sites.size(); ++i) {
75 const CaveKnickpointSite& site = sites[i];
76 const CaveHydrologyVec3 poolDelta = subtract(point, site.poolCenter);
77 const float along = dot(poolDelta, site.tangent);
78 const float lateral = dot(poolDelta, site.lateral);
79 const float vertical = poolDelta.y;
80 const float poolDistance =
81 std::sqrt((along * along) / std::max(site.alongRadius * site.alongRadius, 1e-6f) +
82 (lateral * lateral) / std::max(site.lateralRadius * site.lateralRadius, 1e-6f) +
83 (vertical * vertical) / std::max(site.depthRadius * site.depthRadius, 1e-6f));
84 const float poolEnvelope = 1.f - smoothstep(0.1f, 1.f, poolDistance);
85 const float floorBias = 1.f - smoothstep(-0.12f, 0.68f, vertical / std::max(site.depthRadius, 1e-6f));
86 const float verticalDrilling = poolEnvelope * floorBias * site.erosionPotential;
87
88 const CaveHydrologyVec3 headDelta = subtract(point, site.headwallCenter);
89 const float headAlong = dot(headDelta, site.tangent);
90 const float headLateral = dot(headDelta, site.lateral);
91 const float headVertical = headDelta.y;
92 const float headDistance =
93 std::sqrt((headAlong * headAlong) / std::max(site.alongRadius * site.alongRadius * 0.22f, 1e-6f) +
94 (headLateral * headLateral) / std::max(site.lateralRadius * site.lateralRadius, 1e-6f) +
95 (headVertical * headVertical) / std::max(site.depthRadius * site.depthRadius * 0.42f, 1e-6f));
96 const float headEnvelope = 1.f - smoothstep(0.12f, 1.f, headDistance);
97 const float lowerFace = 1.f - smoothstep(0.05f, 0.75f, headVertical / std::max(site.depthRadius, 1e-6f));
98 const float headwallUndercut = headEnvelope * lowerFace * site.erosionPotential * 0.48f;
99 const float erosion = std::max(verticalDrilling, headwallUndercut);
100 if (erosion > result.erosion) result = {erosion, verticalDrilling, headwallUndercut, site.slopeBreak, int(i)};
101 }
102 return result;
103}
104
105} // namespace eve::procgen
double value
Vec3 tangent
Definition CaveMesh.cpp:80
float length
Definition CaveMesh.cpp:94
std::array< float, 3 > position
std::array< float, 3 > scale
MeleePoint3 b
Definition MeleeHit.cpp:41
MeleePoint3 a
Definition MeleeHit.cpp:40
float radius
float t
glm::vec3 point
Vec2 normalize(const Vec2 &a)
Normalize.
Definition UrbanTypes.h:44
double dot(const Vec2 &a, const Vec2 &b)
Dot.
Definition UrbanTypes.h:38
CaveKnickpointSample sampleCaveKnickpointErosion(CaveHydrologyVec3 point, const std::vector< CaveKnickpointSite > &sites)
Sample plunge-pool drilling and lower-headwall erosion around derived knickpoints.
std::vector< CaveKnickpointSite > createCaveKnickpointSites(const std::vector< CaveHydrologyPoint > &trunk, const std::vector< float > &hydraulicWeights, float sedimentLoad)
Derive knickpoints from steepening downstream segments of the authoritative trunk path.
CaveHydrologyVec3 public API.
Local vertical drilling and headwall-undercut response at a cave-stream knickpoint.
One slope-break-driven cave-stream knickpoint and downstream plunge pool.