载入中...
搜索中...
未找到
VolumeFluidFoamSurface.cpp
浏览该文件的文档.
1#include <algorithm>
2#include <cmath>
3#include <glm/gtc/matrix_transform.hpp>
6
7namespace eve::fluids {
9 if (downsample < 1 || downsample > 4)
11 DiagnosticCode::InvalidArgument, "Foam downsample must be in [1,4]", "fluids.surface.configureFoam"));
12 foamEnabled_ = enabled;
13 foamDownsample_ = downsample;
14 return Result<void>::success();
15}
16
18 float fadeSeconds) {
19 const auto fail = [](const char* message) {
22 };
23 if (!std::isfinite(radius) || radius <= 0.f || radius > 1.f || !std::isfinite(opacity) || opacity < 0.f ||
24 opacity > 1.f || !std::isfinite(fadeSeconds) || fadeSeconds <= 0.f || fadeSeconds > 86400.f)
25 return fail("Invalid diffuse rendering settings");
26 if (!foamEnabled_ || pool.particleCount() == 0 || opacity == 0.f) return Result<void>::success();
27 const int width = params_.width, height = params_.height;
28 if (width <= 0 || height <= 0 || depth_.size() != size_t(width) * size_t(height) ||
29 color_.size() != depth_.size() * 4)
30 return fail("Invalid reconstructed frame size");
31 const int renderWidth = std::max(1, (width + foamDownsample_ - 1) / foamDownsample_);
32 const int renderHeight = std::max(1, (height + foamDownsample_ - 1) / foamDownsample_);
33 const float tangent = std::tan(glm::radians(params_.fovYDeg) * .5f);
34 if (!std::isfinite(tangent) || tangent <= 0.f) return fail("Invalid diffuse camera projection");
35 const auto view = glm::lookAtRH(params_.eye, params_.target, params_.up);
36 pool.copyRenderData(diffuseParticles_);
37 diffuseSplats_.clear();
38 diffuseSplats_.reserve(diffuseParticles_.size());
39 uint64_t visits = 0;
40 for (const auto p : diffuseParticles_) {
41 const auto v = view * glm::vec4(glm::vec3(p), 1.f);
42 if (!std::isfinite(v.x) || !std::isfinite(v.y) || !std::isfinite(v.z))
43 return fail("Invalid diffuse camera transform");
44 DiffuseSplat s;
45 s.z = -v.z;
46 if (s.z <= params_.nearZ || s.z >= params_.farZ) continue;
47 s.r = std::max(1.f, radius * float(renderHeight) / (2.f * s.z * tangent));
48 s.x = (.5f + .5f * v.x / (s.z * tangent * float(renderWidth) / float(renderHeight))) * float(renderWidth);
49 s.y = (.5f - .5f * v.y / (s.z * tangent)) * float(renderHeight);
50 if (!std::isfinite(s.r) || !std::isfinite(s.x) || !std::isfinite(s.y))
51 return fail("Invalid diffuse projection");
52 if (s.x + s.r < 0.f || s.y + s.r < 0.f || s.x - s.r >= float(renderWidth) || s.y - s.r >= float(renderHeight))
53 continue;
54 // Clamp in floating point before converting extreme off-screen coordinates.
55 s.x0 = int(std::floor(std::clamp(s.x - s.r, 0.f, float(renderWidth - 1))));
56 s.x1 = int(std::ceil(std::clamp(s.x + s.r, 0.f, float(renderWidth - 1))));
57 s.y0 = int(std::floor(std::clamp(s.y - s.r, 0.f, float(renderHeight - 1))));
58 s.y1 = int(std::ceil(std::clamp(s.y + s.r, 0.f, float(renderHeight - 1))));
59 s.alpha = opacity * std::min(1.f, p.w / fadeSeconds);
60 visits += uint64_t(s.x1 - s.x0 + 1) * uint64_t(s.y1 - s.y0 + 1);
61 if (visits > 4000000) return fail("Diffuse rendering exceeds 4M pixel visits");
62 diffuseSplats_.push_back(s);
63 }
64 if (foamDownsample_ > 1) foamCoverageScratch_.assign(size_t(renderWidth) * size_t(renderHeight), 0.f);
65 for (const auto& s : diffuseSplats_) {
66 for (int y = s.y0; y <= s.y1; ++y)
67 for (int x = s.x0; x <= s.x1; ++x) {
68 const float dx = (float(x) + .5f - s.x) / s.r, dy = (float(y) + .5f - s.y) / s.r;
69 const float q = 1.f - dx * dx - dy * dy;
70 if (q <= 0.f) continue;
71 const size_t reducedAt = size_t(y) * size_t(renderWidth) + size_t(x);
72 const int fullX = std::min(width - 1, x * width / renderWidth);
73 const int fullY = std::min(height - 1, y * height / renderHeight);
74 const size_t at = size_t(fullY) * size_t(width) + size_t(fullX);
75 const float front = s.z - radius * std::sqrt(q);
76 const float visibility = std::clamp(1.f + (depth_[at] - front) / radius, 0.f, 1.f);
77 const float alpha = s.alpha * q * q * visibility;
78 if (alpha <= 0.f) continue;
79 if (foamDownsample_ > 1) {
80 foamCoverageScratch_[reducedAt] = alpha + foamCoverageScratch_[reducedAt] * (1.f - alpha);
81 continue;
82 }
83 const float oldAlpha = float(color_[at * 4 + 3]) / 255.f;
84 const float retained = oldAlpha * (1.f - alpha), combined = alpha + retained;
85 for (size_t c = 0; c < 3; ++c) {
86 const float color = (alpha + float(color_[at * 4 + c]) / 255.f * retained) / combined;
87 color_[at * 4 + c] = uint8_t(std::clamp(color, 0.f, 1.f) * 255.f + .5f);
88 }
89 color_[at * 4 + 3] = uint8_t(std::clamp(combined, 0.f, 1.f) * 255.f + .5f);
90 }
91 }
92 if (foamDownsample_ > 1) {
93 for (int y = 0; y < height; ++y)
94 for (int x = 0; x < width; ++x) {
95 const int sx = std::min(renderWidth - 1, x * renderWidth / width);
96 const int sy = std::min(renderHeight - 1, y * renderHeight / height);
97 const float alpha = foamCoverageScratch_[size_t(sy) * size_t(renderWidth) + size_t(sx)];
98 if (alpha <= 0.f) continue;
99 const size_t at = size_t(y) * size_t(width) + size_t(x);
100 const float oldAlpha = float(color_[at * 4u + 3u]) / 255.f;
101 const float retained = oldAlpha * (1.f - alpha), combined = alpha + retained;
102 for (size_t c = 0; c < 3; ++c) {
103 const float value = (alpha + float(color_[at * 4u + c]) / 255.f * retained) / combined;
104 color_[at * 4u + c] = uint8_t(std::clamp(value, 0.f, 1.f) * 255.f + .5f);
105 }
106 color_[at * 4u + 3u] = uint8_t(std::clamp(combined, 0.f, 1.f) * 255.f + .5f);
107 }
108 }
109 residentColorCurrent_ = false;
110 return Result<void>::success();
111}
112} // namespace eve::fluids
double value
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
const std::string & s
Vec3 tangent
Definition CaveMesh.cpp:80
glm::vec4 p[6]
std::string message
std::array< double, 10 > q
float v
std::int32_t c
std::uint32_t height
std::uint32_t width
float radius
glm::mat4 view
float dy
float dx
float opacity
std::size_t at
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 > configureFoam(bool enabled, int downsample=1)
Configures Fluid3D-compatible foam generation visibility and render-target downsampling.
const std::vector< uint8_t > & color() const
RGBA8 shaded output.
Result< void > compositeDiffuse(const VolumeFluidDiffuse &pool, float radius, float opacity, float fadeSeconds)
Composites white secondary particles over the last reconstructed frame.
Bounded, one-way fluid-advected secondary particle pool. @ownership Owns particles and capacity; no f...
unsigned particleCount() const
Returns live count without copying particle data.
void copyRenderData(std::vector< glm::vec4 > &positionLife) const
Reuses caller storage to copy XY Z position and remaining life for rendering.
GLSL compute kernels for the GPU surface-flow solver.
Definition FluidTarget.h:12
bool enabled