11constexpr float Pi = 3.1415926535f;
13float ellipsoidDistance(
float x,
float y,
float z,
const CaveBreakdownEvent& event) {
14 const float c = std::cos(event.yaw);
15 const float s = std::sin(event.yaw);
16 const float dx =
x -
event.x;
17 const float dz =
z -
event.z;
18 const float u =
dx *
c +
dz *
s;
19 const float v = -
dx *
s +
dz *
c;
20 const float q = std::sqrt((
u *
u) / (event.scarX * event.scarX) +
21 ((
y - event.ceilingY) * (
y - event.ceilingY)) / (event.scarY * event.scarY) +
22 (
v *
v) / (event.scarZ * event.scarZ));
23 return (
q - 1.f) * std::min({
event.scarX,
event.scarY,
event.scarZ});
26float roundedBoxDistance(
float x,
float y,
float z,
const CaveBreakdownBlock& block) {
27 const float c = std::cos(block.yaw);
28 const float s = std::sin(block.yaw);
29 const float dx =
x - block.x;
30 const float dz =
z - block.z;
31 const float u = std::fabs(
dx *
c +
dz *
s) - block.hx;
32 const float v = std::fabs(
y - block.y) - block.hy;
33 const float w = std::fabs(-
dx *
s +
dz *
c) - block.hz;
34 const float outside = std::sqrt(std::max(
u, 0.f) * std::max(
u, 0.f) + std::max(
v, 0.f) * std::max(
v, 0.f) +
35 std::max(
w, 0.f) * std::max(
w, 0.f));
36 return outside + std::min(std::max({
u,
v,
w}), 0.f) - 0.006f;
44 if (
strength <= 0.f || eventCount <= 0 || chambers.empty())
return result;
46 std::mt19937 rng(
seed ^ 0x91e10da5u);
47 std::uniform_real_distribution<float>
unit(0.f, 1.f);
48 const float boundedStrength = std::clamp(
strength, 0.f, 1.f);
49 result.
events.reserve(
size_t(eventCount));
50 for (
int i = 0; i < eventCount; ++i) {
53 event.
x = chamber.
x + (
unit(rng) * 2.f - 1.f) * chamber.
rx * 0.38f;
54 event.z = chamber.
z + (
unit(rng) * 2.f - 1.f) * chamber.
rz * 0.38f;
55 event.ceilingY = chamber.
y + chamber.
ry * (0.72f +
unit(rng) * 0.1f);
56 event.scarX = (0.075f +
unit(rng) * 0.065f) * (0.65f + 0.35f * boundedStrength);
57 event.scarY = (0.025f +
unit(rng) * 0.025f) * (0.7f + 0.3f * boundedStrength);
58 event.scarZ = (0.075f +
unit(rng) * 0.065f) * (0.65f + 0.35f * boundedStrength);
59 event.yaw =
unit(rng) * Pi;
61 const int blockCount = 2 + int(rng() % 3u);
62 event.blocks.reserve(
size_t(blockCount));
63 for (
int blockIndex = 0; blockIndex < blockCount; ++blockIndex) {
65 const float slab =
unit(rng);
66 block.
hx =
event.scarX * (0.22f +
unit(rng) * 0.18f);
67 block.
hz =
event.scarZ * (0.22f +
unit(rng) * 0.18f);
68 block.
hy = (slab < 0.58f ? 0.28f : 0.55f) * std::min(block.
hx, block.
hz);
69 block.
x =
event.x + (
unit(rng) * 2.f - 1.f) * event.
scarX * 0.65f;
70 block.
z =
event.z + (
unit(rng) * 2.f - 1.f) * event.
scarZ * 0.65f;
71 const float floorY = chamber.
y - chamber.
ry * 0.92f;
72 block.
y = floorY + block.
hy * 0.55f;
73 block.
yaw =
event.yaw + (
unit(rng) * 2.f - 1.f) * 0.42f;
74 event.blocks.push_back(block);
78 result.
detachedVolume += 4.f / 3.f * Pi *
event.scarX *
event.scarY *
event.scarZ;
79 result.
events.push_back(std::move(event));
100 if (std::fabs(roundedBoxDistance(
x,
y,
z, block)) <= tolerance)
return true;
std::array< double, 10 > q
float addCaveBreakdownBlocks(float x, float y, float z, float current, const CaveBreakdownSet &breakdown)
Union the event's landed breakdown blocks into a cave SDF.
bool isCaveBreakdownBlockSurface(float x, float y, float z, float tolerance, const CaveBreakdownSet &breakdown)
Test whether a point lies on a generated breakdown block surface.
CaveBreakdownSet createCaveBreakdown(const std::vector< CaveBreakdownChamber > &chambers, int eventCount, float strength, uint32_t seed)
Create paired ceiling-spall scars and floor blocks from host chambers.
float carveCaveBreakdownScars(float x, float y, float z, float current, const CaveBreakdownSet &breakdown)
Carve the event's shallow ceiling detachment scars from a cave SDF.
CaveBreakdownBlock public API.
CaveBreakdownChamber public API.
CaveBreakdownEvent public API.
CaveBreakdownSet public API.
std::vector< CaveBreakdownEvent > events