Unravel Engine C++ Reference
Loading...
Searching...
No Matches
pipeline.cpp
Go to the documentation of this file.
1#include "pipeline.h"
9
16
18#define POOLSTL_STD_SUPPLEMENT 1
19#include <poolstl/poolstl.hpp>
20
21namespace unravel
22{
23namespace rendering
24{
25auto pipeline::init(rtti::context& ctx) -> bool
26{
27 prefilter_pass_.init(ctx);
28 blit_pass_.init(ctx);
29 atmospheric_pass_.init(ctx);
30 atmospheric_pass_perez_.init(ctx);
31 atmospheric_pass_skybox_.init(ctx);
32 fxaa_pass_.init(ctx);
33 tonemapping_pass_.init(ctx);
34 assao_pass_.init(ctx);
35 ssr_pass_.init(ctx);
36 hiz_pass_.init(ctx);
37
38 auto& am = ctx.get_cached<asset_manager>();
39
40 auto load_program = [&](const std::string& vs, const std::string& fs)
41 {
42 auto vs_shader = am.get_asset<gfx::shader>("engine:/data/shaders/" + vs + ".sc");
43 auto fs_shadfer = am.get_asset<gfx::shader>("engine:/data/shaders/" + fs + ".sc");
44
45 return std::make_unique<gpu_program>(vs_shader, fs_shadfer);
46 };
47
48 particle_program_ = load_program("particles/vs_particle", "particles/fs_particle");
49 particle_program_instanced_ = load_program("particles/instanced/vs_particle_instanced", "particles/instanced/fs_particle_instanced");
50
51
52 return true;
53}
54
55auto pipeline::gather_visible_models(scene& scn, const math::frustum* frustum, visibility_flags query, const layer_mask& render_mask)
57{
58 APP_SCOPE_PERF("Cull Models Legacy");
59
60 auto view = scn.registry->view<transform_component, model_component, layer_component, active_component>();
61
62 // Pre-allocate with estimated size
64
65 // Thread-safe collection using mutex
66 //std::mutex result_mutex;
67
68 // Use parallel execution for visibility testing
69 std::for_each(/*std::execution::par_unseq,*/ view.begin(), view.end(),
70 [&](auto entity)
71 {
72 auto&& [transform_comp, model_comp, layer_comp, active_comp] = view.get(entity);
73
74 // Get layer component if it exists, otherwise use default layer
75 auto entity_layer = layer_comp.layers;
76
77 // Early exit checks
78 if(!model_comp.is_enabled())
79 {
80 return;
81 }
82 if((query & visibility_query::is_static) && !model_comp.is_static())
83 {
84 return;
85 }
86 if((query & visibility_query::is_reflection_caster) && !model_comp.casts_reflection())
87 {
88 return;
89 }
90 if((query & visibility_query::is_shadow_caster) && !model_comp.casts_shadow())
91 {
92 return;
93 }
94
95 // Layer filtering - check if entity's layer matches camera's render mask
96 if((entity_layer.mask & render_mask.mask) == 0)
97 {
98 return; // Entity's layer is not visible to this camera
99 }
100
101 bool is_visible = true;
102
103 if(frustum)
104 {
105 const auto& world_transform = transform_comp.get_transform_global();
106 const auto& local_bounds = model_comp.get_local_bounds();
107
108 // Test the bounding box of the mesh
109 is_visible = frustum->test_obb(local_bounds, world_transform);
110 // Alternative: is_visible = frustum->test_aabb(model_comp.get_world_bounds());
111 }
112
113 if(is_visible)
114 {
115 // Thread-safe insertion
116 //std::lock_guard<std::mutex> lock(result_mutex);
117 result.emplace_back(scn.create_handle(entity));
118 }
119 });
120
121 return result;
122}
123
124
125auto pipeline::create_run_params(entt::handle camera_ent) const -> rendering::pipeline::run_params
126{
128
129 if(auto assao_comp = camera_ent.try_get<assao_component>(); assao_comp && assao_comp->enabled)
130 {
131 params.fill_assao_params = [camera_ent](assao_pass::run_params& params)
132 {
133 if(auto assao_comp = camera_ent.try_get<assao_component>())
134 {
135 params.params = assao_comp->settings;
136 }
137 };
138 }
139
140 if(auto tonemapping_comp = camera_ent.try_get<tonemapping_component>(); tonemapping_comp && tonemapping_comp->enabled)
141 {
142 params.fill_hdr_params = [camera_ent](tonemapping_pass::run_params& params)
143 {
144 if(auto tonemapping_comp = camera_ent.try_get<tonemapping_component>())
145 {
146 params.config = tonemapping_comp->settings;
147 }
148 };
149 }
150 else
151 {
152 // Always set up tonemapping params but with disabled method if component is disabled
153 params.fill_hdr_params = [camera_ent](tonemapping_pass::run_params& params)
154 {
155 params.config.method = tonemapping_method::none;
156 };
157 }
158
159 if(auto fxaa_comp = camera_ent.try_get<fxaa_component>(); fxaa_comp && fxaa_comp->enabled)
160 {
161 params.fill_fxaa_params = [camera_ent](fxaa_pass::run_params& params)
162 {
163 if(auto fxaa_comp = camera_ent.try_get<fxaa_component>())
164 {
165 // Fill FXAA parameters
166 }
167 };
168 }
169
170 if(auto ssr_comp = camera_ent.try_get<ssr_component>(); ssr_comp && ssr_comp->enabled)
171 {
172 params.fill_ssr_params = [camera_ent](ssr_pass::run_params& params)
173 {
174 if(auto ssr_comp = camera_ent.try_get<ssr_component>())
175 {
176 params.settings = ssr_comp->settings;
177 }
178 };
179 }
180
181 return params;
182}
183
184void pipeline::ui_pass(scene& scn, const camera& camera, gfx::render_view& rview, const gfx::frame_buffer::ptr& output)
185{
186 APP_SCOPE_PERF("Rendering/3D Text Pass");
187
188 const auto& view = camera.get_view();
189 const auto& proj = camera.get_projection();
190 auto& fbo = rview.fbo_get("OBUFFER_DEPTH");
191
192
193 gfx::render_pass pass("ui_elements_pass");
194 pass.bind(fbo.get());
195 pass.set_view_proj(view, proj);
196
198 [&](auto e, auto&& transform_comp, auto&& text_comp, auto&& active)
199 {
200 const auto& world_transform = transform_comp.get_transform_global();
201 auto bbox = text_comp.get_bounds();
202
203 if(!camera.test_obb(bbox, world_transform))
204 {
205 return;
206 }
207
208 text_comp.submit(pass.id, world_transform, BGFX_STATE_DEPTH_TEST_LESS);
209 });
210
211 gfx::discard();
212}
213
214
215void pipeline::particle_pass(scene& scn, const camera& camera, gfx::render_view& rview, const gfx::frame_buffer::ptr& output)
216{
217 APP_SCOPE_PERF("Rendering/Particle Pass");
218
219 auto lbuffer_depth = rview.fbo_get("LBUFFER_DEPTH");
220
221 // Set up render pass to render particles to the output framebuffer
222 gfx::render_pass pass("particle_pass");
223 pass.bind(lbuffer_depth.get());
224
225 const auto& view = camera.get_view();
226 const auto& proj = camera.get_projection();
227 pass.set_view_proj(view, proj);
228
229 stats_.drawn_particles = 0;
230 stats_.drawn_particles_batches = 0;
231
232 if(particle_program_instanced_ && particle_program_instanced_->begin())
233 {
234 // Render particles using the particle system
235 auto cam_pos = camera.get_position();
236 auto cam_view = camera.get_view();
237
238
239 struct sort_key
240 {
242 float distance;
243 };
244 hpp::small_vector<sort_key, 16> particle_emitters;
245
246 {
247 APP_SCOPE_PERF("Rendering/Particle Pass/Cull Emitters");
249 [&](auto e, auto&& transform_comp, auto&& particle_emitter_comp, auto&& active)
250 {
251 const auto& bounds = particle_emitter_comp.get_world_bounds();
252 if(!particle_emitter_comp.is_enabled() || !camera.test_aabb(bounds))
253 {
254 return;
255 }
256
257 auto distance = math::distance(bounds.get_center(), cam_pos);
258 particle_emitters.emplace_back(sort_key{&particle_emitter_comp, distance});
259 });
260 }
261
262 {
263 APP_SCOPE_PERF("Rendering/Particle Pass/Sort Emitters");
264 // Sort by distance first (back to front for proper alpha blending)
265 std::sort(particle_emitters.begin(), particle_emitters.end(), [](const sort_key& a, const sort_key& b)
266 {
267 return a.distance < b.distance;
268 });
269
270 }
271
272 {
273 APP_SCOPE_PERF("Rendering/Particle Pass/Group Emitters by Texture");
274 // Group by texture while maintaining distance order
275 // This batches emitters with the same texture together for efficient rendering
276 // while preserving the distance-sorted order for proper alpha blending
277 hpp::small_vector<EmitterHandle, 16> current_batch;
278 asset_handle<gfx::texture> current_texture;
279
280 for(const auto& particle_emitter : particle_emitters)
281 {
282 // Check if we need to start a new batch (different texture)
283 if(current_texture != particle_emitter.component->get_texture())
284 {
285 // Render the current batch if it has emitters
286 if(!current_batch.empty())
287 {
288 auto texture = current_texture.get()->native_handle();
289 stats_.drawn_particles += psRenderEmitterBatch(current_batch.data(), static_cast<uint32_t>(current_batch.size()),
290 pass.id, particle_program_instanced_->native_handle(),
291 cam_view, cam_pos, texture);
292 stats_.drawn_particles_batches++;
293 }
294
295 // Start new batch
296 current_batch.clear();
297 current_texture = particle_emitter.component->get_texture();
298 }
299
300 // Add emitter to current batch (only if it's enabled and has valid handle)
301 if(particle_emitter.component->is_enabled())
302 {
303 auto emitter_handle = particle_emitter.component->get_emitter_handle();
304 if(isValid(emitter_handle))
305 {
306 current_batch.push_back(emitter_handle);
307 }
308 }
309 }
310
311 // Render the final batch
312 if(!current_batch.empty() && current_texture.is_valid())
313 {
314 auto texture = current_texture.get()->native_handle();
315 stats_.drawn_particles += psRenderEmitterBatch(current_batch.data(), static_cast<uint32_t>(current_batch.size()),
316 pass.id, particle_program_instanced_->native_handle(),
317 cam_view, cam_pos, texture);
318 stats_.drawn_particles_batches++;
319 }
320 }
321
322 particle_program_instanced_->end();
323 }
324}
325
326// pipeline_stats implementation
327void pipeline_stats::add_batch_stats(const batch_stats& stats)
328{
329 batching_stats.total_batches += stats.total_batches;
330 batching_stats.total_instances += stats.total_instances;
331 batching_stats.collection_time_ms += stats.collection_time_ms;
332 batching_stats.preparation_time_ms += stats.preparation_time_ms;
333 batching_stats.submission_time_ms += stats.submission_time_ms;
334 batching_stats.instance_buffer_memory_used += stats.instance_buffer_memory_used;
335 batching_stats.split_batches += stats.split_batches;
336
337 // Recalculate derived stats
338 batching_stats.calculate_derived_stats();
339}
340
341} // namespace rendering
342} // namespace unravel
entt::handle b
entt::handle a
auto fbo_get(const hpp::string_view &id) const -> const frame_buffer::ptr &
Storage for frustum planes / values and wraps up common functionality.
Definition frustum.h:18
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....
Definition camera.h:35
auto test_obb(const math::bbox &bounds, const math::transform &t) const -> bool
Tests if the specified OBB is within the frustum.
Definition camera.cpp:444
auto get_projection() const -> const math::transform &
Retrieves the current projection matrix.
Definition camera.cpp:203
auto get_view() const -> const math::transform &
Retrieves the current view matrix.
Definition camera.cpp:276
auto test_aabb(const math::bbox &bounds) const -> bool
Tests if the specified AABB is within the frustum.
Definition camera.cpp:426
auto get_position() const -> const math::vec3 &
Retrieves the current position of the camera.
Definition camera.cpp:346
bool enabled
Whether FXAA is enabled.
Class that contains core data for meshes.
Component that wraps particle system emitter functionality.
virtual auto init(rtti::context &ctx) -> bool
Definition pipeline.cpp:25
virtual auto gather_visible_models(scene &scn, const math::frustum *frustum, visibility_flags query, const layer_mask &render_mask) -> visibility_set_models_t
Gathers visible models from the scene based on the given query.
Definition pipeline.cpp:55
uint32_t visibility_flags
Type alias for visibility flags.
Definition pipeline.h:98
bool enabled
Whether SSR is enabled.
bool enabled
Whether tonemapping is enabled.
Component that handles transformations (position, rotation, scale, etc.) in the ACE framework.
Definition cache.hpp:11
void discard(uint8_t _flags)
Definition graphics.cpp:969
hpp::small_vector< entt::handle > visibility_set_models_t
Definition pipeline.h:48
uint32_t psRenderEmitterBatch(const EmitterHandle *_handles, uint32_t _count, uint8_t _view, bgfx::ProgramHandle _program, const float *_mtxView, const math::vec3 &_eye, bgfx::TextureHandle _texture)
#define APP_SCOPE_PERF(name)
Create a scoped performance timer that only accepts string literals.
Definition profiler.h:160
entt::entity entity
float distance
Represents a handle to an asset, providing access and management functions.
auto is_valid() const -> bool
Checks if the handle is valid.
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)
gfx::view_id id
Definition render_pass.h:98
void bind(const frame_buffer *fb=nullptr) const
Statistics for batch collection and rendering performance.
Component that provides a layer mask for an entity.
std::function< void(assao_pass::run_params &params)> fill_assao_params
Definition pipeline.h:104
std::function< void(ssr_pass::run_params &params)> fill_ssr_params
Definition pipeline.h:107
std::function< void(tonemapping_pass::run_params &params)> fill_hdr_params
Definition pipeline.h:105
std::function< void(fxaa_pass::run_params &params)> fill_fxaa_params
Definition pipeline.h:106
Represents a scene in the ACE framework, managing entities and their relationships.
Definition scene.h:21
std::unique_ptr< entt::registry > registry
The registry that manages all entities in the scene.
Definition scene.h:117
bool isValid(SpriteHandle _handle)
Definition debugdraw.h:34