载入中...
搜索中...
未找到
CaveWetness.cpp
浏览该文件的文档.
2
3#include "procgen/MeshBuild.h"
4
5#include <algorithm>
6#include <cmath>
7#include <cstddef>
8#include <string>
9#include <vector>
10
11namespace eve::procgen {
12namespace {
13
14struct WetVertex {
15 float px = 0.f, py = 0.f, pz = 0.f;
16 float nx = 0.f, ny = 0.f, nz = 0.f;
17 float u = 0.f, v = 0.f;
18 float wetness = 0.f;
19};
20
21uint32_t hash(uint32_t value) {
22 value ^= value >> 16u;
23 value *= 0x7feb352du;
24 value ^= value >> 15u;
25 value *= 0x846ca68bu;
26 return value ^ (value >> 16u);
27}
28
29float latticeNoise(float x, float y, float z, uint32_t seed) {
30 const int ix = int(std::floor(x)), iy = int(std::floor(y)), iz = int(std::floor(z));
31 const float fx = x - float(ix), fy = y - float(iy), fz = z - float(iz);
32 auto smooth = [](float t) { return t * t * (3.f - 2.f * t); };
33 auto sample = [seed](int sx, int sy, int sz) {
34 const uint32_t h = hash(uint32_t(sx) * 73856093u ^ uint32_t(sy) * 19349663u ^ uint32_t(sz) * 83492791u ^ seed);
35 return float(h & 0xffffu) / 32767.5f - 1.f;
36 };
37 auto lerp = [](float a, float b, float t) { return a + (b - a) * t; };
38 const float ux = smooth(fx), uy = smooth(fy), uz = smooth(fz);
39 const float x00 = lerp(sample(ix, iy, iz), sample(ix + 1, iy, iz), ux);
40 const float x10 = lerp(sample(ix, iy + 1, iz), sample(ix + 1, iy + 1, iz), ux);
41 const float x01 = lerp(sample(ix, iy, iz + 1), sample(ix + 1, iy, iz + 1), ux);
42 const float x11 = lerp(sample(ix, iy + 1, iz + 1), sample(ix + 1, iy + 1, iz + 1), ux);
43 return lerp(lerp(x00, x10, uy), lerp(x01, x11, uy), uz);
44}
45
46WetVertex interpolate(WetVertex a, WetVertex b) {
47 const float denominator = a.wetness - b.wetness;
48 const float t = std::fabs(denominator) > 1e-12f ? std::clamp(a.wetness / denominator, 0.f, 1.f) : 0.5f;
49 auto lerp = [t](float from, float to) { return from + (to - from) * t; };
50 return {lerp(a.px, b.px), lerp(a.py, b.py), lerp(a.pz, b.pz),
51 lerp(a.nx, b.nx), lerp(a.ny, b.ny), lerp(a.nz, b.nz),
52 lerp(a.u, b.u), lerp(a.v, b.v), 0.f};
53}
54
55std::vector<WetVertex> clip(const WetVertex (&triangle)[3], bool keepWet) {
56 std::vector<WetVertex> input{triangle, triangle + 3};
57 std::vector<WetVertex> output;
58 output.reserve(4);
59 for (size_t i = 0; i < input.size(); ++i) {
60 const WetVertex current = input[i];
61 const WetVertex next = input[(i + 1) % input.size()];
62 const bool currentInside = keepWet ? current.wetness >= 0.f : current.wetness <= 0.f;
63 const bool nextInside = keepWet ? next.wetness >= 0.f : next.wetness <= 0.f;
64 if (currentInside) output.push_back(current);
65 if (currentInside != nextInside) output.push_back(interpolate(current, next));
66 }
67 return output;
68}
69
70void emitPolygon(MeshBuild& mesh, const std::vector<WetVertex>& polygon, const std::string& group) {
71 if (polygon.size() < 3) return;
72 mesh.setActiveGroup(group);
73 for (size_t corner = 1; corner + 1 < polygon.size(); ++corner) {
74 const uint32_t base = uint32_t(mesh.getVertexCount());
75 for (const WetVertex& vertex : {polygon[0], polygon[corner], polygon[corner + 1]})
76 mesh.addVertex(vertex.px, vertex.py, vertex.pz, vertex.nx, vertex.ny, vertex.nz, vertex.u, vertex.v);
77 mesh.addTriangle(base, base + 1, base + 2);
78 }
79}
80
81} // namespace
82
83float caveWetnessField(CaveHydrologyVec3 point, const std::vector<CaveHydrologyPoint>& drainageSpine,
84 float fallbackRadius, uint32_t seed) {
85 float nearestDistance2 = 1e9f;
86 float nearestY = 0.f;
87 float nearestRadius = fallbackRadius;
88 for (size_t i = 1; i < drainageSpine.size(); ++i) {
89 const CaveHydrologyVec3 start = drainageSpine[i - 1].position;
90 const CaveHydrologyVec3 end = drainageSpine[i].position;
91 const CaveHydrologyVec3 segment{end.x - start.x, end.y - start.y, end.z - start.z};
92 const float length2 = segment.x * segment.x + segment.y * segment.y + segment.z * segment.z;
93 const CaveHydrologyVec3 relative{point.x - start.x, point.y - start.y, point.z - start.z};
94 const float t =
95 length2 > 1e-8f
96 ? std::clamp((relative.x * segment.x + relative.y * segment.y + relative.z * segment.z) / length2, 0.f,
97 1.f)
98 : 0.f;
99 const CaveHydrologyVec3 nearest{start.x + segment.x * t, start.y + segment.y * t, start.z + segment.z * t};
100 const float dx = point.x - nearest.x, dy = point.y - nearest.y, dz = point.z - nearest.z;
101 const float distance2 = dx * dx + dy * dy + dz * dz;
102 if (distance2 < nearestDistance2) {
103 nearestDistance2 = distance2;
104 nearestY = nearest.y;
105 nearestRadius = drainageSpine[i - 1].radius + (drainageSpine[i].radius - drainageSpine[i - 1].radius) * t;
106 }
107 }
108 const float radius2 = std::max(nearestRadius * nearestRadius, 1e-8f);
109 const float drainage = (radius2 * 6.25f - nearestDistance2) / (radius2 * 6.25f);
110 const float gravity = (nearestY - nearestRadius * 0.22f - point.y) / std::max(nearestRadius, 1e-4f);
111 const float surfaceAccess = latticeNoise(point.x * 4.f, point.y * 2.f, point.z * 4.f, seed ^ 0x68e31da4u) + 0.32f;
112 return std::min({drainage, gravity, surfaceAccess});
113}
114
115CaveWetnessRefinement refineCaveWetnessBoundary(MeshBuild& mesh, const std::vector<CaveHydrologyPoint>& drainageSpine,
116 float fallbackRadius, uint32_t seed, bool splitBoundary) {
117 MeshBuild refined;
118 refined.reserve(mesh.getVertexCount() * 2, mesh.getIndexCount() * 2);
119 refined.setActiveGroup("caveWalls");
120 refined.setActiveGroup("speleothems");
121 refined.setActiveGroup("wetWalls");
122 for (int group = 0; group < mesh.getGroupCount(); ++group) {
123 const std::string name = mesh.getGroupName(group);
124 if (name != "caveWalls" && name != "wetWalls" && name != "speleothems") refined.setActiveGroup(name);
125 }
127 for (int triangleIndex = 0; triangleIndex < mesh.getIndexCount() / 3; ++triangleIndex) {
128 WetVertex triangle[3];
129 for (int corner = 0; corner < 3; ++corner) {
130 const int vertex = mesh.getIndex(triangleIndex * 3 + corner);
131 const CaveHydrologyVec3 point{mesh.getPositionX(vertex) * 2.f, mesh.getPositionY(vertex) * 2.f,
132 mesh.getPositionZ(vertex) * 2.f};
133 triangle[corner] = {mesh.getPositionX(vertex),
134 mesh.getPositionY(vertex),
135 mesh.getPositionZ(vertex),
136 mesh.getNormalX(vertex),
137 mesh.getNormalY(vertex),
138 mesh.getNormalZ(vertex),
139 mesh.getUvU(vertex),
140 mesh.getUvV(vertex),
141 caveWetnessField(point, drainageSpine, fallbackRadius, seed)};
142 }
143 const std::string sourceGroup = mesh.getGroupName(mesh.getTriangleGroup(triangleIndex));
144 if (sourceGroup != "caveWalls" && sourceGroup != "wetWalls") {
145 emitPolygon(refined, {triangle[0], triangle[1], triangle[2]}, sourceGroup);
146 continue;
147 }
148 const bool anyWet = triangle[0].wetness >= 0.f || triangle[1].wetness >= 0.f || triangle[2].wetness >= 0.f;
149 const bool anyDry = triangle[0].wetness < 0.f || triangle[1].wetness < 0.f || triangle[2].wetness < 0.f;
150 if (!splitBoundary || !anyWet || !anyDry) {
151 const CaveHydrologyVec3 center{(triangle[0].px + triangle[1].px + triangle[2].px) * (2.f / 3.f),
152 (triangle[0].py + triangle[1].py + triangle[2].py) * (2.f / 3.f),
153 (triangle[0].pz + triangle[1].pz + triangle[2].pz) * (2.f / 3.f)};
154 const bool wet = caveWetnessField(center, drainageSpine, fallbackRadius, seed) > 0.f;
155 emitPolygon(refined, {triangle[0], triangle[1], triangle[2]}, wet ? "wetWalls" : "caveWalls");
156 continue;
157 }
158 ++result.boundaryTriangles;
159 const std::vector<WetVertex> wet = clip(triangle, true);
160 const std::vector<WetVertex> dry = clip(triangle, false);
161 const int emitted = int(wet.size() >= 3 ? wet.size() - 2 : 0) + int(dry.size() >= 3 ? dry.size() - 2 : 0);
162 result.addedTriangles += emitted - 1;
163 emitPolygon(refined, wet, "wetWalls");
164 emitPolygon(refined, dry, "caveWalls");
165 }
166 mesh = std::move(refined);
167 return result;
168}
169
170} // namespace eve::procgen
double value
Duration start
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
float z
Definition AnimClip.cpp:738
Vec3 relative
Definition AnimSmr.cpp:164
std::string output
std::string from
building::EdgeCurveGroup group
float py
float nx
float nz
float ny
float pz
float wetness
std::array< std::uint8_t, 32 > hash
Definition Evpack.cpp:172
EvpackChunkInput input
Definition Evpack.cpp:170
int triangle
glm::vec4 clip
float u
Definition Grass.cpp:233
float v
HexCoordinates to
Cell the unit walks towards on this segment.
Definition HexUnits.cpp:64
int h
std::vector< Colorf > px
std::string name
MeleePoint3 b
Definition MeleeHit.cpp:41
MeleePoint3 a
Definition MeleeHit.cpp:40
std::uint32_t seed
Definition PointSet.cpp:807
float t
Mesh * mesh
double current
float dz
float dy
float dx
double gravity
glm::vec3 point
CPU triangle mesh from procedural mesh recipes (e.g. marching cubes). Positions/normals are xyz-packe...
Definition MeshBuild.h:19
void reserve(int vertexCount, int indexCount)
Reserve.
Definition MeshBuild.cpp:20
int setActiveGroup(const std::string &name)
Select/create the named group assigned to subsequently added triangles.
Definition MeshBuild.cpp:53
Vec3 interpolate(Vec3 start, Vec3 end, float amount) noexcept
Interpolate.
constexpr HexDirection next(HexDirection d) noexcept
The next direction clockwise (NW wraps to NE).
Definition HexMetrics.h:76
constexpr HexVec3 lerp(HexVec3 a, HexVec3 b, float t) noexcept
Linear interpolation between two positions.
Definition HexMetrics.h:51
double sample(const Heightmap &map, double u, double v)
Sample.
CaveWetnessRefinement refineCaveWetnessBoundary(MeshBuild &mesh, const std::vector< CaveHydrologyPoint > &drainageSpine, float fallbackRadius, uint32_t seed, bool splitBoundary)
Refine cave wetness boundary.
float caveWetnessField(CaveHydrologyVec3 point, const std::vector< CaveHydrologyPoint > &drainageSpine, float fallbackRadius, uint32_t seed)
Cave wetness field.
CaveHydrologyVec3 public API.
CaveWetnessRefinement public API.
Definition CaveWetness.h:13