11size_t voxelIndex(
int x,
int y,
int z,
int nx,
int ny) {
12 return size_t(
x) + size_t(
y) * size_t(
nx) + size_t(
z) * size_t(
nx) * size_t(
ny);
15uint64_t mixBits(uint64_t
value) {
17 value *= 0xbf58476d1ce4e5b9ULL;
19 value *= 0x94d049bb133111ebULL;
23float latticeValue(
int x,
int y,
int z, uint64_t
seed) {
24 uint64_t
key =
seed ^ (uint64_t(uint32_t(
x)) * 0x9e3779b185ebca87ULL);
25 key ^= uint64_t(uint32_t(
y)) * 0xc2b2ae3d27d4eb4fULL;
26 key ^= uint64_t(uint32_t(
z)) * 0x165667b19e3779f9ULL;
27 return float(mixBits(
key) >> 40u) * (2.f / 16777215.f) - 1.f;
32float lerp(
float a,
float b,
float t) {
return a + (
b -
a) *
t; }
34float valueNoise(
float x,
float y,
float z,
float frequency, uint64_t
seed) {
38 const int x0 = int(std::floor(
x)), y0 = int(std::floor(
y)), z0 = int(std::floor(
z));
39 const float tx = smooth(
x -
float(x0)), ty = smooth(
y -
float(y0)), tz = smooth(
z -
float(z0));
40 const float x00 =
lerp(latticeValue(x0, y0, z0,
seed), latticeValue(x0 + 1, y0, z0,
seed), tx);
41 const float x10 =
lerp(latticeValue(x0, y0 + 1, z0,
seed), latticeValue(x0 + 1, y0 + 1, z0,
seed), tx);
42 const float x01 =
lerp(latticeValue(x0, y0, z0 + 1,
seed), latticeValue(x0 + 1, y0, z0 + 1,
seed), tx);
43 const float x11 =
lerp(latticeValue(x0, y0 + 1, z0 + 1,
seed), latticeValue(x0 + 1, y0 + 1, z0 + 1,
seed), tx);
47float dot(
const CaveHydrologyVec3&
a,
const CaveHydrologyVec3&
b) {
return a.x *
b.x +
a.y *
b.y +
a.z *
b.z; }
51 if (
length <= 1e-6f)
return {1.f, 0.f, 0.f};
55CaveHydrologyVec3 add(CaveHydrologyVec3
a, CaveHydrologyVec3
b) {
return {
a.x +
b.x,
a.y +
b.y,
a.z +
b.z}; }
57CaveHydrologyVec3 mul(CaveHydrologyVec3
value,
float scale) {
61CaveHydrologyVec3 transverse(CaveHydrologyVec3
tangent) {
67CaveHydrologyVec3 flowWarp(CaveHydrologyVec3
position, CaveHydrologyVec3
tangent) {
68 constexpr float longitudinalScale = 0.28f;
75 const float broad = valueNoise(warped.x, warped.y, warped.z, 3.25f,
seed ^ 0x7265616374697665ULL);
76 const float detail = valueNoise(warped.x, warped.y, warped.z, 7.5f,
seed ^ 0x7061746368657321ULL);
77 const float spectrum = std::clamp(broad * 0.72f + detail * 0.28f, -1.f, 1.f);
78 const float normalized = smooth(spectrum * 0.5f + 0.5f);
79 return 0.35f + normalized * 1.65f;
85 const std::vector<float>& rateField,
86 const std::vector<CaveHydrologyVec3>& flowField,
91 density.size() != flowField.size() || density.size() !=
size_t(
nx) *
size_t(
ny) *
size_t(
nz))
94 const float hx = 2.f / float(
nx - 1), hy = 2.f / float(
ny - 1), hz = 2.f / float(
nz - 1);
95 const float cellScale = std::min({hx, hy, hz});
96 const float band = cellScale * 2.5f;
97 std::vector<float>
source(density.size());
98 std::vector<uint8_t> affected(density.size(), uint8_t(0));
99 float coherenceTotal = 0.f;
100 float flowCoherenceTotal = 0.f;
101 float transverseCoherenceTotal = 0.f;
102 int coherenceSamples = 0;
104 for (
int iteration = 0; iteration <
iterations; ++iteration) {
106 for (
int z = 2;
z <
nz - 2; ++
z) {
107 for (
int y = 2;
y <
ny - 2; ++
y) {
108 for (
int x = 2;
x <
nx - 2; ++
x) {
111 if (std::fabs(
value) > band)
continue;
112 const float px = float(
x) / float(
nx - 1) * 2.f - 1.f;
113 const float py = float(
y) / float(
ny - 1) * 2.f - 1.f;
114 const float pz = float(
z) / float(
nz - 1) * 2.f - 1.f;
118 const float localPatchRate = patchRate(
position, flow,
seed);
119 const float adjacentPatchRate = patchRate({
px + hx,
py,
pz}, flow,
seed);
120 const float flowPatchRate = patchRate(add(
position, mul(flow, cellScale)), flow,
seed);
121 const float transversePatchRate = patchRate(add(
position, mul(
across, cellScale)), flow,
seed);
122 coherenceTotal += 1.f - std::min(std::fabs(localPatchRate - adjacentPatchRate) / 1.65f, 1.f);
123 flowCoherenceTotal += 1.f - std::min(std::fabs(localPatchRate - flowPatchRate) / 1.65f, 1.f);
124 transverseCoherenceTotal +=
125 1.f - std::min(std::fabs(localPatchRate - transversePatchRate) / 1.65f, 1.f);
128 const float surfaceWeight = 1.f - std::clamp(std::fabs(
value) / band, 0.f, 1.f);
129 const float accessRate = std::clamp(rateField[
center], 0.25f, 2.5f);
130 const float coupledPatchRate = 1.f +
strength * (localPatchRate - 1.f);
131 const float retreat =
strength * cellScale * 0.032f * surfaceWeight * accessRate *
133 if (retreat <= 1e-7f)
continue;
134 density[
center] -= retreat;
135 if (affected[
center] == 0) {
147 if (coherenceSamples > 0) {
std::array< float, 3 > position
std::array< float, 3 > scale
const UnitySourceAsset & source
constexpr HexVec3 lerp(HexVec3 a, HexVec3 b, float t) noexcept
Linear interpolation between two positions.
Vec2 normalize(const Vec2 &a)
Normalize.
double dot(const Vec2 &a, const Vec2 &b)
Dot.
CaveReactivePatchinessResult evolveCaveSurfaceByCorrelatedReactivity(std::vector< float > &density, const std::vector< float > &rateField, const std::vector< CaveHydrologyVec3 > &flowField, int nx, int ny, int nz, float strength, uint64_t seed, int iterations)
Retreat a cave surface through a deterministic, multiscale correlated reactivity field.
CaveHydrologyVec3 public API.
Diagnostics from spatially correlated heterogeneous cave-wall dissolution.
float meanNeighborCoherence
float meanTransverseCoherence