载入中...
搜索中...
未找到
VolumeFluidFoam.cpp
浏览该文件的文档.
2#include <algorithm>
3#include <cmath>
4#include <glm/geometric.hpp>
5#include <iomanip>
6#include <limits>
7#include <locale>
8#include <sstream>
9#include <stdexcept>
10#include "fluids/VolumeFluid.h"
12
13namespace eve::fluids {
14namespace {
15bool range(float v, float low, float high) { return std::isfinite(v) && v >= low && v <= high; }
16Status invalid(const char* message) {
18}
19uint32_t next(uint32_t& state) {
20 state ^= state << 13;
21 state ^= state >> 17;
22 state ^= state << 5;
23 return state;
24}
25float unit(uint32_t& state) { return float(next(state) >> 8) * (1.f / 16777216.f); }
26glm::vec3 jitter(uint32_t& state, float radius) {
27 // Fixed three draws, uniformly distributed ball; no unbounded rejection loop.
28 const float z = 2.f * unit(state) - 1.f;
29 const float angle = 6.28318530718f * unit(state);
30 const float r = radius * std::cbrt(unit(state));
31 const float xy = std::sqrt(std::max(0.f, 1.f - z * z));
32 return r * glm::vec3(xy * std::cos(angle), xy * std::sin(angle), z);
33}
34} // namespace
35
37 return advanceFiltered(source, pool, seconds, false, 0, 1.f);
38}
39
41 unsigned actorGroup) {
42 return advanceFiltered(source, pool, seconds, true, actorGroup, 1.f);
43}
44
46 float seconds, unsigned actorGroup, float alpha) {
47 return advanceFiltered(source, pool, seconds, true, actorGroup, alpha);
48}
49
50Result<unsigned> VolumeFluidFoam::advanceFiltered(const VolumeFluid& source, VolumeFluidDiffuse& pool, float seconds,
51 bool filterActor, unsigned actorGroup, float alpha) {
52 if (!range(seconds, 0.f, 1.f / 30.f) || !range(alpha, 0.f, 1.f))
53 return Result<unsigned>::failure(invalid("Invalid foam timestep or interpolation alpha"));
54 const double credit = credit_ + double(seconds) * settings_.rate;
55 const auto whole = unsigned(std::floor(credit));
56 const double remainder = credit - whole;
57 const unsigned budget = std::min({whole, settings_.maxPerStep, pool.availableCapacity()});
58 if (budget == 0) {
59 credit_ = remainder;
61 }
62 if (source.particleCount() > 65536)
63 return Result<unsigned>::failure(invalid("Foam source exceeds 65536 particles"));
64 const auto particles = source.particleView();
65 positionScratch_.clear();
66 positionScratch_.reserve(particles.size());
67 for (size_t i = 0; i < particles.size(); ++i) {
68 const auto& p = particles[i];
69 if ((!filterActor || p.actorGroup == actorGroup) &&
70 (p.material.phase == VolumeFluidPhase::Liquid || p.material.phase == VolumeFluidPhase::Gas))
71 positionScratch_.push_back(source.interpolatedPositionUnchecked(i, alpha));
72 }
73 auto sampled = source.sampleFieldInto(positionScratch_, sampleScratch_);
74 if (!sampled) return Result<unsigned>::failure(sampled.status());
75 size_t eligibleCount = 0;
76 for (size_t i = 0; i < positionScratch_.size(); ++i) {
77 const auto& field = sampleScratch_[i];
78 const float curl2 = glm::dot(field.vorticity, field.vorticity);
79 if (!std::isfinite(curl2) || !std::isfinite(field.density))
80 return Result<unsigned>::failure(invalid("Invalid foam field sample"));
81 if (curl2 > settings_.vorticityThreshold * settings_.vorticityThreshold &&
82 field.density < settings_.densityThreshold)
83 ++eligibleCount;
84 }
85 const unsigned count = std::min(budget, unsigned(eligibleCount));
86 auto rng = randomState_;
87 batchScratch_.clear();
88 batchScratch_.reserve(count);
89 if (count != 0) {
90 const unsigned stride = unsigned(eligibleCount) / count;
91 const unsigned start = next(rng) % stride;
92 unsigned eligibleOrdinal = 0;
93 unsigned nextOrdinal = start;
94 for (size_t at = 0; at < positionScratch_.size() && batchScratch_.size() < count; ++at) {
95 const auto& field = sampleScratch_[at];
96 const float curl2 = glm::dot(field.vorticity, field.vorticity);
97 if (!(curl2 > settings_.vorticityThreshold * settings_.vorticityThreshold &&
98 field.density < settings_.densityThreshold))
99 continue;
100 if (eligibleOrdinal++ != nextOrdinal) continue;
101 batchScratch_.push_back(
102 {positionScratch_[at] + jitter(rng, settings_.randomness), field.velocity, settings_.lifetime});
103 nextOrdinal += stride;
104 }
105 }
106 auto admitted = pool.emit(batchScratch_);
107 if (!admitted) return Result<unsigned>::failure(admitted.status());
108 credit_ = remainder;
109 randomState_ = rng;
111}
112
114 std::ostringstream stream;
115 stream.imbue(std::locale::classic());
116 stream << std::setprecision(std::numeric_limits<double>::max_digits10) << credit_;
117 if (!stream) throw std::runtime_error("Foam credit encoding failed");
118 return {"eve.volume-fluid-foam", 1, settings_, stream.str(), randomState_};
119}
121 const auto& s = state.settings;
122 double credit = 0;
123 std::istringstream stream(state.credit);
124 stream.imbue(std::locale::classic());
125 stream >> std::noskipws >> credit;
126 if (state.schema != "eve.volume-fluid-foam" || state.version != 1 || state.randomState == 0 ||
127 !range(s.rate, 0.f, 1000000.f) || !range(s.randomness, 0.f, 10.f) ||
128 !range(s.vorticityThreshold, 0.f, 1000000.f) || !range(s.densityThreshold, 0.f, 1000000000.f) ||
129 !range(s.lifetime, 0.f, 86400.f) || s.lifetime == 0.f || s.maxPerStep == 0 || s.maxPerStep > 4096 ||
130 stream.fail() || !stream.eof() || !std::isfinite(credit) ||
131 credit < 0 || credit >= 1)
132 return Result<void>::failure(invalid("Invalid foam schema, settings, credit or RNG state"));
133 settings_ = s;
134 credit_ = credit;
135 randomState_ = state.randomState;
136 return Result<void>::success();
137}
138} // namespace eve::fluids
Duration start
float z
Definition AnimClip.cpp:738
const std::string & s
glm::vec4 p[6]
std::string message
double r
float v
Range range
float radius
std::uint32_t count
TacticalUnit * unit
const UnitySourceAsset & source
std::size_t at
float angle
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
static Status failure(StatusCode code, Diagnostic diagnostic)
Construct a failed status with one diagnostic.
Definition Status.h:84
Bounded, one-way fluid-advected secondary particle pool. @ownership Owns particles and capacity; no f...
Result< void > emit(std::span< const VolumeFluidDiffuseParticle > particles)
Admits an entire batch or fails without mutation; finite speed must be <=100 m/s.
unsigned availableCapacity() const
Returns remaining admission capacity without allocating.
Result< unsigned > advanceFromActor(const VolumeFluid &source, VolumeFluidDiffuse &pool, float seconds, unsigned actorGroup)
Emits only from particles owned by one emitter actor group.
Result< void > restore(const VolumeFluidFoamSnapshot &state)
Validates all settings/schema/credit/RNG before atomic replacement.
Result< unsigned > advanceFromActorInterpolated(const VolumeFluid &source, VolumeFluidDiffuse &pool, float seconds, unsigned actorGroup, float alpha)
Emits from one actor using fixed-step interpolated source positions.
Result< unsigned > advance(const VolumeFluid &source, VolumeFluidDiffuse &pool, float seconds)
Emits after the caller steps the source and advects existing diffuse particles.
VolumeFluidFoamSnapshot snapshot() const
Copies owning settings, fractional credit and isolated RNG state.
CPU position-based free-volume fluid with a bounded spatial grid. @ownership Owns all particle state;...
eve::StatusCode Status
GLSL compute kernels for the GPU surface-flow solver.
Definition FluidTarget.h:12
constexpr HexDirection next(HexDirection d) noexcept
The next direction clockwise (NW wraps to NE).
Definition HexMetrics.h:76
Result< int > invalid(std::string message)
Invalid.
const EditorValue * field(const EditorValue &value, const char *name)
Owning strict version-1 foam controller state; checkpoint the diffuse pool separately.