Unravel Engine C++ Reference
Loading...
Searching...
No Matches
particle_emitter_component.cpp
Go to the documentation of this file.
2#include "math/transform.hpp"
5#include <graphics/graphics.h>
6#include <logging/logging.h>
7
8namespace math
9{
10template<>
11auto gradient_lerp(const frange_t& start, const frange_t& end, float progress) -> frange_t
12{
13 return frange_t(gradient_lerp(start.min, end.min, progress), gradient_lerp(start.max, end.max, progress));
14}
15}
16
17namespace unravel
18{
19
20void particle_emitter_component::on_create_component(entt::registry& r, entt::entity e)
21{
22 entt::handle entity(r, e);
23 auto& component = entity.get<particle_emitter_component>();
24 component.set_owner(entity);
25 component.desc_.reset();
26 component.recreate_emitter();
27}
28
29void particle_emitter_component::on_destroy_component(entt::registry& r, entt::entity e)
30{
31 entt::handle entity(r, e);
33 {
34 auto& component = entity.get<particle_emitter_component>();
35 if(ps_soa::is_valid(component.emitter_handle_))
36 {
37 ps_soa::destroy_emitter(component.emitter_handle_);
38 component.emitter_handle_ = {};
39 }
40 }
41}
42
47
49{
50 return enabled_;
51}
52
53auto particle_emitter_component::get_emitter_handle() const -> ps_soa::emitter_handle
54{
55 return emitter_handle_;
56}
57
59{
60 if(shape_ != shape)
61 {
62 shape_ = shape;
64 }
65}
66
67auto particle_emitter_component::get_shape() const -> ps_soa::emitter_shape
68{
69 return shape_;
70}
71
73{
74 if(direction_ != direction)
75 {
76 direction_ = direction;
78 }
79}
80
81auto particle_emitter_component::get_direction() const -> ps_soa::emitter_direction
82{
83 return direction_;
84}
85
90
91auto particle_emitter_component::get_spawn_location() const -> ps_soa::spawn_location
92{
93 return desc_.emission.spawn_location;
94}
95
97{
98 if(max_particles_ != max_particles)
99 {
100 max_particles_ = max_particles;
102 }
103}
104
106{
107 return max_particles_;
108}
109
110void particle_emitter_component::set_emission_lifetime(std::chrono::duration<float> lifetime)
111{
112 desc_.emission.emission_lifetime = lifetime.count();
113}
114
115auto particle_emitter_component::get_emission_lifetime() const -> std::chrono::duration<float>
116{
117 return std::chrono::duration<float>(desc_.emission.emission_lifetime);
118}
119
124
126{
127 return desc_.motion.gravity_scale;
128}
129
131{
132 desc_.emission.particles_per_second = math::max(emission_rate, 0.0f);
134}
135
137{
138 return desc_.emission.particles_per_second;
139}
140
142{
143 desc_.motion.temporal_motion = math::clamp(temporal_motion, 0.0f, 1.0f);
144}
145
147{
148 return desc_.motion.temporal_motion;
149}
150
152{
153 desc_.motion.velocity_damping = math::clamp(velocity_damping, 0.0f, 1.0f);
154}
155
157{
158 return desc_.motion.velocity_damping;
159}
160
165
170
175
180
185
187{
188 return desc_.emission.shape_scale;
189}
190
192{
193 desc_.appearance.size_by_speed_range = size_range;
194}
195
200
205
210
216
221
226
231
236
241
246
251
252void particle_emitter_component::set_lifetime(std::chrono::duration<float> lifetime)
253{
254 desc_.motion.lifetime = math::max(lifetime.count(), 0.0f);
256}
257
258auto particle_emitter_component::get_lifetime() const -> std::chrono::duration<float>
259{
260 return std::chrono::duration<float>(desc_.motion.lifetime);
261}
262
264{
265 desc_.motion.velocity_gradient = gradient;
266 desc_.motion.velocity_gradient.generate_lut(256);
267}
268
270{
271 return desc_.motion.velocity_gradient;
272}
273
275{
276 desc_.appearance.scale_gradient = gradient;
277 desc_.appearance.scale_gradient.generate_lut(256);
278}
279
281{
282 return desc_.appearance.scale_gradient;
283}
284
289
294
296{
297 desc_.appearance.opacity = math::clamp(opacity, 0.0f, 1.0f);
298}
299
301{
302 return desc_.appearance.opacity;
303}
304
306{
307 desc_.appearance.color_intensity = math::max(intensity, 0.0f);
308}
309
311{
312 return desc_.appearance.color_intensity;
313}
314
316{
317 desc_.playback.playing = true;
318 desc_.playback.paused = false;
319}
320
322{
323 desc_.playback.playing = false;
324 desc_.playback.paused = false;
325}
326
328{
329 desc_.playback.playing = false;
330 desc_.playback.paused = false;
332}
333
335{
336 if(desc_.playback.playing)
337 {
338 desc_.playback.paused = true;
339 }
340}
341
343{
344 if(desc_.playback.playing)
345 {
346 desc_.playback.paused = false;
347 }
348}
349
351{
352 auto owner = get_owner();
353 if(owner.valid())
354 {
356 [](particle_emitter_component& emitter)
357 {
358 emitter.play();
359 });
360 }
361}
362
364{
365 auto owner = get_owner();
366 if(owner.valid())
367 {
369 [](particle_emitter_component& emitter)
370 {
371 emitter.stop();
372 });
373 }
374}
375
388
390{
391 auto owner = get_owner();
392 if(owner.valid())
393 {
395 [](particle_emitter_component& emitter)
396 {
397 emitter.pause();
398 });
399 }
400}
401
403{
404 auto owner = get_owner();
405 if(owner.valid())
406 {
408 [](particle_emitter_component& emitter)
409 {
410 emitter.resume();
411 });
412 }
413}
414
416{
417 return desc_.playback.playing;
418}
419
421{
422 return desc_.playback.paused;
423}
424
426{
427 return !desc_.playback.playing && !desc_.playback.paused;
428}
429
431{
432 desc_.emission.loop = loop;
433}
434
436{
437 return desc_.emission.loop;
438}
439
440void particle_emitter_component::set_start_delay(std::chrono::duration<float> delay)
441{
442 desc_.emission.start_delay = math::max(0.0f, delay.count());
444}
445
446auto particle_emitter_component::get_start_delay() const -> std::chrono::duration<float>
447{
448 return std::chrono::duration<float>(desc_.emission.start_delay);
449}
450
455
457{
458 return desc_.render.align_to_direction;
459}
460
461void particle_emitter_component::set_pivot(const math::vec2& pivot)
462{
463 desc_.render.pivot = pivot;
464}
465
467{
468 return desc_.render.pivot;
469}
470
476
478{
479 return desc_.appearance.color_gradient;
480}
481
483{
484 desc_.motion.position_easing = easing;
485}
486
488{
489 return desc_.motion.position_easing;
490}
491
493{
494 return ps_soa::get_num_particles(emitter_handle_);
495}
496
498{
499 math::bbox bounds(math::vec3(-1.0f), math::vec3(1.0f));
500 ps_soa::get_aabb(emitter_handle_, bounds);
501 return bounds;
502}
503
505{
506 auto bounds = get_world_bounds();
507 if(!ps_soa::has_updated(emitter_handle_))
508 {
509 bounds.mul(world_transform);
510 }
511 return bounds;
512}
513
515{
516 texture_ = texture;
517}
518
520{
521 if(texture_.is_valid())
522 {
523 return texture_;
524 }
526}
527
532
533auto particle_emitter_component::get_texture_mode() const -> ps_soa::texture_mode
534{
535 return desc_.render.texture_mode;
536}
537
542
543auto particle_emitter_component::get_render_mode() const -> ps_soa::render_mode
544{
545 return desc_.render.render_mode;
546}
547
552
553auto particle_emitter_component::get_blend_mode() const -> ps_soa::blend_mode
554{
555 return desc_.render.blend_mode;
556}
557
559{
560 desc_.render.tex_sheet_tiles = math::vec2(math::max(tiles.x, 1.0f), math::max(tiles.y, 1.0f));
561}
562
564{
565 return desc_.render.tex_sheet_tiles;
566}
567
569{
570 desc_.render.tex_sheet_cycles = math::max(cycles, 0.0f);
571}
572
574{
575 return desc_.render.tex_sheet_cycles;
576}
577
579{
580 desc_.render.tex_sheet_randomize = randomize;
581}
582
587
589{
590 culling_mode_ = mode;
591}
592
594{
595 return culling_mode_;
596}
597
599{
600 last_render_frame_ = frame;
601}
602
604{
605 return last_render_frame_;
606}
607
609{
610 return last_render_frame_ == 0;
611}
612
614{
615 const auto current_frame = uint64_t(gfx::get_render_frame());
616 const bool is_new = is_newly_created();
617 const bool was_used_recently = current_frame - last_render_frame_ <= 1;
618 return is_new || was_used_recently;
619}
620
622{
623 if(!ps_soa::is_valid(emitter_handle_) || !enabled_)
624 {
625 return;
626 }
627 transform_state_.current = world_transform;
628 bool should_simulate = true;
629 if(culling_mode_ == culling_mode::renderer_based && !was_used_last_frame())
630 {
631 should_simulate = false;
632 }
633 if(should_simulate)
634 {
635 ps_soa::update_emitter(emitter_handle_, dt.count(), desc_, transform_state_, desc_.playback);
636 }
637 else
638 {
639 ps_soa::update_emitter_bounds_only(emitter_handle_, desc_, transform_state_);
640 }
641}
642
643auto particle_emitter_component::get_desc() const -> const ps_soa::emitter_desc&
644{
645 return desc_;
646}
647
649{
650 if(ps_soa::is_valid(emitter_handle_))
651 {
652 ps_soa::destroy_emitter(emitter_handle_);
653 emitter_handle_ = {};
654 }
655 emitter_handle_ = ps_soa::create_emitter(shape_, direction_, max_particles_);
656 if(!ps_soa::is_valid(emitter_handle_))
657 {
658 APPLOG_ERROR("Failed to create particle emitter");
659 return;
660 }
661 ps_soa::set_emitter_sim_backend(emitter_handle_, simulation_backend_);
662}
663
665{
666 if(ps_soa::is_valid(emitter_handle_))
667 {
668 ps_soa::reset_emitter(emitter_handle_);
669 }
670}
671
677
678auto particle_emitter_component::get_simulation_space() const -> ps_soa::simulation_space
679{
680 return desc_.motion.space;
681}
682
684{
685 simulation_backend_ = backend;
686 if(ps_soa::is_valid(emitter_handle_))
687 {
688 ps_soa::set_emitter_sim_backend(emitter_handle_, simulation_backend_);
689 }
690}
691
692auto particle_emitter_component::get_simulation_backend() const -> ps_soa::particle_sim_backend
693{
694 return simulation_backend_;
695}
696
697} // namespace unravel
void generate_lut(size_t lut_size=256)
Definition gradient.hpp:222
General purpose transformation class designed to maintain each component of the transformation separa...
Definition transform.hpp:27
static auto default_color_map() -> asset_handle< gfx::texture > &
Gets the default color map.
Definition material.cpp:26
auto get_owner() const noexcept -> entt::const_handle
Gets the owner of the component.
void set_owner(entt::handle owner)
Sets the owner of the component.
Component that wraps the soa particle system emitter.
auto get_texture() const -> const asset_handle< gfx::texture > &
auto get_desc() const -> const ps_soa::emitter_desc &
auto get_size_by_speed_range() const -> const frange_t &
void set_size_by_speed_range(const frange_t &size_range)
void set_color_by_speed_velocity_range(const frange_t &velocity_range)
auto get_color_by_speed_velocity_range() const -> const frange_t &
void set_texture(const asset_handle< gfx::texture > &texture)
void set_start_delay(std::chrono::duration< float > delay)
static void on_destroy_component(entt::registry &r, entt::entity e)
auto get_shape() const -> ps_soa::emitter_shape
auto get_emitter_handle() const -> ps_soa::emitter_handle
void set_spawn_location(ps_soa::spawn_location spawn_location)
auto get_render_mode() const -> ps_soa::render_mode
auto get_blend_mode() const -> ps_soa::blend_mode
auto get_start_delay() const -> std::chrono::duration< float >
void set_lifetime(std::chrono::duration< float > lifetime)
void update_emitter(const math::transform &world_transform, delta_t dt)
void set_simulation_space(ps_soa::simulation_space space)
void set_color_by_speed_gradient(const math::gradient< math::color > &gradient)
auto get_lifetime_by_emitter_speed_gradient() const -> const math::gradient< float > &
void set_size_by_speed_velocity_range(const frange_t &velocity_range)
void set_initial_scale_3d(const math::vec3 &scale)
auto get_texture_mode() const -> ps_soa::texture_mode
auto was_used_last_frame() const noexcept -> bool
void set_simulation_backend(ps_soa::particle_sim_backend backend)
CPU vs GPU particle pack/sim path for this emitter (artist-selectable).
void set_position_easing(bx::Easing::Enum easing)
auto get_scale_gradient() const -> const math::gradient< frange_t > &
void set_velocity_gradient(const math::gradient< frange_t > &gradient)
void set_force_over_lifetime(const math::vec3 &force)
void set_emission_shape_scale(const math::vec3 &scale)
void set_color_gradient(const math::gradient< math::color > &gradient)
void set_texture_mode(ps_soa::texture_mode mode)
auto get_color_by_speed_gradient() const -> const math::gradient< math::color > &
auto get_velocity_gradient() const -> const math::gradient< frange_t > &
auto get_lifetime() const -> std::chrono::duration< float >
auto get_updated_world_bounds(const math::transform &world_transform) const -> math::bbox
auto get_direction() const -> ps_soa::emitter_direction
void set_lifetime_by_emitter_speed_gradient(const math::gradient< float > &gradient)
void set_emission_lifetime(std::chrono::duration< float > lifetime)
auto get_simulation_space() const -> ps_soa::simulation_space
void set_shape(ps_soa::emitter_shape shape)
auto get_color_gradient() const -> const math::gradient< math::color > &
auto get_simulation_backend() const -> ps_soa::particle_sim_backend
auto get_size_by_speed_velocity_range() const -> const frange_t &
auto get_spawn_location() const -> ps_soa::spawn_location
static void on_create_component(entt::registry &r, entt::entity e)
auto get_emission_lifetime() const -> std::chrono::duration< float >
void set_lifetime_by_emitter_speed_range(const frange_t &speed_range)
void set_emission_shape_position(const math::vec3 &position)
auto get_last_render_frame() const noexcept -> uint64_t
void set_scale_gradient(const math::gradient< frange_t > &gradient)
void set_direction(ps_soa::emitter_direction direction)
auto get_position_easing() const -> bx::Easing::Enum
auto get_lifetime_by_emitter_speed_range() const -> const frange_t &
std::chrono::duration< float > delta_t
range< float > frange_t
math::vec3 position
Definition defaults.cpp:52
uint32_t frame
Definition graphics.cpp:23
#define APPLOG_ERROR(...)
Definition logging.h:20
Definition imgui.h:25
uint32_t get_render_frame()
Definition bbox.cpp:5
auto gradient_lerp(const vec4 &start, const vec4 &end, float progress) -> vec4
Definition gradient.cpp:8
Hash specialization for batch_key to enable use in std::unordered_map.
blend_mode
Blend mode. Ordinals match legacy BlendMode.
void update_emitter(emitter_handle handle, float dt, const emitter_desc &desc, emitter_transform_state &transform, emitter_playback_desc &playback)
Advance simulation for one emitter.
texture_mode
Texture interpretation. Ordinals match legacy TextureMode.
void update_emitter_bounds_only(emitter_handle handle, const emitter_desc &desc, emitter_transform_state &transform)
Refresh transform-driven world bounds without advancing sim (renderer-based freeze).
void destroy_emitter(emitter_handle handle)
Destroy an emitter and free its particle storage.
emitter_direction
Initial emission direction. Ordinals match legacy EmitterDirection.
particle_sim_backend
Selects CPU vs resident-GPU simulation backend.
emitter_shape
Emission volume shape. Ordinals match legacy EmitterShape for content compatibility.
simulation_space
Simulation space. Ordinals match legacy SimulationSpace.
auto create_emitter(emitter_shape shape, emitter_direction direction, uint32_t max_particles) -> emitter_handle
Create an emitter with shape/direction and capacity.
void get_aabb(emitter_handle handle, math::bbox &out_aabb)
World-space AABB used for culling.
auto is_valid(emitter_handle handle) -> bool
void set_emitter_sim_backend(emitter_handle handle, particle_sim_backend backend)
Override backend for one emitter.
spawn_location
Where particles spawn within the shape. Ordinals match legacy EmitterSpawnLocation.
auto get_num_particles(emitter_handle handle) -> uint32_t
Live particle count.
void reset_emitter(emitter_handle handle)
Clear particles and reset sim bookkeeping.
render_mode
Billboard / facing mode. Ordinals match legacy RenderMode.
auto has_updated(emitter_handle handle) -> bool
True after the first successful update.
void for_each_component_in_children(entt::handle parent, std::function< void(ComponentType &)> callback)
Iterates through all children (recursively) and calls the callback for each entity that has the speci...
Definition ecs_utils.h:15
std::vector< math::color > color
std::vector< float > scale
std::vector< math::vec3 > start
entt::handle entity
Thread-safe handle to an asset.
auto is_valid() const -> bool
Checks if the handle references a task.
Storage for box vector values and wraps up common functionality.
Definition bbox.h:21
math::gradient< math::color > color_by_speed_gradient
math::gradient< math::color > color_gradient
math::gradient< frange_t > scale_gradient
emitter_appearance_desc appearance
emitter_emission_desc emission
emitter_render_desc render
emitter_motion_desc motion
emitter_playback_desc playback
math::gradient< frange_t > velocity_gradient
math::gradient< float > lifetime_by_emitter_speed_gradient
std::string owner
bool enabled