载入中...
搜索中...
未找到
TrailEffect.cpp
浏览该文件的文档.
2
3#include "common/Exception.h"
4
5#include <glm/geometric.hpp>
6
7#include <algorithm>
8#include <cmath>
9
10namespace eve::stylize {
11namespace {
12bool finite(glm::vec3 value) {
13 return std::isfinite(value.x) && std::isfinite(value.y) && std::isfinite(value.z);
14}
15float endpointDistance(const TrailSample& sample, glm::vec3 root, glm::vec3 tip) {
16 return std::max(glm::length(root - sample.root), glm::length(tip - sample.tip));
17}
18} // namespace
19
20TrailEmitter::TrailEmitter(TrailSettings settings) : settings_(settings) { validateSettings(settings_); }
21
22void TrailEmitter::validateSettings(const TrailSettings& settings) {
23 if (settings.maxSamples < 2) throw eve::Exception("TrailEmitter: maxSamples must be at least two");
24 if (!std::isfinite(settings.lifetime) || settings.lifetime <= 0.f)
25 throw eve::Exception("TrailEmitter: lifetime must be finite and positive");
26 if (!std::isfinite(settings.minSampleDistance) || settings.minSampleDistance < 0.f)
27 throw eve::Exception("TrailEmitter: minSampleDistance must be finite and non-negative");
28 if (!std::isfinite(settings.teleportDistance) || settings.teleportDistance <= 0.f)
29 throw eve::Exception("TrailEmitter: teleportDistance must be finite and positive");
31 throw eve::Exception("TrailEmitter: teleportDistance must not be smaller than minSampleDistance");
32}
33
35 validateSettings(settings);
36 settings_ = settings;
37 while (samples_.size() > settings_.maxSamples) samples_.pop_front();
38}
39
40void TrailEmitter::update(float dtSeconds) {
41 if (!std::isfinite(dtSeconds) || dtSeconds < 0.f)
42 throw eve::Exception("TrailEmitter.update: dt must be finite and non-negative");
43 for (TrailSample& sample : samples_) sample.age += dtSeconds;
44 while (!samples_.empty() && samples_.front().age >= settings_.lifetime) samples_.pop_front();
45}
46
48 if (!finite(root) || !finite(tip)) throw eve::Exception("TrailEmitter.append: endpoints must be finite");
50 if (!samples_.empty() && !forceBreak_) {
51 const float distance = endpointDistance(samples_.back(), root, tip);
53 if (distance > settings_.teleportDistance) {
54 ++segment_;
56 }
57 } else {
58 if (!samples_.empty()) ++segment_;
60 }
61 samples_.push_back({root, tip, 0.f, segment_});
62 forceBreak_ = false;
63 while (samples_.size() > settings_.maxSamples) samples_.pop_front();
64 return result;
65}
66
67void TrailEmitter::breakTrail() noexcept { forceBreak_ = true; }
68
69void TrailEmitter::clear() noexcept {
70 samples_.clear();
71 segment_ = 0;
72 forceBreak_ = true;
73}
74
77 mesh.vertices.reserve(samples_.size() * 2);
78 if (samples_.size() < 2) return mesh;
79 std::size_t segmentStart = 0;
80 while (segmentStart < samples_.size()) {
81 std::size_t segmentEnd = segmentStart + 1;
82 while (segmentEnd < samples_.size() && samples_[segmentEnd].segment == samples_[segmentStart].segment)
83 ++segmentEnd;
84 const std::size_t segmentSize = segmentEnd - segmentStart;
85 for (std::size_t i = segmentStart; i < segmentEnd; ++i) {
86 const float u = segmentSize > 1 ? float(i - segmentStart) / float(segmentSize - 1) : 0.f;
87 const float alpha = std::clamp(1.f - samples_[i].age / settings_.lifetime, 0.f, 1.f);
88 mesh.vertices.push_back({samples_[i].root, {u, 0.f}, alpha});
89 mesh.vertices.push_back({samples_[i].tip, {u, 1.f}, alpha});
90 if (i > segmentStart) {
91 const std::uint32_t previous = static_cast<std::uint32_t>(mesh.vertices.size() - 4);
92 const std::uint32_t current = static_cast<std::uint32_t>(mesh.vertices.size() - 2);
93 mesh.indices.insert(mesh.indices.end(), {previous, previous + 1, current + 1,
94 previous, current + 1, current});
95 }
96 }
97 segmentStart = segmentEnd;
98 }
99 return mesh;
100}
101
102} // namespace eve::stylize
double value
int tip
Definition AnimSmr.cpp:121
int root
Definition AnimSmr.cpp:119
float u
Definition Grass.cpp:233
float distance
graphics::Canvas * previous
bool finite
Mesh * mesh
double current
TerrainThermalSettings settings
EVENGINE_API_FOUNDATION public API.
Definition Exception.h:13
TrailSettings settings() const noexcept
Return a value snapshot of current settings.
Definition TrailEffect.h:65
TrailAppendResult append(glm::vec3 root, glm::vec3 tip)
Append a weapon edge sample or report why it was not appended.
void clear() noexcept
Remove all samples and reset segment numbering.
void update(float dtSeconds)
Age samples and remove expired entries using injected dt.
TrailEmitter(TrailSettings settings={})
Construct an empty emitter with validated settings.
void breakTrail() noexcept
Start a disconnected segment at the next appended sample.
TrailMeshSnapshot buildMesh() const
Build an owning triangle-list snapshot from current samples.
void setSettings(TrailSettings settings)
Replace settings and enforce the new sample budget.
double sample(const Heightmap &map, double u, double v)
Sample.
TrailAppendResult
Result of attempting to append one weapon-edge sample.
Definition TrailEffect.h:24
Owning CPU snapshot suitable for upload by a graphics adapter.
Definition TrailEffect.h:42
std::vector< TrailVertex > vertices
Definition TrailEffect.h:43
One retained pair of weapon root/tip positions.
Definition TrailEffect.h:27
Sampling and retention policy for a weapon ribbon trail.
Definition TrailEffect.h:16