载入中...
搜索中...
未找到
CaveDepositAnchoring.cpp
浏览该文件的文档.
2
3#include <algorithm>
4#include <cmath>
5
6namespace eve::procgen {
7namespace {
8
9float lengthSquared(CaveFieldPoint point) { return point.x * point.x + point.y * point.y + point.z * point.z; }
10
11CaveFieldPoint normalize(CaveFieldPoint point) {
12 const float length2 = lengthSquared(point);
13 if (length2 < 1e-10f) return {};
14 const float inverseLength = 1.f / std::sqrt(length2);
15 return {point.x * inverseLength, point.y * inverseLength, point.z * inverseLength};
16}
17
18float interpolateZero(float aPosition, float aValue, float bPosition, float bValue) {
19 const float denominator = aValue - bValue;
20 if (std::abs(denominator) < 1e-8f) return (aPosition + bPosition) * 0.5f;
21 return aPosition + (bPosition - aPosition) * std::clamp(aValue / denominator, 0.f, 1.f);
22}
23
24CaveSurfaceAnchor makeAnchor(const std::vector<float>& density, int nx, int ny, int nz, CaveFieldPoint position) {
26}
27
28} // namespace
29
30std::optional<CaveVerticalSpan> findCaveVerticalSpan(const std::vector<float>& density, int nx, int ny, int nz, float x,
31 float z, float preferredY) {
32 if (nx < 2 || ny < 3 || nz < 2 || density.size() != size_t(nx) * size_t(ny) * size_t(nz)) return std::nullopt;
33 x = std::clamp(x, -1.f, 1.f);
34 z = std::clamp(z, -1.f, 1.f);
35 preferredY = std::clamp(preferredY, -1.f, 1.f);
36
37 struct Interval {
38 float floorY;
39 float ceilingY;
40 };
41 std::vector<Interval> intervals;
42 bool inAir = false;
43 float floorY = -1.f;
44 float previousY = -1.f;
45 float previousVal = sampleCaveDensity(density, nx, ny, nz, {x, previousY, z});
46 for (int yIndex = 1; yIndex < ny; ++yIndex) {
47 const float y = float(yIndex) / float(ny - 1) * 2.f - 1.f;
48 const float value = sampleCaveDensity(density, nx, ny, nz, {x, y, z});
49 if (!inAir && previousVal >= 0.f && value < 0.f) {
50 floorY = interpolateZero(previousY, previousVal, y, value);
51 inAir = true;
52 } else if (inAir && previousVal < 0.f && value >= 0.f) {
53 intervals.push_back({floorY, interpolateZero(previousY, previousVal, y, value)});
54 inAir = false;
55 }
56 previousY = y;
57 previousVal = value;
58 }
59 if (intervals.empty()) return std::nullopt;
60
61 const Interval* selected = nullptr;
62 for (const Interval& interval : intervals) {
63 if (preferredY >= interval.floorY && preferredY <= interval.ceilingY) {
64 selected = &interval;
65 break;
66 }
67 }
68 if (selected == nullptr) {
69 selected = &*std::min_element(intervals.begin(), intervals.end(), [preferredY](const auto& a, const auto& b) {
70 const float aDistance = std::abs((a.floorY + a.ceilingY) * 0.5f - preferredY);
71 const float bDistance = std::abs((b.floorY + b.ceilingY) * 0.5f - preferredY);
72 return aDistance < bDistance;
73 });
74 }
75 const float minimumGap = 4.f / float(ny - 1);
76 if (selected->ceilingY - selected->floorY < minimumGap) return std::nullopt;
77
79 span.floor = makeAnchor(density, nx, ny, nz, {x, selected->floorY, z});
80 span.ceiling = makeAnchor(density, nx, ny, nz, {x, selected->ceilingY, z});
81 if (lengthSquared(span.floor.rockNormal) < 0.5f || lengthSquared(span.ceiling.rockNormal) < 0.5f)
82 return std::nullopt;
83 return span;
84}
85
86std::optional<CaveSurfaceAnchor> projectToFinalCaveSurface(const std::vector<float>& density, int nx, int ny, int nz,
87 CaveFieldPoint point, float maximumDistance) {
88 if (nx < 2 || ny < 2 || nz < 2 || density.size() != size_t(nx) * size_t(ny) * size_t(nz) || maximumDistance <= 0.f)
89 return std::nullopt;
90 const CaveFieldPoint original = point;
91 for (int iteration = 0; iteration < 10; ++iteration) {
92 const float value = sampleCaveDensity(density, nx, ny, nz, point);
93 const CaveFieldPoint gradient = sampleCaveDensityGradient(density, nx, ny, nz, point);
94 const float gradientLength2 = lengthSquared(gradient);
95 if (gradientLength2 < 1e-8f) return std::nullopt;
96 point.x = std::clamp(point.x - gradient.x * value / gradientLength2, -1.f, 1.f);
97 point.y = std::clamp(point.y - gradient.y * value / gradientLength2, -1.f, 1.f);
98 point.z = std::clamp(point.z - gradient.z * value / gradientLength2, -1.f, 1.f);
99 }
100 const CaveFieldPoint displacement{point.x - original.x, point.y - original.y, point.z - original.z};
101 const float tolerance = 1.f / float(std::min({nx - 1, ny - 1, nz - 1}));
102 if (lengthSquared(displacement) > maximumDistance * maximumDistance ||
103 std::abs(sampleCaveDensity(density, nx, ny, nz, point)) > tolerance)
104 return std::nullopt;
105 CaveSurfaceAnchor anchor = makeAnchor(density, nx, ny, nz, point);
106 if (lengthSquared(anchor.rockNormal) < 0.5f) return std::nullopt;
107 return anchor;
108}
109
110} // namespace eve::procgen
double value
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
float z
Definition AnimClip.cpp:738
Vec3 anchor
Definition CaveMesh.cpp:90
float nx
float nz
float ny
std::array< float, 3 > position
MeleePoint3 b
Definition MeleeHit.cpp:41
MeleePoint3 a
Definition MeleeHit.cpp:40
glm::vec3 point
float length2(float x, float z)
Length 2.
Definition AnimMath.h:150
float lengthSquared(Vec3 value)
Length squared.
Vec2 normalize(const Vec2 &a)
Normalize.
Definition UrbanTypes.h:44
std::optional< CaveSurfaceAnchor > projectToFinalCaveSurface(const std::vector< float > &density, int nx, int ny, int nz, CaveFieldPoint point, float maximumDistance)
Projects a nearby field-space point to the final cave zero isosurface.
std::optional< CaveVerticalSpan > findCaveVerticalSpan(const std::vector< float > &density, int nx, int ny, int nz, float x, float z, float preferredY)
Finds the first connected cave-air interval intersected by a vertical ray.
float sampleCaveDensity(const std::vector< float > &density, int nx, int ny, int nz, CaveFieldPoint point)
Sample cave density.
CaveFieldPoint sampleCaveDensityGradient(const std::vector< float > &density, int nx, int ny, int nz, CaveFieldPoint point)
Sample cave density gradient.
CaveFieldPoint public API.
CaveSurfaceAnchor public API.
CaveVerticalSpan public API.