载入中...
搜索中...
未找到
EditorSurfaceFluidPreview.cpp
浏览该文件的文档.
2
7
8#include <algorithm>
9#include <cmath>
10
11namespace eve::editor {
12namespace {
13void error(SurfaceFluidPreviewSnapshot& result, const char* rule, std::string message) {
14 result.diagnostics.push_back(eve::editing::ruleDiagnostic(
15 DiagnosticCode::PreconditionViolation, RuleId(rule), DiagnosticSeverity::Error,
16 std::move(message)));
17 result.status = EditorStatus::Rejected;
18}
19bool finite(const std::array<double, 3>& value) {
20 return std::all_of(value.begin(), value.end(), [](double component) { return std::isfinite(component); });
21}
22std::array<double, 3> values(const glm::vec3& value) { return {value.x, value.y, value.z}; }
23} // namespace
24
28 result.documentRevision = target.revision();
29 if (request.documentRevision != target.revision()) {
30 error(result, "editor.surface-fluid.preview-stale", "Surface fluid preview request is stale");
31 result.status = EditorStatus::Conflict;
32 return result;
33 }
34 if (!std::isfinite(request.seconds) || !std::isfinite(request.fixedStep) || request.seconds < 0.0 ||
35 request.seconds > 600.0 || request.fixedStep <= 0.0 || request.positions.empty() ||
36 request.positions.size() > request.maximumVertices || request.indices.empty() ||
37 request.indices.size() % 3 != 0 || (!request.uvs.empty() && request.uvs.size() != request.positions.size()) ||
38 request.seeds.size() > request.maximumDroplets || request.maximumSteps == 0 ||
39 request.seconds / request.fixedStep > static_cast<double>(request.maximumSteps)) {
40 error(result, "editor.surface-fluid.preview-request", "Surface fluid preview request or budget is invalid");
41 return result;
42 }
43
44 std::vector<glm::vec3> positions;
45 positions.reserve(request.positions.size());
46 for (const auto& position : request.positions) {
47 if (!finite(position)) {
48 error(result, "editor.surface-fluid.preview-position", "Surface positions must be finite");
49 return result;
50 }
51 positions.emplace_back(position[0], position[1], position[2]);
52 }
53 for (std::uint32_t index : request.indices)
54 if (index >= positions.size()) {
55 error(result, "editor.surface-fluid.preview-index", "Surface index is out of range");
56 return result;
57 }
58
59 std::vector<glm::vec2> uvs;
60 uvs.reserve(request.uvs.size());
61 for (const auto& uv : request.uvs) {
62 if (!std::isfinite(uv[0]) || !std::isfinite(uv[1])) {
63 error(result, "editor.surface-fluid.preview-uv", "Surface UVs must be finite");
64 return result;
65 }
66 uvs.emplace_back(uv[0], uv[1]);
67 }
69 if (!binding.build(positions, request.indices, uvs)) {
70 error(result, "editor.surface-fluid.preview-topology", "Surface topology is invalid");
71 return result;
72 }
74 if (!wetness.build(binding)) {
75 error(result, "editor.surface-fluid.preview-wetness", "Could not initialize surface wetness");
76 return result;
77 }
80 fluids::SurfaceWetnessParams wetnessParams;
81 auto applied = SurfaceFluidRuntimeApplier().apply(target, &simulation, &renderParams, &wetnessParams);
82 if (!applied.ok()) {
83 result.status = applied.code();
84 result.diagnostics = applied.diagnostics();
85 return result;
86 }
87 for (const auto& seed : request.seeds) {
88 if (!finite(seed.barycentric) || !finite(seed.velocity) || !std::isfinite(seed.volume) || seed.volume <= 0.0 ||
89 seed.triangle >= static_cast<std::uint32_t>(binding.triangleCount()) ||
90 std::any_of(seed.barycentric.begin(), seed.barycentric.end(), [](double v) { return v < 0.0; }) ||
91 std::abs(seed.barycentric[0] + seed.barycentric[1] + seed.barycentric[2] - 1.0) > 1e-5) {
92 error(result, "editor.surface-fluid.preview-seed", "Surface droplet seed is invalid");
93 return result;
94 }
95 if (!simulation.addDroplet({seed.triangle, {seed.barycentric[0], seed.barycentric[1], seed.barycentric[2]}},
96 static_cast<float>(seed.volume),
97 {seed.velocity[0], seed.velocity[1], seed.velocity[2]})) {
98 error(result, "editor.surface-fluid.preview-seed-add", "Surface droplet seed could not be added");
99 return result;
100 }
101 }
102 const std::size_t fullSteps = static_cast<std::size_t>(std::floor(request.seconds / request.fixedStep));
103 const double remainder = request.seconds - static_cast<double>(fullSteps) * request.fixedStep;
104 for (std::size_t step = 0; step < fullSteps + (remainder > 1e-12 ? 1u : 0u); ++step) {
105 const float dt = static_cast<float>(step < fullSteps ? request.fixedStep : remainder);
106 simulation.step(dt);
107 wetness.step(dt, wetnessParams);
108 if (simulation.droplets().size() + simulation.airborneDroplets().size() > request.maximumDroplets) {
109 error(result, "editor.surface-fluid.preview-droplet-budget",
110 "Surface fluid preview exceeds its droplet budget");
111 return result;
112 }
113 }
114 fluids::SurfaceFluidRenderData renderData;
115 renderData.update(binding, simulation, &wetness, renderParams);
116 result.droplets.reserve(renderData.droplets().size());
117 for (const auto& droplet : renderData.droplets())
118 result.droplets.push_back({droplet.id, values(droplet.position), values(droplet.normal),
119 values(droplet.majorAxis), values(droplet.minorAxis), droplet.capHeight,
120 droplet.wetness});
121 result.vertexWetness.reserve(wetness.values().size());
122 for (float value : wetness.values()) result.vertexWetness.push_back(value);
123 result.simulatedSeconds = request.seconds;
124 result.status = EditorStatus::Applied;
125 return result;
126}
127
128} // namespace eve::editor
LogicalId target
double value
float uv
float wetness
std::map< std::string, Var > values
std::string message
const GltfImportRequest & request
float u
Definition Grass.cpp:233
std::vector< float > positions
float v
std::array< float, 3 > position
bool finite
std::string error
Definition Package.cpp:60
eve::action::ActionVfxBinding binding
std::uint32_t seed
Definition PointSet.cpp:807
float step
Definition TreeMesh.cpp:314
uint32_t index
SurfaceFluidPreviewSnapshot build(const SurfaceFluidTarget &target, const SurfaceFluidPreviewRequest &request) const
Validate, replay and capture a renderer-neutral surface-fluid frame.
Dynamic triangle surface used to bind films and droplets to deforming meshes.
CPU reference solver for droplets moving over static, rigid or deforming surfaces.
Lightweight material-space wet-film field stored at mesh vertices.
Optional bridge copying a validated document into live fluid components.
Result< void > apply(const SurfaceFluidTarget &target, fluids::SurfaceDropletSimulation *simulation, fluids::SurfaceFluidRenderParams *render, fluids::SurfaceWetnessParams *wetness) const
Apply droplet parameters and emit matching render/wetness parameters atomically.
Reversible document for surface droplets, wet traces and material response.
Diagnostic ruleDiagnostic(eve::DiagnosticCode code, RuleId rule, DiagnosticSeverity severity, std::string message)
Build a common diagnostic carrying an open editing rule identity.
eve::editing::RuleId RuleId
Definition EditorIds.h:32
Complete deterministic input needed to replay a surface-fluid scrub.
Revision-bound result containing droplet geometry and per-vertex wetness.
Tuning for converting simulated droplets into render instances.
Parameters controlling persistent wet-film traces on a triangle surface.