载入中...
搜索中...
未找到
VolumeFluidDiffuse.cpp
浏览该文件的文档.
2#include <cmath>
3#include <glm/geometric.hpp>
5
6namespace eve::fluids {
7namespace {
8bool finite(glm::vec3 p) { return std::isfinite(p.x) && std::isfinite(p.y) && std::isfinite(p.z); }
9bool valid(const VolumeFluidDiffuseParticle& p) {
10 return finite(p.position) && finite(p.velocity) && glm::length(p.velocity) <= 100.f && std::isfinite(p.life) &&
11 p.life > 0.f && p.life <= 86400.f;
12}
13} // namespace
14Result<void> VolumeFluidDiffuse::emit(std::span<const VolumeFluidDiffuseParticle> particles) {
15 if (particles.size() > availableCapacity()) return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, "Diffuse capacity exceeded", "fluids.volume.diffuse"));
16 for (const auto& particle : particles)
17 if (!valid(particle)) return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, "Invalid diffuse particle", "fluids.volume.diffuse"));
18 particles_.insert(particles_.end(), particles.begin(), particles.end());
19 return Result<void>::success();
20}
21Result<void> VolumeFluidDiffuse::advance(const VolumeFluid& fluid, float seconds, unsigned minimumNeighbors) {
22 if (!std::isfinite(seconds) || seconds <= 0.f || seconds > 1.f / 30.f || minimumNeighbors > 1000000)
23 return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, "Invalid diffuse timestep or neighbor threshold", "fluids.volume.diffuse"));
24 candidateScratch_.clear();
25 positionScratch_.clear();
26 candidateScratch_.reserve(particles_.size());
27 positionScratch_.reserve(particles_.size());
28 for (auto particle : particles_) {
29 particle.life -= seconds;
30 if (particle.life <= 0.f) continue;
31 candidateScratch_.push_back(particle);
32 positionScratch_.push_back(particle.position);
33 }
34 if (candidateScratch_.empty()) {
35 particles_.clear();
36 return Result<void>::success();
37 }
38 auto sampled = fluid.sampleFieldInto(positionScratch_, sampleScratch_);
39 if (!sampled) return Result<void>::failure(sampled.status());
40 size_t remaining = 0;
41 for (size_t i = 0; i < candidateScratch_.size(); ++i) {
42 const auto& sample = sampleScratch_[i];
43 if (sample.neighborCount < minimumNeighbors) continue;
44 auto particle = candidateScratch_[i];
45 particle.velocity = sample.velocity;
46 particle.position += particle.velocity * seconds;
47 if (!valid(particle)) return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, "Invalid diffuse advection result", "fluids.volume.diffuse"));
48 candidateScratch_[remaining++] = particle;
49 }
50 candidateScratch_.resize(remaining);
51 particles_.swap(candidateScratch_);
52 return Result<void>::success();
53}
55 return {"eve.volume-fluid-diffuse", 1, capacity_, particles_};
56}
58 if (snapshot.schema != "eve.volume-fluid-diffuse" || snapshot.version != 1 || snapshot.capacity == 0 ||
60 return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, "Invalid diffuse snapshot", "fluids.volume.diffuse"));
61 for (const auto& p : snapshot.particles)
62 if (!valid(p)) return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, "Invalid diffuse snapshot particle", "fluids.volume.diffuse"));
63 auto candidate = snapshot.particles;
64 particles_.swap(candidate);
65 capacity_ = snapshot.capacity;
66 return Result<void>::success();
67}
68unsigned VolumeFluidDiffuse::particleCount() const { return unsigned(particles_.size()); }
69unsigned VolumeFluidDiffuse::availableCapacity() const { return capacity_ - particleCount(); }
70void VolumeFluidDiffuse::copyRenderData(std::vector<glm::vec4>& positionLife) const {
71 positionLife.resize(particles_.size());
72 for (size_t i = 0; i < particles_.size(); ++i)
73 positionLife[i] = glm::vec4(particles_[i].position, particles_[i].life);
74}
75void VolumeFluidDiffuse::clear() { particles_.clear(); }
76} // namespace eve::fluids
glm::vec4 p[6]
std::array< float, 3 > position
bool valid
bool finite
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
Result< void > advance(const VolumeFluid &fluid, float seconds, unsigned minimumNeighbors=4)
Advances once using current liquid/gas velocity, after the caller steps the fluid.
unsigned particleCount() const
Returns live count without copying particle data.
Result< void > emit(std::span< const VolumeFluidDiffuseParticle > particles)
Admits an entire batch or fails without mutation; finite speed must be <=100 m/s.
void clear()
Removes all particles, preserving configured capacity.
Result< void > restore(const VolumeFluidDiffuseSnapshot &snapshot)
Validates schema, capacity [1,65536] and all particles before replacing state.
unsigned availableCapacity() const
Returns remaining admission capacity without allocating.
VolumeFluidDiffuseSnapshot snapshot() const
Returns an owning snapshot; later mutation cannot change its values.
void copyRenderData(std::vector< glm::vec4 > &positionLife) const
Reuses caller storage to copy XY Z position and remaining life for rendering.
CPU position-based free-volume fluid with a bounded spatial grid. @ownership Owns all particle state;...
GLSL compute kernels for the GPU surface-flow solver.
Definition FluidTarget.h:12
Strict version-1 diffuse pool state; unknown fields and versions are rejected.
std::vector< VolumeFluidDiffuseParticle > particles