25#include <RmlUi/Core/ElementDocument.h>
31#define POOLSTL_STD_SUPPLEMENT 1
32#include <poolstl/poolstl.hpp>
50 return BGFX_STATE_BLEND_ADD;
52 return BGFX_STATE_BLEND_MULTIPLY;
54 return BGFX_STATE_BLEND_NORMAL;
60 cache_entity_ = cache_registry_.create();
62 prefilter_pass_.init(ctx);
64 atmospheric_pass_perez_.init(ctx);
65 atmospheric_pass_skybox_.init(ctx);
66 auto_exposure_pass_.init(ctx);
67 bloom_pass_.init(ctx);
70 tonemapping_pass_.init(ctx);
71 assao_pass_.init(ctx);
78 auto load_program = [&](
const std::string& vs,
const std::string&
fs)
80 auto vs_shader = am.get_asset<
gfx::shader>(
"engine:/data/shaders/" + vs +
".sc");
81 auto fs_shadfer = am.get_asset<
gfx::shader>(
"engine:/data/shaders/" +
fs +
".sc");
83 return std::make_unique<gpu_program>(vs_shader, fs_shadfer);
86 particle_program_ = load_program(
"particles/vs_particle",
"particles/fs_particle");
87 particle_program_instanced_ = load_program(
"particles/instanced/vs_particle_instanced",
"particles/instanced/fs_particle_instanced");
88 particle_program_instanced_mask_ = load_program(
"particles/instanced/vs_particle_instanced",
"particles/instanced/fs_particle_instanced_mask");
89 world_quad_program_ = load_program(
"rmlui_world/vs_world_quad",
"rmlui_world/fs_world_quad");
97std::atomic<float> shadow_lod_bias{1.0f};
102 return shadow_lod_bias.load(std::memory_order_relaxed);
107 shadow_lod_bias.store(bias, std::memory_order_relaxed);
116 const camera* lod_reference_cam)
119 APP_SCOPE_PERF(cam ?
"Rendering/Cull Models" :
"Rendering/Gather Models");
120 static const std::string thread_name =
"Rendering/Gather Models Thread";
121 tpp::this_thread::register_this_thread(thread_name,
true);
136 std::for_each(poolstl::par,
141 tpp::this_thread::register_this_thread(thread_name, true);
143 auto&& [transform_comp, model_comp, layer_comp, active_comp] = view.get(entity);
146 auto entity_layer = layer_comp.layers;
149 if((entity_layer.mask & render_mask.mask) == 0)
155 if(!model_comp.is_enabled())
169 bool is_visible =
true;
173 const auto& model = model_comp.get_model();
176 if(!model.is_valid())
185 const auto& world_bounds = model_comp.get_world_bounds();
194 is_visible = cam->
get_frustum().test_aabb(world_bounds);
196 else if(lod_reference_cam)
201 const auto&
model = model_comp.get_model();
207 get_shadow_lod_bias());
208 current_lod_data.current_lod_index = lod;
209 current_lod_data.target_lod_index = lod;
210 current_lod_data.current_time = 0.0f;
211 current_lod_data.transition_time = 0.0f;
218 queue.enqueue(std::make_pair(
entity, current_lod_data));
223 std::pair<entt::entity, lod_data> entity_lod_data;
224 while(
queue.try_dequeue_non_interleaved(entity_lod_data))
226 lod_data_callback(scn.
create_handle(entity_lod_data.first), entity_lod_data.second);
241 params.params = assao_comp->settings;
252 params.config = ae_comp->settings;
262 params.config = bloom_comp->settings;
272 params.config = tonemapping_comp->settings;
281 params.config.method = tonemapping_method::none;
291 p.config = c->settings;
298 const std::uint32_t sample_count = (std::min)(std::uint32_t(16),
299 (std::max)(std::uint32_t(2), c->settings.temporal_sample_count));
303 c->settings.jitter_mode,
304 c->settings.jitter_amplitude,
305 c->settings.jitter_temporal_phase_scale);
327 params.settings = ssr_comp->settings;
338 params.settings = ssil_comp->settings;
348 auto params = create_run_params(camera_ent);
354 const bool has_any_volume = resolved.has_auto_exposure || resolved.has_bloom || resolved.has_tonemapping ||
355 resolved.has_fxaa || resolved.has_taa || resolved.has_ssr || resolved.has_assao || resolved.has_ssil;
360 if(resolved.has_auto_exposure)
365 if(resolved.has_bloom)
370 if(resolved.has_tonemapping)
375 if(resolved.has_fxaa)
383 params.apply_taa_params = [s](
camera& cam,
const usize32_t& viewport_size) ->
void
385 const std::uint32_t sample_count =
386 (std::min)(std::uint32_t(16), (std::max)(std::uint32_t(2), s.temporal_sample_count));
392 s.jitter_temporal_phase_scale);
400 if(resolved.has_assao)
405 if(resolved.has_ssil)
410 if(params.fill_taa_params)
412 params.fill_fxaa_params = {};
423 auto& fbo = rview.
fbo_get(
"OBUFFER_DEPTH");
426 pass.
bind(fbo.get());
430 struct world_space_ui_entry
435 float distance = 0.0f;
437 struct world_space_ui_cache
439 std::vector<world_space_ui_entry>
entries;
441 auto& ui_cache = cache_registry_.get_or_emplace<world_space_ui_cache>(cache_entity_);
442 ui_cache.entries.clear();
445 if(world_quad_program_ && world_quad_program_->begin())
447 constexpr uint64_t world_ui_state = BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A | BGFX_STATE_WRITE_Z |
448 BGFX_STATE_DEPTH_TEST_LESS | BGFX_STATE_BLEND_NORMAL;
451 [&](
auto e,
auto&& transform_comp,
auto&& ui_comp,
auto&&)
453 if(ui_comp.render_mode != ui_render_mode::world_space)
457 if(!ui_comp.is_enabled() || !ui_comp.framebuffer || !ui_comp.document || !ui_comp.document->IsVisible())
462 const auto& world_transform = transform_comp.get_transform_global();
463 auto bbox = ui_comp.get_bounds();
470 ui_cache.entries.push_back({
handle, &ui_comp, &transform_comp,
dist});
473 std::sort(ui_cache.entries.begin(), ui_cache.entries.end(), [](
const world_space_ui_entry&
a,
const world_space_ui_entry&
b)
475 return a.distance > b.distance;
478 for(
const auto&
entry : ui_cache.entries)
480 auto& ui_comp = *
entry.comp;
482 const auto& world_transform =
entry.transform_comp->get_transform_global();
483 const auto scale = ui_comp.get_world_space_scale();
487 world_quad_program_->set_texture(0,
"s_tex", ui_comp.framebuffer.get(), 0);
489 gfx::submit(pass.
id, world_quad_program_->native_handle()); }
491 ui_cache.entries.clear();
493 world_quad_program_->end();
497 struct world_space_text_entry
502 float distance = 0.0f;
504 struct world_space_text_cache
506 std::vector<world_space_text_entry>
entries;
510 auto& text_cache = cache_registry_.get_or_emplace<world_space_text_cache>(cache_entity_);
511 text_cache.entries.clear();
514 [&](
auto e,
auto&& transform_comp,
auto&& text_comp,
auto&& active)
516 const auto& world_transform = transform_comp.get_transform_global();
517 auto bbox = text_comp.get_bounds();
526 text_cache.entries.push_back({
handle, &text_comp, &transform_comp,
dist});
529 std::sort(text_cache.entries.begin(), text_cache.entries.end(), [](
const world_space_text_entry&
a,
const world_space_text_entry&
b)
531 return a.distance > b.distance;
534 for(
const auto&
entry : text_cache.entries)
536 auto& text_comp = *
entry.comp;
538 const auto& world_transform =
entry.transform_comp->get_transform_global();
539 text_comp.submit(pass.
id, world_transform, BGFX_STATE_DEPTH_TEST_LESS);
542 text_cache.entries.clear();
552 auto lbuffer_depth = rview.
fbo_get(
"LBUFFER_DEPTH");
556 pass.
bind(lbuffer_depth.get());
562 stats_.drawn_particles = 0;
563 stats_.drawn_particles_batches = 0;
565 if(particle_program_instanced_ && particle_program_instanced_mask_ && particle_program_instanced_->begin() && particle_program_instanced_mask_->begin())
580 hpp::uuid texture_uid;
583 hpp::small_vector<sort_key, 16> particle_emitters;
590 case ps_soa::blend_mode::additive:
592 case ps_soa::blend_mode::multiply:
602 [&](
auto e,
auto&& transform_comp,
auto&& particle_emitter_comp,
auto&& active)
604 const auto& bounds = particle_emitter_comp.get_world_bounds();
613 const auto& tex = particle_emitter_comp.get_texture();
614 const float distance = math::distance2(bounds.get_center(), cam_pos);
615 particle_emitters.emplace_back(sort_key{&particle_emitter_comp,
616 particle_emitter_comp.get_blend_mode(),
617 particle_emitter_comp.get_texture_mode(),
624 APP_SCOPE_PERF(
"Rendering/Particle Pass/Sort Emitters by Material");
625 std::sort(particle_emitters.begin(),
626 particle_emitters.end(),
627 [&](
const sort_key&
a,
const sort_key&
b)
629 const int ao = blend_draw_order(a.blend_mode);
630 const int bo = blend_draw_order(b.blend_mode);
635 if(
a.texture_uid !=
b.texture_uid)
637 return a.texture_uid < b.texture_uid;
639 if(
a.texture_mode !=
b.texture_mode)
641 return a.texture_mode < b.texture_mode;
644 return a.distance >
b.distance;
650 hpp::small_vector<ps_soa::emitter_handle, 16> current_batch;
654 bool batch_open =
false;
656 auto flush_particle_batch = [&]()
658 if(current_batch.empty() || !batch_texture.
is_valid())
660 current_batch.clear();
665 const bgfx::ProgramHandle program = (batch_texture_mode == ps_soa::texture_mode::mask)
666 ? particle_program_instanced_mask_->native_handle()
667 : particle_program_instanced_->native_handle();
668 auto texture = batch_texture.
get()->native_handle();
669 const uint64_t
blend_state = particle_blend_bgfx_state(batch_blend_mode);
671 const bool sort_by_depth = (batch_blend_mode == ps_soa::blend_mode::normal);
672 stats_.drawn_particles += ps_soa::render_emitter_batch(current_batch.data(),
673 static_cast<uint32_t
>(current_batch.size()),
681 stats_.drawn_particles_batches++;
682 current_batch.clear();
686 for(
const auto& particle_emitter : particle_emitters)
688 auto* comp = particle_emitter.component;
689 const auto& tex = comp->get_texture();
692 if(batch_open && (tex != batch_texture || tm != batch_texture_mode || bm != batch_blend_mode))
694 flush_particle_batch();
699 batch_texture_mode = tm;
700 batch_blend_mode = bm;
703 if(comp->is_enabled())
705 auto emitter_handle = comp->get_emitter_handle();
706 if(ps_soa::is_valid(emitter_handle))
708 current_batch.push_back(emitter_handle);
712 flush_particle_batch();
715 particle_program_instanced_->end();
716 particle_program_instanced_mask_->end();
723 batching_stats.total_batches += stats.total_batches;
724 batching_stats.total_instances += stats.total_instances;
725 batching_stats.collection_time_ms += stats.collection_time_ms;
726 batching_stats.preparation_time_ms += stats.preparation_time_ms;
727 batching_stats.submission_time_ms += stats.submission_time_ms;
728 batching_stats.instance_buffer_memory_used += stats.instance_buffer_memory_used;
729 batching_stats.split_batches += stats.split_batches;
732 batching_stats.calculate_derived_stats();
737 drawn_models += stats.drawn_models;
738 drawn_static_submeshes += stats.drawn_static_submeshes;
739 drawn_skinned_models += stats.drawn_skinned_models;
740 drawn_skinned_submeshes += stats.drawn_skinned_submeshes;
741 drawn_models_for_shadows += stats.drawn_models_for_shadows;
742 drawn_submeshes_for_shadows += stats.drawn_submeshes_for_shadows;
743 drawn_skinned_models_for_shadows += stats.drawn_skinned_models_for_shadows;
744 drawn_skinned_submeshes_for_shadows += stats.drawn_skinned_submeshes_for_shadows;
745 drawn_lights += stats.drawn_lights;
746 drawn_lights_casting_shadows += stats.drawn_lights_casting_shadows;
747 drawn_particles += stats.drawn_particles;
748 drawn_particles_batches += stats.drawn_particles_batches;
750 add_batch_stats(stats.batching_stats);
std::shared_ptr< frame_buffer > ptr
auto fbo_get(const hpp::string_view &id) const -> const frame_buffer::ptr &
bool enabled
Whether ASSAO is enabled.
Manages assets, including loading, unloading, and storage.
Class representing a camera. Contains functionality for manipulating and updating a camera....
auto test_obb(const math::bbox &bounds, const math::transform &t) const -> bool
Tests if the specified OBB is within the frustum.
auto get_projection() const -> const math::transform &
Retrieves the current projection matrix.
auto get_view() const -> const math::transform &
Retrieves the current view matrix.
auto test_aabb(const math::bbox &bounds) const -> bool
Tests if the specified AABB is within the frustum.
void set_aa_data(const usize32_t &viewport_size, std::uint32_t temporal_frame_index, std::uint32_t temporal_aa_samples, taa_jitter_mode jitter_mode=taa_jitter_mode::progressive_golden, float jitter_amplitude=1.0f, float jitter_temporal_phase_scale=1.0f)
Sets the current jitter value for temporal anti-aliasing.
auto get_position() const -> const math::vec3 &
Retrieves the current position of the camera.
auto get_frustum() const -> const math::frustum &
Retrieves the current camera object frustum.
bool enabled
Whether FXAA is enabled.
Class that contains core data for meshes.
Structure describing a LOD group (set of meshes), LOD transitions, and their materials.
auto is_valid() const -> bool
Checks if the model is valid.
auto calculate_lod_data(lod_data &data, const math::bbox &world_bounds, const camera &cam, float dt) const -> bool
Calculates the LOD data for the model using distance-based hysteresis with time-based transitions....
auto compute_lod_index(const math::bbox &world_bounds, const camera &cam, float extra_bias=0.0f) const -> uint32_t
Computes a LOD index for this model without hysteresis, transitions or visibility culling.
Component that wraps the soa particle system emitter.
virtual auto init(rtti::context &ctx) -> bool
@ is_static
Query for static entities.
@ is_shadow_caster
Query for shadow casting entities.
static auto get_shadow_lod_bias() -> float
LOD bias applied on top of the main selection when rendering shadows. 0 = shadows use the same LOD th...
virtual void gather_visible_models(scene &scn, const camera *cam, visibility_flags query, const layer_mask &render_mask, delta_t dt, const std::function< void(entt::handle entity, const lod_data &lod_data)> &lod_data_callback, const camera *lod_reference_cam=nullptr)
Gathers visible models from the scene based on the given query.
static void set_shadow_lod_bias(float bias)
uint32_t visibility_flags
Type alias for visibility flags.
bool enabled
Whether SSR is enabled.
Temporal anti-aliasing (HDR, before tonemap). Mutually exclusive with FXAA when enabled.
bool enabled
Whether tonemapping is enabled.
std::chrono::duration< float > delta_t
void submit(view_id _id, program_handle _handle, int32_t _depth, bool _preserveState)
void set_state(uint64_t _state, uint32_t _rgba)
void set_world_transform(const void *_mtx, uint16_t _num)
void discard(uint8_t _flags)
uint32_t get_render_frame()
auto clip_quad(float depth, float width, float height) -> uint64_t
auto queue(seq_action action, const seq_scope_policy &scope_policy, hpp::source_location location) -> seq_id_t
Queues a new action.
blend_mode
Blend mode. Ordinals match legacy BlendMode.
texture_mode
Texture interpretation. Ordinals match legacy TextureMode.
auto resolve_post_process_volumes(scene &scn, const math::vec3 &camera_pos, entt::handle camera_ent) -> resolved_post_process_settings
Resolves post-process volumes for a camera position.
std::vector< float > scale
#define APP_SCOPE_PERF(name_literal)
Create a scoped performance timer that records to the timeline profiler. Only accepts string literals...
Thread-safe handle to an asset.
auto is_valid() const -> bool
Checks if the handle references a task.
auto get(bool wait=true) const -> std::shared_ptr< T >
Gets the shared pointer to the asset.
void set_view_proj(const float *v, const float *p)
void bind(const frame_buffer *fb=nullptr) const
Component that provides a layer mask for an entity.
Contains level of detail (LOD) data for an entity per view. Uses distance-based hysteresis for stable...
std::function< void(assao_pass::run_params ¶ms)> fill_assao_params
std::function< void(auto_exposure_pass::run_params ¶ms)> fill_auto_exposure_params
std::function< void(taa_pass::run_params ¶ms)> fill_taa_params
std::function< void(ssr_pass::run_params ¶ms)> fill_ssr_params
std::function< void(bloom_pass::run_params ¶ms)> fill_bloom_params
std::function< void(tonemapping_pass::run_params ¶ms)> fill_hdr_params
std::function< void(ssil_pass::run_params ¶ms)> fill_ssil_params
std::function< void(fxaa_pass::run_params ¶ms)> fill_fxaa_params
std::function< void(camera &, const usize32_t &viewport_size)> apply_taa_params
Represents a scene in the ACE framework, managing entities and their relationships.
std::unique_ptr< entt::registry > registry
The registry that manages all entities in the scene.
auto create_handle(entt::entity e) -> entt::handle
Creates an entity in the scene.
Component that holds a reference to a UI document for RmlUi rendering.