载入中...
搜索中...
未找到
CaveScallops.cpp
浏览该文件的文档.
2
3#include <algorithm>
4#include <cmath>
5
6namespace eve::procgen {
7namespace {
8
9constexpr float Pi = 3.1415926535f;
10
11float smoothstep(float edge0, float edge1, float value) {
12 const float t = std::clamp((value - edge0) / (edge1 - edge0), 0.f, 1.f);
13 return t * t * (3.f - 2.f * t);
14}
15
16float scallopCell(float along, float angle, float radius, float scale, float phaseOffset, float exponent,
17 float flowSeparation) {
18 const int cells = std::max(3, int(std::round(2.f * Pi * radius / scale)));
19 const float flowPhase = along * 2.f * Pi / scale + phaseOffset;
20 const float crossPhase = angle * float(cells) + 0.5f * std::sin(flowPhase * 0.5f) + phaseOffset * 0.37f;
21 const float stationaryWave = 0.5f + 0.5f * std::cos(flowPhase) + 0.16f * std::sin(flowPhase);
22 const float separatedPhase = flowPhase + (0.32f + 0.24f * (1.f - exponent)) * std::cos(flowPhase);
23 const float separatedWave = 0.5f + 0.5f * std::cos(separatedPhase) + 0.1f * std::sin(separatedPhase);
24 const float shiftedWave = std::clamp(stationaryWave + flowSeparation * (separatedWave - stationaryWave), 0.f, 1.f);
25 const float crossWave = 0.5f + 0.5f * std::cos(crossPhase);
26 return std::pow(shiftedWave * crossWave, exponent);
27}
28
29float dot(CaveHydrologyVec3 a, CaveHydrologyVec3 b) { return a.x * b.x + a.y * b.y + a.z * b.z; }
30CaveHydrologyVec3 sub(CaveHydrologyVec3 a, CaveHydrologyVec3 b) { return {a.x - b.x, a.y - b.y, a.z - b.z}; }
31CaveHydrologyVec3 add(CaveHydrologyVec3 a, CaveHydrologyVec3 b) { return {a.x + b.x, a.y + b.y, a.z + b.z}; }
32CaveHydrologyVec3 mul(CaveHydrologyVec3 a, float scale) { return {a.x * scale, a.y * scale, a.z * scale}; }
33
34} // namespace
35
37 CaveScallopSample result;
38 const float hydraulicScale = 1.f / std::sqrt(std::clamp(input.hydraulicIntensity, 0.25f, 1.45f));
39 const float seedPhase = float(input.seed % 1009u) * (2.f * Pi / 1009.f);
40 const float patchScale = std::max(input.baseScale * 5.5f, 1e-4f);
41 const float correlatedField = 0.68f * std::sin(input.along * 2.f * Pi / patchScale + seedPhase) +
42 0.32f * std::sin(input.angle * 2.f + seedPhase * 1.73f);
43 result.scaleMultiplier = std::exp(input.scaleVariability * 0.38f * correlatedField);
44 result.scale = input.baseScale * (1.f + input.hydraulicScaling * (hydraulicScale - 1.f)) * result.scaleMultiplier;
45 const float wallMask = 1.f - smoothstep(input.radius * 1.25f, input.radius * 2.2f, input.distance);
46 const float crestExponent = 0.62f - input.maturity * 0.24f;
47 const float youngCell =
48 scallopCell(input.along, input.angle, input.radius, result.scale, 0.f, crestExponent, input.flowSeparation);
49 // Normal ablation broadens troughs until adjacent cells merge. A subdued
50 // fine-scale remnant keeps the mature surface from becoming a single wave.
51 const float matureScale = result.scale * (1.f + input.maturity * 1.6f);
52 const float matureCell =
53 scallopCell(input.along, input.angle, input.radius, matureScale, 1.17f, crestExponent, input.flowSeparation);
54 const float coarsenedCell = std::max(youngCell * (1.f - input.maturity * 0.68f), matureCell * input.maturity);
55
56 // Curved conduits focus fresh reactant and separated flow on the outer bank.
57 // The broad cosine lobe avoids a seam while retaining the scallop-scale cusps.
58 const float outerBank = std::max(0.f, std::cos(input.angle - input.outerBankAngle));
59 const float bendGain = 1.f + input.bendUndercut * input.bendStrength * outerBank * 1.35f;
60 result.erosion = coarsenedCell * wallMask * std::clamp(result.scale / input.baseScale, 0.7f, 1.5f) * bendGain;
61 return result;
62}
63
64CavePassageFrame nearestCavePassageFrame(const CaveHydrologyVec3& point, const std::vector<CaveHydrologyPoint>& path,
65 const std::vector<float>& hydraulicIntensity) {
66 CavePassageFrame nearest;
67 float accumulated = 0.f;
68 auto nodeIntensity = [&](size_t node) {
69 if (hydraulicIntensity.empty()) return 1.f;
70 if (node == 0) return hydraulicIntensity.front();
71 if (node >= path.size() - 1) return hydraulicIntensity.back();
72 return 0.5f * (hydraulicIntensity[node - 1] + hydraulicIntensity[node]);
73 };
74 auto nodeBend = [&](size_t node) {
75 if (node == 0 || node + 1 >= path.size()) return CaveHydrologyVec3{};
76 const CaveHydrologyVec3 incoming = sub(path[node].position, path[node - 1].position);
77 const CaveHydrologyVec3 outgoing = sub(path[node + 1].position, path[node].position);
78 const float incomingLength = std::sqrt(dot(incoming, incoming));
79 const float outgoingLength = std::sqrt(dot(outgoing, outgoing));
80 if (incomingLength <= 1e-8f || outgoingLength <= 1e-8f) return CaveHydrologyVec3{};
81 return sub(mul(outgoing, 1.f / outgoingLength), mul(incoming, 1.f / incomingLength));
82 };
83 for (size_t i = 1; i < path.size(); ++i) {
84 const CaveHydrologyVec3 segment = sub(path[i].position, path[i - 1].position);
85 const float length2 = dot(segment, segment);
86 const float length = std::sqrt(length2);
87 const float t =
88 length2 > 1e-8f ? std::clamp(dot(sub(point, path[i - 1].position), segment) / length2, 0.f, 1.f) : 0.f;
89 const CaveHydrologyVec3 closest = add(path[i - 1].position, mul(segment, t));
90 const CaveHydrologyVec3 delta = sub(point, closest);
91 const float distance = std::sqrt(dot(delta, delta));
92 if (distance < nearest.distance) {
94 length > 1e-8f ? mul(segment, 1.f / length) : CaveHydrologyVec3{1.f, 0.f, 0.f};
95 CaveHydrologyVec3 binormal{-tangent.z, 0.f, tangent.x};
96 const float binormalLength = std::sqrt(dot(binormal, binormal));
97 binormal = binormalLength > 1e-6f ? mul(binormal, 1.f / binormalLength) : CaveHydrologyVec3{1.f, 0.f, 0.f};
98 nearest.along = accumulated + t * length;
99 nearest.angle = std::atan2(dot(delta, binormal), delta.y);
100 nearest.distance = distance;
101 nearest.radius = path[i - 1].radius + (path[i].radius - path[i - 1].radius) * t;
102 nearest.hydraulicIntensity = nodeIntensity(i - 1) + (nodeIntensity(i) - nodeIntensity(i - 1)) * t;
103 nearest.tangent = tangent;
104 const CaveHydrologyVec3 bend = add(mul(nodeBend(i - 1), 1.f - t), mul(nodeBend(i), t));
105 const float bendLength = std::sqrt(dot(bend, bend));
106 nearest.bendStrength = std::clamp(bendLength, 0.f, 1.f);
107 if (bendLength > 1e-6f) {
108 const CaveHydrologyVec3 outer = mul(bend, -1.f / bendLength);
109 nearest.outerBankAngle = std::atan2(dot(outer, binormal), outer.y);
110 }
111 }
112 accumulated += length;
113 }
114 return nearest;
115}
116
117} // namespace eve::procgen
double value
Vec3 tangent
Definition CaveMesh.cpp:80
float length
Definition CaveMesh.cpp:94
EvpackChunkInput input
Definition Evpack.cpp:170
std::array< float, 3 > position
std::array< float, 3 > scale
MeleePoint3 b
Definition MeleeHit.cpp:41
MeleePoint3 a
Definition MeleeHit.cpp:40
float distance
std::array< PixelCell, kPixelChunkSize *kPixelChunkSize > cells
float radius
std::string path
Definition PlayHost.cpp:110
float t
const RoadNode * node
glm::vec3 point
float angle
double dot(const Vec2 &a, const Vec2 &b)
Dot.
Definition UrbanTypes.h:38
CaveScallopSample sampleCaveScallops(const CaveScallopInput &input)
Sample cave scallops.
CavePassageFrame nearestCavePassageFrame(const CaveHydrologyVec3 &point, const std::vector< CaveHydrologyPoint > &path, const std::vector< float > &hydraulicIntensity)
Nearest cave passage frame.
CaveHydrologyVec3 public API.
CavePassageFrame public API.
CaveScallopInput public API.
CaveScallopSample public API.