Unravel Engine C++ Reference
Loading...
Searching...
No Matches
pipeline.cpp
Go to the documentation of this file.
1#include "pipeline.h"
2#include "glm/ext/scalar_integer.hpp"
14
15#include <engine/engine.h>
21
25#include <graphics/texture.h>
27
28namespace unravel
29{
30namespace rendering
31{
32
33namespace
34{
35
36auto create_or_resize_d_buffer(gfx::render_view& rview,
37 const usize32_t& viewport_size,
38 const pipeline::run_params& params) -> const gfx::texture::ptr&
39{
40 auto& depth = rview.tex_get_or_emplace("DEPTH");
41 if(!depth || (depth && depth->get_size() != viewport_size))
42 {
43 depth = std::make_shared<gfx::texture>(viewport_size.width,
44 viewport_size.height,
45 false,
46 1,
47 gfx::texture_format::D32F,
48 BGFX_TEXTURE_RT);
49 }
50
51 return depth;
52}
53
54auto create_or_resize_hiz_buffer(gfx::render_view& rview, const usize32_t& viewport_size) -> const gfx::texture::ptr&
55{
56 auto& hiz = rview.tex_get_or_emplace("HIZBUFFER");
57 if(!hiz || (hiz && hiz->get_size() != viewport_size))
58 {
59 // Create Hi-Z texture with compute shader support
60 hiz = std::make_shared<gfx::texture>(viewport_size.width,
61 viewport_size.height,
62 true, // generate mips
63 1, // one layer
64 gfx::texture_format::R32F, // R32F for better precision
65 BGFX_TEXTURE_RT | // Render target
66 BGFX_TEXTURE_COMPUTE_WRITE | // Allow compute writes
67 BGFX_SAMPLER_MIN_POINT | // Point sampling for min filter
68 BGFX_SAMPLER_MAG_POINT | // Point sampling for mag filter
69 BGFX_SAMPLER_MIP_POINT | // Point sampling for mips
70 BGFX_SAMPLER_U_CLAMP | // Clamp UVs
71 BGFX_SAMPLER_V_CLAMP // Clamp UVs
72 );
73 }
74
75 return hiz;
76}
77
78auto create_or_resize_g_buffer(gfx::render_view& rview,
79 const usize32_t& viewport_size,
80 const pipeline::run_params& params) -> const gfx::frame_buffer::ptr&
81{
82 auto& depth = create_or_resize_d_buffer(rview, viewport_size, params);
83
84 auto& fbo = rview.fbo_get_or_emplace("GBUFFER");
85 if(!fbo || (fbo && fbo->get_size() != viewport_size))
86 {
87 auto format = params.fill_hdr_params ? gfx::texture_format::RGBA16F : gfx::texture_format::RGBA8;
88
89 auto tex0 = std::make_shared<gfx::texture>(viewport_size.width,
90 viewport_size.height,
91 false,
92 1,
93 gfx::texture_format::RGBA8,
94 BGFX_TEXTURE_COMPUTE_WRITE | BGFX_TEXTURE_RT);
95
96 auto tex1 = std::make_shared<gfx::texture>(viewport_size.width,
97 viewport_size.height,
98 false,
99 1,
100 format,
101 BGFX_TEXTURE_RT);
102
103 auto tex2 = std::make_shared<gfx::texture>(viewport_size.width,
104 viewport_size.height,
105 false,
106 1,
107 gfx::texture_format::RGBA8,
108 BGFX_TEXTURE_RT);
109
110 auto tex3 = std::make_shared<gfx::texture>(viewport_size.width,
111 viewport_size.height,
112 false,
113 1,
114 gfx::texture_format::RGBA8,
115 BGFX_TEXTURE_RT);
116
117 fbo = std::make_shared<gfx::frame_buffer>();
118 fbo->populate({tex0, tex1, tex2, tex3, depth});
119 }
120
121 return fbo;
122}
123
124auto create_or_resize_l_buffer(gfx::render_view& rview,
125 const usize32_t& viewport_size,
126 const pipeline::run_params& params) -> const gfx::frame_buffer::ptr&
127{
128 auto& depth = create_or_resize_d_buffer(rview, viewport_size, params);
129
130 auto& fbo = rview.fbo_get_or_emplace("LBUFFER");
131 if(!fbo || (fbo && fbo->get_size() != viewport_size))
132 {
133 auto format = params.fill_hdr_params ? gfx::texture_format::RGBA16F : gfx::texture_format::RGBA8;
134
135 auto tex = std::make_shared<gfx::texture>(viewport_size.width,
136 viewport_size.height,
137 false,
138 1,
139 format,
140 BGFX_TEXTURE_RT);
141
142 fbo = std::make_shared<gfx::frame_buffer>();
143 fbo->populate({tex});
144
145 auto& fbo_depth = rview.fbo_get_or_emplace("LBUFFER_DEPTH");
146 fbo_depth = std::make_shared<gfx::frame_buffer>();
147 fbo_depth->populate({tex, depth});
148 }
149
150 return fbo;
151}
152
153auto create_or_resize_r_buffer(gfx::render_view& rview,
154 const usize32_t& viewport_size,
155 const pipeline::run_params& params) -> const gfx::frame_buffer::ptr&
156{
157 auto& fbo = rview.fbo_get_or_emplace("RBUFFER");
158 if(!fbo || (fbo && fbo->get_size() != viewport_size))
159 {
160 auto format = params.fill_hdr_params ? gfx::texture_format::RGBA16F : gfx::texture_format::RGBA8;
161
162 auto tex = std::make_shared<gfx::texture>(viewport_size.width,
163 viewport_size.height,
164 false,
165 1,
166 format,
167 BGFX_TEXTURE_RT | BGFX_TEXTURE_COMPUTE_WRITE);
168
169 fbo = std::make_shared<gfx::frame_buffer>();
170 fbo->populate({tex});
171 }
172
173 return fbo;
174}
175auto create_or_resize_o_buffer(gfx::render_view& rview,
176 const usize32_t& viewport_size,
177 const pipeline::run_params& params) -> const gfx::frame_buffer::ptr&
178{
179 auto& depth = create_or_resize_d_buffer(rview, viewport_size, params);
180
181 auto& tex = rview.tex_get_or_emplace("OBUFFER");
182 tex = std::make_shared<gfx::texture>(viewport_size.width,
183 viewport_size.height,
184 false,
185 1,
186 gfx::texture_format::RGBA8,
187 BGFX_TEXTURE_COMPUTE_WRITE | BGFX_TEXTURE_RT);
188
189 {
190 auto& fbo = rview.fbo_get_or_emplace("OBUFFER_DEPTH");
191 if(!fbo || (fbo && fbo->get_size() != viewport_size))
192 {
193 fbo = std::make_shared<gfx::frame_buffer>();
194 fbo->populate({tex, depth});
195 }
196 }
197
198 auto& fbo = rview.fbo_get_or_emplace("OBUFFER");
199 if(!fbo || (fbo && fbo->get_size() != viewport_size))
200 {
201 fbo = std::make_shared<gfx::frame_buffer>();
202 fbo->populate({tex});
203 }
204
205 return fbo;
206}
207
208auto update_lod_data(lod_data& data,
209 const std::vector<urange32_t>& lod_limits,
210 std::size_t total_lods,
211 float transition_time,
212 float dt,
214 const math::transform& world,
215 const camera& cam) -> bool
216{
217 if(!mesh)
218 return false;
219
220 if(total_lods <= 1)
221 return true;
222
223 const auto& viewport = cam.get_viewport_size();
224 auto rect = mesh.get()->calculate_screen_rect(world, cam);
225
226 float percent = math::clamp((float(rect.height()) / float(viewport.height)) * 100.0f, 0.0f, 100.0f);
227
228 std::size_t lod = 0;
229 for(size_t i = 0; i < lod_limits.size(); ++i)
230 {
231 const auto& range = lod_limits[i];
233 {
234 lod = i;
235 }
236 }
237
238 lod = math::clamp<std::size_t>(lod, 0, total_lods - 1);
239 if(data.target_lod_index != lod && data.target_lod_index == data.current_lod_index)
240 data.target_lod_index = static_cast<std::uint32_t>(lod);
241
242 if(data.current_lod_index != data.target_lod_index)
243 data.current_time += dt;
244
245 if(data.current_time >= transition_time)
246 {
248 data.current_time = 0.0f;
249 }
250
251 if(percent < 1.0f)
252 return false;
253
254 return true;
255}
256
257auto should_rebuild_shadows(const visibility_set_models_t& visibility_set,
258 const light& light,
259 const math::bbox& light_bounds,
260 const math::transform& light_transform) -> bool
261{
262 APP_SCOPE_PERF("Rendering/Shadow Rebuild Check Per Light");
263
264 auto light_world_bounds = math::bbox::mul(light_bounds, light_transform);
265 for(const auto& element : visibility_set)
266 {
267 const auto& transform_comp_ref = element.get<transform_component>();
268 const auto& model_comp_ref = element.get<model_component>();
269 const auto& model_world_bounds = model_comp_ref.get_world_bounds();
270
271 bool result = light_world_bounds.intersect(model_world_bounds);
272
273 if(result)
274 return true;
275 }
276
277 return false;
278}
279} // namespace
280
281auto deferred::get_light_program(const light& l) const -> const color_lighting&
282{
283 return color_lighting_[uint8_t(l.type)][uint8_t(l.shadow_params.depth)][uint8_t(l.shadow_params.type)];
284}
285
286auto deferred::get_light_program_no_shadows(const light& l) const -> const color_lighting&
287{
288 return color_lighting_no_shadow_[uint8_t(l.type)];
289}
290
291void deferred::submit_pbr_material(geom_program& program, const pbr_material& mat)
292{
293 const auto& color_map = mat.get_color_map();
294 const auto& normal_map = mat.get_normal_map();
295 const auto& roughness_map = mat.get_roughness_map();
296 const auto& metalness_map = mat.get_metalness_map();
297 const auto& ao_map = mat.get_ao_map();
298 const auto& emissive_map = mat.get_emissive_map();
299
300 const auto& albedo = color_map ? color_map : mat.default_color_map();
301 const auto& normal = normal_map ? normal_map : mat.default_normal_map();
302 const auto& roughness = roughness_map ? roughness_map : mat.default_color_map();
303 const auto& metalness = metalness_map ? metalness_map : mat.default_color_map();
304 const auto& ao = ao_map ? ao_map : mat.default_color_map();
305 const auto& emissive = emissive_map ? emissive_map : mat.default_color_map();
306
307 const auto& base_color = mat.get_base_color();
308 const auto& subsurface_color = mat.get_subsurface_color();
309 const auto& emissive_color = mat.get_emissive_color();
310 const auto& surface_data = mat.get_surface_data();
311 const auto& tiling = mat.get_tiling();
312 const auto& dither_threshold = mat.get_dither_threshold();
313 const auto& surface_data2 = mat.get_surface_data2();
314
315 gfx::set_texture(program.s_tex_color, 0, albedo.get());
316 gfx::set_texture(program.s_tex_normal, 1, normal.get());
317 gfx::set_texture(program.s_tex_roughness, 2, roughness.get());
318 gfx::set_texture(program.s_tex_metalness, 3, metalness.get());
319 gfx::set_texture(program.s_tex_ao, 4, ao.get());
320 gfx::set_texture(program.s_tex_emissive, 5, emissive.get());
321
322 gfx::set_uniform(program.u_base_color, base_color);
323 gfx::set_uniform(program.u_subsurface_color, subsurface_color);
324 gfx::set_uniform(program.u_emissive_color, emissive_color);
325 gfx::set_uniform(program.u_surface_data, surface_data);
326 gfx::set_uniform(program.u_tiling, tiling);
327 gfx::set_uniform(program.u_dither_threshold, dither_threshold);
328 gfx::set_uniform(program.u_surface_data2, surface_data2);
329
330 auto state = mat.get_render_states(true, true, true);
331
332 gfx::set_state(state);
333}
334
336{
337 APP_SCOPE_PERF("Rendering/Reflection Generation Pass");
338
340 [&](auto e, auto&& transform_comp, auto&& reflection_probe_comp, auto&& active)
341 {
342 if(reflection_probe_comp.already_generated())
343 {
344 return;
345 }
346
347 // reflection_probe_comp.set_generation_frame(gfx::get_render_frame());
348
349 const auto& world_transform = transform_comp.get_transform_global();
350
351 const auto& bounds = reflection_probe_comp.get_bounds();
352 if(!camera.test_obb(bounds, world_transform))
353 {
354 return;
355 }
356
357 const auto& probe = reflection_probe_comp.get_probe();
358
359 auto handle = scn.create_handle(e);
360 {
361 gfx::render_pass::push_scope("build.reflecitons");
362
363 // iterate trough each cube face
364 for(std::uint32_t face = 0; face < 6; ++face)
365 {
366 if(reflection_probe_comp.already_generated(face))
367 {
368 continue;
369 }
370
371 reflection_probe_comp.set_generation_frame(face, gfx::get_render_frame());
372
373 auto camera = camera::get_face_camera(face, world_transform);
374 camera.set_far_clip(probe.get_face_extents(face, world_transform));
375 auto& rview = reflection_probe_comp.get_render_view(face);
376 const auto& cubemap_fbo = reflection_probe_comp.get_cubemap_fbo(face);
377
378 camera.set_viewport_size(usize32_t(cubemap_fbo->get_size()));
379
380 bool not_environment = probe.method != reflect_method::environment;
381
384
385 if(not_environment)
386 {
388 }
389
390 auto params = create_run_params(handle);
391 params.vflags = vflags;
392
393 run_pipeline_impl(cubemap_fbo, scn, camera, rview, dt, params, pflags);
394 }
395
396 auto env_cube = reflection_probe_comp.get_cubemap();
397 auto env_cube_prefiltered = reflection_probe_comp.get_cubemap_prefiltered();
398
399 {
400 prefilter_pass::run_params prefilter_params;
401
402 prefilter_params.apply_prefilter = reflection_probe_comp.get_apply_prefilter();
403
404 for(std::uint32_t face = 0; face < 6; ++face)
405 {
406 const auto& cubemap_fbo = reflection_probe_comp.get_cubemap_fbo(face);
407 prefilter_params.input_faces[face] = cubemap_fbo->get_texture();
408 }
409
410 prefilter_params.output_cube = env_cube;
411 prefilter_params.output_cube_prefiltered = env_cube_prefiltered;
412
413 prefilter_pass_.run(prefilter_params);
414 }
415
417 }
418 });
419}
420
422{
423 APP_SCOPE_PERF("Rendering/Shadow Generation Pass");
424
426
427 bool queried = false;
428 visibility_set_models_t dirty_models;
429
430 const auto& view = camera.get_view();
431 const auto& proj = camera.get_projection();
432 const auto& camera_pos = camera.get_position();
433
435 [&](auto e, auto&& transform_comp, auto&& light_comp)
436 {
437 const auto& light = light_comp.get_light();
438
439 bool is_directional = light.type == light_type::directional;
440 bool has_render_mask = render_mask.mask != layer_reserved::everything_layer;
441 bool camera_dependant = is_directional || has_render_mask;
442 bool is_active = scn.registry->all_of<active_component>(e);
443
444 auto& generator = light_comp.get_shadowmap_generator();
445 generator.enable_adaptive_shadows(true);
446 generator.set_altitude_scale_factor(0.4f);
447 if(!camera_dependant && generator.already_updated())
448 {
449 return;
450 }
451
452 APP_SCOPE_PERF("Rendering/Shadow Generation Pass Per Light");
453
454 auto world_transform = transform_comp.get_transform_global();
455 world_transform.reset_scale();
456 const auto& light_direction = world_transform.z_unit_axis();
457
458 generator.update(camera, light, world_transform, is_active);
459
460 if(!is_active)
461 {
462 return;
463 }
464
465 const auto& bounds = light_comp.get_bounds_precise(light_direction);
466 if(!camera.test_obb(bounds, world_transform))
467 {
468 return;
469 }
470
472 {
473 return;
474 }
475
476 if(!queried)
477 {
478 dirty_models = gather_visible_models(scn, nullptr, query, render_mask);
479 queried = true;
480 }
481
482 bool should_rebuild = should_rebuild_shadows(dirty_models, light, bounds, world_transform);
483
484 // If shadows shouldn't be rebuilt - continue.
485 if(!should_rebuild)
486 return;
487
488 APP_SCOPE_PERF("Rendering/Shadow Generation Pass Per Light After Cull");
489
490 generator.generate_shadowmaps(dirty_models);
491 });
492}
493
495 const camera& camera,
496 gfx::render_view& rview,
497 delta_t dt,
498 const run_params& params,
499 layer_mask render_mask) -> gfx::frame_buffer::ptr
500{
501 const auto& viewport_size = camera.get_viewport_size();
502 const auto& obuffer = create_or_resize_o_buffer(rview, viewport_size, params);
503
504 run_pipeline_impl(obuffer, scn, camera, rview, dt, params, pipeline_steps::full, render_mask);
505
506 return obuffer;
507}
508
510 scene& scn,
511 const camera& camera,
512 gfx::render_view& rview,
513 delta_t dt,
514 const run_params& params,
515 layer_mask render_mask)
516{
517 auto obuffer = run_pipeline(scn, camera, rview, dt, params, render_mask);
518
519 blit_pass::run_params pass_params;
520 pass_params.input = obuffer;
521 pass_params.output = output;
522 blit_pass_.run(pass_params);
523}
524
526{
527 debug_pass_ = pass;
528}
529
531 scene& scn,
532 const camera& camera,
533 gfx::render_view& rview,
534 delta_t dt,
535 const run_params& params,
536 pipeline_flags pflags,
537 layer_mask render_mask)
538{
539 APP_SCOPE_PERF("Rendering/Run Pipeline");
540
541 visibility_set_models_t visibility_set;
542 gfx::frame_buffer::ptr target = nullptr;
543
544 bool apply_reflecitons = pflags & pipeline_steps::reflection_probe;
545 bool apply_shadows = pflags & pipeline_steps::shadow_pass;
546
547 if(apply_reflecitons)
548 {
549 build_reflections(scn, camera, dt);
550 }
551
552 if(apply_shadows)
553 {
555 }
556
557 const auto& viewport_size = camera.get_viewport_size();
558 create_or_resize_d_buffer(rview, viewport_size, params);
559 create_or_resize_g_buffer(rview, viewport_size, params);
560 create_or_resize_l_buffer(rview, viewport_size, params);
561 create_or_resize_r_buffer(rview, viewport_size, params);
562
564 {
565 visibility_set = gather_visible_models(scn, &camera.get_frustum(), params.vflags, render_mask);
566 }
567 run_g_buffer_pass(visibility_set, camera, rview, dt);
568
569 run_assao_pass(visibility_set, camera, rview, dt, params);
570
571 run_reflection_probe_pass(scn, camera, rview, dt);
572
573 if(apply_reflecitons)
574 {
575 run_ssr_pass(camera, rview, target, params);
576 }
577
578 target = run_lighting_pass(scn, camera, rview, apply_shadows, dt);
579
580 target = run_atmospherics_pass(target, scn, camera, rview, dt);
581
582 target = run_tonemapping_pass(rview, target, output, params);
583
584 run_fxaa_pass(rview, target, output, params);
585
586 if(pflags == pipeline_steps::full)
587 {
588 ui_pass(scn, camera, rview, output);
589
590 if(debug_pass_ >= 0)
591 {
592 run_debug_visualization_pass(camera, rview, output);
593 }
594 }
595}
596
598 const camera& camera,
599 gfx::render_view& rview,
600 delta_t dt)
601{
602 APP_SCOPE_PERF("Rendering/G-Buffer Pass");
603
604 const auto& view = camera.get_view();
605 const auto& proj = camera.get_projection();
606 const auto& viewport_size = camera.get_viewport_size();
607
608 const auto& gbuffer = rview.fbo_get("GBUFFER");
609
610 gfx::render_pass pass("g_buffer_pass");
611 pass.clear();
612 pass.set_view_proj(view, proj);
613 pass.bind(gbuffer.get());
614
615 for(const auto& e : visibility_set)
616 {
617 const auto& transform_comp = e.get<transform_component>();
618 auto& model_comp = e.get<model_component>();
619
620 const auto& model = model_comp.get_model();
621 if(!model.is_valid())
622 continue;
623
624 const auto& world_transform = transform_comp.get_transform_global();
625 const auto clip_planes = math::vec2(camera.get_near_clip(), camera.get_far_clip());
626
627 lod_data lod_runtime_data{}; // camera_lods[e];
628 const auto transition_time = 0.0f;
629 const auto lod_count = model.get_lods().size();
630 const auto& lod_limits = model.get_lod_limits();
631
632 const auto base_mesh = model.get_lod(0);
633 if(!base_mesh)
634 continue;
635
636 if(false == update_lod_data(lod_runtime_data,
637 lod_limits,
638 lod_count,
639 transition_time,
640 dt.count(),
641 base_mesh,
642 world_transform,
643 camera))
644 continue;
645
646 const auto current_time = lod_runtime_data.current_time;
647 const auto current_lod_index = lod_runtime_data.current_lod_index;
648 const auto target_lod_index = lod_runtime_data.target_lod_index;
649
650 const auto params = math::vec3{0.0f, -1.0f, (transition_time - current_time) / transition_time};
651
652 const auto params_inv = math::vec3{1.0f, 1.0f, current_time / transition_time};
653
654 const auto& submesh_transforms = model_comp.get_submesh_transforms();
655 const auto& bone_transforms = model_comp.get_bone_transforms();
656 const auto& skinning_matrices = model_comp.get_skinning_transforms();
657
658 auto camera_pos = camera.get_position();
659
660 model::submit_callbacks callbacks;
661 callbacks.setup_begin = [&](const model::submit_callbacks::params& submit_params)
662 {
663 geom_program& prog = submit_params.skinned ? geom_program_skinned_ : geom_program_;
664
665 prog.program->begin();
666
667 gfx::set_uniform(prog.u_camera_wpos, camera_pos);
668 gfx::set_uniform(prog.u_camera_clip_planes, clip_planes);
669 };
670 callbacks.setup_params_per_instance = [&](const model::submit_callbacks::params& submit_params)
671 {
672 geom_program& prog = submit_params.skinned ? geom_program_skinned_ : geom_program_;
673
674 gfx::set_uniform(prog.u_lod_params, params);
675 };
676 callbacks.setup_params_per_submesh =
677 [&](const model::submit_callbacks::params& submit_params, const material& mat)
678 {
679 geom_program& prog = submit_params.skinned ? geom_program_skinned_ : geom_program_;
680
681 bool submitted = mat.submit(prog.program.get());
682 if(!submitted)
683 {
684 if(mat.is<pbr_material>())
685 {
686 const auto& pbr = static_cast<const pbr_material&>(mat);
687 submit_pbr_material(prog, pbr);
688 }
689 }
690
691 gfx::submit(pass.id, prog.program->native_handle(), 0, submit_params.preserve_state);
692 };
693 callbacks.setup_end = [&](const model::submit_callbacks::params& submit_params)
694 {
695 geom_program& prog = submit_params.skinned ? geom_program_skinned_ : geom_program_;
696
697 prog.program->end();
698 };
699
700 model_comp.set_last_render_frame(gfx::get_render_frame());
701 model.submit(world_transform,
702 submesh_transforms,
703 bone_transforms,
704 skinning_matrices,
705 current_lod_index,
706 callbacks);
707 if(math::epsilonNotEqual(current_time, 0.0f, math::epsilon<float>()))
708 {
709 callbacks.setup_params_per_instance = [&](const model::submit_callbacks::params& submit_params)
710 {
711 geom_program& prog = submit_params.skinned ? geom_program_skinned_ : geom_program_;
712
713 gfx::set_uniform(prog.u_lod_params, params);
714 };
715
716 model.submit(world_transform,
717 submesh_transforms,
718 bone_transforms,
719 skinning_matrices,
720 target_lod_index,
721 callbacks);
722 }
723 }
724 gfx::discard();
725}
726
728 const camera& camera,
729 gfx::render_view& rview,
730 delta_t dt,
731 const run_params& rparams)
732{
733 if(!rparams.fill_assao_params)
734 {
735 return;
736 }
737 APP_SCOPE_PERF("Rendering/ASSAO Pass");
738
739 const auto& gbuffer = rview.fbo_get("GBUFFER");
740
741 auto color_ao = gbuffer->get_texture(0);
742 auto normal = gbuffer->get_texture(1);
743 auto depth = gbuffer->get_texture(4);
744
746 params.depth = depth.get();
747 params.normal = normal.get();
748 params.color_ao = color_ao.get();
749
750 rparams.fill_assao_params(params);
751
752 assao_pass_.run(camera, rview, params);
753}
754
756 const camera& camera,
757 gfx::render_view& rview,
758 bool apply_shadows,
760{
761 APP_SCOPE_PERF("Rendering/Lighting Pass");
762
763 const auto& view = camera.get_view();
764 const auto& proj = camera.get_projection();
765 const auto& camera_pos = camera.get_position();
766
767 const auto& viewport_size = camera.get_viewport_size();
768
769 const auto& gbuffer = rview.fbo_get("GBUFFER");
770 const auto& rbuffer = rview.fbo_safe_get("RBUFFER");
771 const auto& lbuffer = rview.fbo_get("LBUFFER");
772
773 const auto buffer_size = lbuffer->get_size();
774
775 gfx::render_pass pass("light_buffer_pass");
776 pass.bind(lbuffer.get());
777 pass.set_view_proj(view, proj);
778 pass.clear(BGFX_CLEAR_COLOR, 0, 0.0f, 0);
779
780 scn.registry->view<transform_component, light_component, active_component>().each(
781 [&](auto e, auto&& transform_comp_ref, auto&& light_comp_ref, auto&& active)
782 {
783 const auto& light = light_comp_ref.get_light();
784 const auto& generator = light_comp_ref.get_shadowmap_generator();
785 auto world_transform = transform_comp_ref.get_transform_global();
786 world_transform.reset_scale();
787 const auto& light_position = world_transform.get_position();
788 const auto& light_direction = world_transform.z_unit_axis();
789
790 const auto& bounds = light_comp_ref.get_bounds_precise(light_direction);
791 if(!camera.test_obb(bounds, world_transform))
792 {
793 return;
794 }
795
796 irect32_t rect(0, 0, irect32_t::value_type(buffer_size.width), irect32_t::value_type(buffer_size.height));
797 if(light_comp_ref
798 .compute_projected_sphere_rect(rect, light_position, light_direction, camera_pos, view, proj) == 0)
799 return;
800
801 APP_SCOPE_PERF("Rendering/Lighting Pass/Per Light");
802
803 bool has_shadows = light.casts_shadows && apply_shadows;
804
805 const auto& lprogram = has_shadows ? get_light_program(light) : get_light_program_no_shadows(light);
806
807 lprogram.program->begin();
808
810 {
811 float light_data[4] = {0.0f, 0.0f, 0.0f, light.ambient_intensity};
812
813 gfx::set_uniform(lprogram.u_light_direction, light_direction);
814 gfx::set_uniform(lprogram.u_light_data, light_data);
815 }
817 {
818 float light_data[4] = {light.point_data.range,
820 0.0f,
822
823 gfx::set_uniform(lprogram.u_light_position, light_position);
824 gfx::set_uniform(lprogram.u_light_data, light_data);
825 }
826
828 {
829 float light_data[4] = {light.spot_data.get_range(),
830 math::cos(math::radians(light.spot_data.get_inner_angle() * 0.5f)),
831 math::cos(math::radians(light.spot_data.get_outer_angle() * 0.5f)),
833
834 gfx::set_uniform(lprogram.u_light_direction, light_direction);
835 gfx::set_uniform(lprogram.u_light_position, light_position);
836 gfx::set_uniform(lprogram.u_light_data, light_data);
837 }
838
839 float light_color_intensity[4] = {light.color.value.r,
840 light.color.value.g,
841 light.color.value.b,
843
844 gfx::set_uniform(lprogram.u_light_color_intensity, light_color_intensity);
845 gfx::set_uniform(lprogram.u_camera_position, camera_pos);
846
847 size_t i = 0;
848 for(; i < gbuffer->get_attachment_count(); ++i)
849 {
850 gfx::set_texture(lprogram.s_tex[i], i, gbuffer->get_texture(i));
851 }
852 gfx::set_texture(lprogram.s_tex[i], i, rbuffer);
853 i++;
854 gfx::set_texture(lprogram.s_tex[i], i, ibl_brdf_lut_.get());
855 i++;
856
857 if(has_shadows)
858 {
859 generator.submit_uniforms(i);
860 }
862 auto topology = gfx::clip_quad(1.0f);
863 gfx::set_state(topology | BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A | BGFX_STATE_BLEND_ADD);
864 gfx::submit(pass.id, lprogram.program->native_handle());
865 gfx::set_state(BGFX_STATE_DEFAULT);
866
867 lprogram.program->end();
868 });
869
870 gfx::discard();
871
872 return lbuffer;
873}
874
876{
877 APP_SCOPE_PERF("Rendering/Reflection Probe Pass");
878
879 const auto& view = camera.get_view();
880 const auto& proj = camera.get_projection();
881 const auto& camera_pos = camera.get_position();
882
883 const auto& viewport_size = camera.get_viewport_size();
884 const auto& gbuffer = rview.fbo_get("GBUFFER");
885 const auto& rbuffer = rview.fbo_get("RBUFFER");
886
887 const auto buffer_size = rbuffer->get_size();
888
889 gfx::render_pass pass("refl_buffer_pass");
890 pass.bind(rbuffer.get());
891 pass.set_view_proj(view, proj);
892 pass.clear(BGFX_CLEAR_COLOR, 0, 0.0f, 0);
893 std::vector<entt::entity> sorted_probes;
894
895 // Collect all entities with the relevant components
897 [&](auto e, auto&& transform_comp_ref, auto&& probe_comp_ref, auto&& active)
898 {
899 sorted_probes.emplace_back(e);
900 });
901
902 // Sort the probes based on the method and max range
903 std::sort(std::begin(sorted_probes),
904 std::end(sorted_probes),
905 [&](const auto& lhs, const auto& rhs)
906 {
907 const auto& lhs_comp = scn.registry->get<reflection_probe_component>(lhs);
908 const auto& lhs_probe = lhs_comp.get_probe();
909
910 const auto& rhs_comp = scn.registry->get<reflection_probe_component>(rhs);
911 const auto& rhs_probe = rhs_comp.get_probe();
912
913 // Environment probes should be last
914 if(lhs_probe.method != rhs_probe.method)
915 {
916 return lhs_probe.method < rhs_probe.method; // Environment method is "greater"
917 }
918
919 // If the reflection methods are the same, compare based on the maximum range
920 return lhs_probe.get_max_range() > rhs_probe.get_max_range(); // Smaller ranges first
921 });
922
923 // Render or process the sorted probes
924 for(const auto& e : sorted_probes)
925 {
926 auto& transform_comp_ref = scn.registry->get<transform_component>(e);
927 auto& probe_comp_ref = scn.registry->get<reflection_probe_component>(e);
928
929 const auto& probe = probe_comp_ref.get_probe();
930 const auto& world_transform = transform_comp_ref.get_transform_global();
931 const auto& probe_position = world_transform.get_position();
932 const auto& probe_scale = world_transform.get_scale();
933
934 irect32_t rect(0, 0, irect32_t::value_type(buffer_size.width), irect32_t::value_type(buffer_size.height));
935 if(probe_comp_ref.compute_projected_sphere_rect(rect, probe_position, probe_scale, camera_pos, view, proj) == 0)
936 {
937 continue;
938 }
939
940 const auto& cubemap = probe_comp_ref.get_cubemap_prefiltered();
941
942 ref_probe_program* ref_probe_program = nullptr;
943 float influence_radius = 0.0f;
944 if(probe.type == probe_type::sphere && sphere_ref_probe_program_.program)
945 {
946 ref_probe_program = &sphere_ref_probe_program_;
947 influence_radius =
948 math::max(probe_scale.x, math::max(probe_scale.y, probe_scale.z)) * probe.sphere_data.range;
949 }
950
951 if(probe.type == probe_type::box && box_ref_probe_program_.program)
952 {
953 math::transform t = world_transform;
954 t.scale(probe.box_data.extents);
955 auto u_inv_world = math::inverse(t).get_matrix();
956 float data2[4] = {probe.box_data.extents.x,
957 probe.box_data.extents.y,
958 probe.box_data.extents.z,
959 probe.box_data.transition_distance};
960
961 ref_probe_program = &box_ref_probe_program_;
962
963 gfx::set_uniform(box_ref_probe_program_.u_inv_world, u_inv_world);
964 gfx::set_uniform(box_ref_probe_program_.u_data2, data2);
965
966 influence_radius = math::length(t.get_scale() + probe.box_data.transition_distance);
967 }
968
969 if(ref_probe_program)
970 {
971 float mips = cubemap ? float(cubemap->info.numMips) : 1.0f;
972 float data0[4] = {
973 probe_position.x,
974 probe_position.y,
975 probe_position.z,
976 influence_radius,
977 };
978
979 float data1[4] = {mips, probe.intensity, 0.0f, 0.0f};
980
981 gfx::set_uniform(ref_probe_program->u_data0, data0);
982 gfx::set_uniform(ref_probe_program->u_data1, data1);
983
984 for(size_t i = 0; i < gbuffer->get_attachment_count(); ++i)
985 {
986 gfx::set_texture(ref_probe_program->s_tex[i], i, gbuffer->get_texture(i));
987 }
988
989 gfx::set_texture(ref_probe_program->s_tex_cube, 5, cubemap);
990
992 auto topology = gfx::clip_quad(1.0f);
993 gfx::set_state(topology | BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A | BGFX_STATE_BLEND_ALPHA);
994
995 ref_probe_program->program->begin();
996 gfx::submit(pass.id, ref_probe_program->program->native_handle());
997 gfx::set_state(BGFX_STATE_DEFAULT);
998 ref_probe_program->program->end();
999 }
1000 }
1001
1002 gfx::discard();
1003}
1004
1006 scene& scn,
1007 const camera& camera,
1008 gfx::render_view& rview,
1010{
1011 APP_SCOPE_PERF("Rendering/Atmospheric Pass");
1012
1016
1017 bool found_sun = false;
1018
1020 scn.registry->view<transform_component, skylight_component, active_component>().each(
1021 [&](auto e, auto&& transform_comp_ref, auto&& light_comp_ref, auto&& active)
1022 {
1023 auto entity = scn.create_handle(e);
1024
1025 if(found_sun)
1026 {
1027 APPLOG_WARNING("[{}] More than one entity with this component. Others are ignored.", "Skylight");
1028 return;
1029 }
1030 const auto& cubemap = light_comp_ref.get_cubemap();
1031 auto cubemap_texture = cubemap.get();
1032 if(cubemap_texture)
1033 {
1034 if(cubemap_texture->info.cubeMap)
1035 {
1036 params_skybox.cubemap = cubemap;
1037 }
1038 }
1039
1040 mode = light_comp_ref.get_mode();
1041 found_sun = true;
1042 if(auto light_comp = entity.template try_get<light_component>())
1043 {
1044 const auto& light = light_comp->get_light();
1045
1047 {
1048 const auto& world_transform = transform_comp_ref.get_transform_global();
1049 params.light_direction = world_transform.z_unit_axis();
1050 params.turbidity = light_comp_ref.get_turbidity();
1051
1052 params_perez.light_direction = world_transform.z_unit_axis();
1053 params_perez.turbidity = light_comp_ref.get_turbidity();
1054 }
1055 }
1056 });
1057
1058 if(!found_sun)
1059 {
1060 return input;
1061 }
1062 const auto& viewport_size = camera.get_viewport_size();
1063
1064 auto c = camera;
1065 c.set_projection_mode(projection_mode::perspective);
1066
1067 auto lbuffer_depth = rview.fbo_get("LBUFFER_DEPTH");
1068
1069 switch(mode)
1070 {
1072 atmospheric_pass_perez_.run(lbuffer_depth, c, rview, dt, params_perez);
1073 break;
1075 atmospheric_pass_.run(lbuffer_depth, c, rview, dt, params);
1076 break;
1077 default:
1078 atmospheric_pass_skybox_.run(lbuffer_depth, c, rview, dt, params_skybox);
1079 break;
1080 }
1081
1082 return input;
1083}
1084
1086 gfx::render_view& rview,
1087 const gfx::frame_buffer::ptr& output,
1088 const run_params& rparams) -> gfx::frame_buffer::ptr
1089{
1090 if(!rparams.fill_ssr_params)
1091 {
1092 return output;
1093 }
1094
1095 ssr_pass::run_params ssr_params;
1096
1097 ssr_params.output = rview.fbo_get("RBUFFER");
1098 ssr_params.g_buffer = rview.fbo_get("GBUFFER");
1099
1100 ssr_params.previous_frame = rview.fbo_get("LBUFFER")->get_texture();
1101
1102 ssr_params.cam = &camera;
1103
1104 if(rparams.fill_ssr_params)
1105 {
1106 rparams.fill_ssr_params(ssr_params);
1107 }
1108
1109 {
1110 create_or_resize_hiz_buffer(rview, camera.get_viewport_size());
1111 run_hiz_pass(camera, rview, delta_t(0.0f));
1112
1113 ssr_params.hiz_buffer = rview.tex_get("HIZBUFFER");
1114 }
1115
1116 // BUG Cone tracing is not working properly, so we disable it for now.
1117 ssr_params.settings.fidelityfx.enable_cone_tracing = false;
1118
1119 return ssr_pass_.run(rview, ssr_params);
1120}
1121
1124 const gfx::frame_buffer::ptr& output,
1125 const run_params& rparams) -> gfx::frame_buffer::ptr
1126{
1127 if(!rparams.fill_fxaa_params)
1128 {
1129 return input;
1130 }
1131
1132 APP_SCOPE_PERF("Rendering/FXAA Pass");
1133
1134 fxaa_pass::run_params params;
1135 params.input = input;
1136 params.output = output;
1137
1138 rparams.fill_fxaa_params(params);
1139
1140 return fxaa_pass_.run(rview, params);
1141}
1142
1145 const gfx::frame_buffer::ptr& output,
1146 const run_params& rparams) -> gfx::frame_buffer::ptr
1147{
1148 if(!rparams.fill_hdr_params)
1149 {
1150 return input;
1151 }
1152 APP_SCOPE_PERF("Rendering/Tonemapping Pass");
1153
1155 params.input = input;
1156
1157 if(!rparams.fill_fxaa_params)
1158 {
1159 params.output = output;
1160 }
1161
1162 rparams.fill_hdr_params(params);
1163
1164 return tonemapping_pass_.run(rview, params);
1165}
1166
1168 gfx::render_view& rview,
1169 const gfx::frame_buffer::ptr& output)
1170{
1171 const auto& view = camera.get_view();
1172 const auto& proj = camera.get_projection();
1173 const auto& gbuffer = rview.fbo_get("GBUFFER");
1174 const auto& rbuffer = rview.fbo_safe_get("RBUFFER");
1175 // const auto& lbuffer = rview.fbo_get("LBUFFER");
1176
1177 gfx::render_pass pass("debug_visualization_pass");
1178 pass.bind(output.get());
1179 pass.set_view_proj(view, proj);
1180 // pass.clear(BGFX_CLEAR_COLOR, 0, 0.0f, 0);
1181
1182 const auto output_size = output->get_size();
1183
1184 debug_visualization_program_.program->begin();
1185
1186 float u_params[4] = {float(debug_pass_), 0.0f, 0.0f, 0.0f};
1187
1188 gfx::set_uniform(debug_visualization_program_.u_params, u_params);
1189
1190 size_t i = 0;
1191 for(; i < gbuffer->get_attachment_count(); ++i)
1192 {
1193 gfx::set_texture(debug_visualization_program_.s_tex[i], i, gbuffer->get_texture(i));
1194 }
1195 gfx::set_texture(debug_visualization_program_.s_tex[i], i, rbuffer);
1196
1197 irect32_t rect(0, 0, irect32_t::value_type(output_size.width), irect32_t::value_type(output_size.height));
1199 auto topology = gfx::clip_quad(1.0f);
1200 gfx::set_state(topology | BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A);
1201 gfx::submit(pass.id, debug_visualization_program_.program->native_handle());
1202 gfx::set_state(BGFX_STATE_DEFAULT);
1203 debug_visualization_program_.program->end();
1204
1205 gfx::discard();
1206}
1207
1209{
1210 APP_SCOPE_PERF("Rendering/SSR/Hi-Z Pass");
1211
1212 auto& gbuffer = rview.fbo_get("GBUFFER");
1213 if(!gbuffer)
1214 return nullptr;
1215
1216 // Run Hi-Z pass using the base class's pass
1217 hiz_pass::run_params params;
1218 params.depth_buffer = gbuffer->get_texture(4);
1219 ;
1220 params.output_hiz = rview.tex_get("HIZBUFFER");
1221 params.cam = &camera;
1222
1223 hiz_pass_.run(rview, params);
1224 return params.output_hiz;
1225}
1226
1231
1236
1238{
1239 auto& am = ctx.get_cached<asset_manager>();
1240
1241 auto load_program = [&](const std::string& vs, const std::string& fs)
1242 {
1243 auto vs_shader = am.get_asset<gfx::shader>("engine:/data/shaders/" + vs + ".sc");
1244 auto fs_shadfer = am.get_asset<gfx::shader>("engine:/data/shaders/" + fs + ".sc");
1245
1246 return std::make_unique<gpu_program>(vs_shader, fs_shadfer);
1247 };
1248
1249 geom_program_.program = load_program("vs_deferred_geom", "fs_deferred_geom");
1250 geom_program_.cache_uniforms();
1251
1252 geom_program_skinned_.program = load_program("vs_deferred_geom_skinned", "fs_deferred_geom");
1253 geom_program_skinned_.cache_uniforms();
1254
1255 sphere_ref_probe_program_.program = load_program("vs_clip_quad_ex", "reflection_probe/fs_sphere_reflection_probe");
1256 sphere_ref_probe_program_.cache_uniforms();
1257
1258 box_ref_probe_program_.program = load_program("vs_clip_quad_ex", "reflection_probe/fs_box_reflection_probe");
1259 box_ref_probe_program_.cache_uniforms();
1260
1261 debug_visualization_program_.program = load_program("vs_clip_quad", "gbuffer/fs_gbuffer_visualize");
1262 debug_visualization_program_.cache_uniforms();
1263
1264 // Color lighting.
1265
1266 // clang-format off
1267 color_lighting_no_shadow_[uint8_t(light_type::spot)].program = load_program("vs_clip_quad", "fs_deferred_spot_light");
1268 color_lighting_[uint8_t(light_type::spot)][uint8_t(sm_depth::invz)][uint8_t(sm_impl::hard)].program = load_program("vs_clip_quad", "fs_deferred_spot_light_hard");
1269 color_lighting_[uint8_t(light_type::spot)][uint8_t(sm_depth::invz)][uint8_t(sm_impl::pcf) ].program = load_program("vs_clip_quad", "fs_deferred_spot_light_pcf");
1270 color_lighting_[uint8_t(light_type::spot)][uint8_t(sm_depth::invz)][uint8_t(sm_impl::pcss) ].program = load_program("vs_clip_quad", "fs_deferred_spot_light_pcss");
1271 color_lighting_[uint8_t(light_type::spot)][uint8_t(sm_depth::invz)][uint8_t(sm_impl::vsm) ].program = load_program("vs_clip_quad", "fs_deferred_spot_light_vsm");
1272 color_lighting_[uint8_t(light_type::spot)][uint8_t(sm_depth::invz)][uint8_t(sm_impl::esm) ].program = load_program("vs_clip_quad", "fs_deferred_spot_light_esm");
1273
1274 color_lighting_[uint8_t(light_type::spot)][uint8_t(sm_depth::linear)][uint8_t(sm_impl::hard)].program = load_program("vs_clip_quad", "fs_deferred_spot_light_hard_linear");
1275 color_lighting_[uint8_t(light_type::spot)][uint8_t(sm_depth::linear)][uint8_t(sm_impl::pcf) ].program = load_program("vs_clip_quad", "fs_deferred_spot_light_pcf_linear");
1276 color_lighting_[uint8_t(light_type::spot)][uint8_t(sm_depth::linear)][uint8_t(sm_impl::pcss) ].program = load_program("vs_clip_quad", "fs_deferred_spot_light_pcss_linear");
1277 color_lighting_[uint8_t(light_type::spot)][uint8_t(sm_depth::linear)][uint8_t(sm_impl::vsm) ].program = load_program("vs_clip_quad", "fs_deferred_spot_light_vsm_linear");
1278 color_lighting_[uint8_t(light_type::spot)][uint8_t(sm_depth::linear)][uint8_t(sm_impl::esm) ].program = load_program("vs_clip_quad", "fs_deferred_spot_light_esm_linear");
1279
1280 color_lighting_no_shadow_[uint8_t(light_type::point)].program = load_program("vs_clip_quad", "fs_deferred_point_light");
1281 color_lighting_[uint8_t(light_type::point)][uint8_t(sm_depth::invz)][uint8_t(sm_impl::hard)].program = load_program("vs_clip_quad", "fs_deferred_point_light_hard");
1282 color_lighting_[uint8_t(light_type::point)][uint8_t(sm_depth::invz)][uint8_t(sm_impl::pcf) ].program = load_program("vs_clip_quad", "fs_deferred_point_light_pcf");
1283 color_lighting_[uint8_t(light_type::point)][uint8_t(sm_depth::invz)][uint8_t(sm_impl::pcss) ].program = load_program("vs_clip_quad", "fs_deferred_point_light_pcss");
1284 color_lighting_[uint8_t(light_type::point)][uint8_t(sm_depth::invz)][uint8_t(sm_impl::vsm) ].program = load_program("vs_clip_quad", "fs_deferred_point_light_vsm");
1285 color_lighting_[uint8_t(light_type::point)][uint8_t(sm_depth::invz)][uint8_t(sm_impl::esm) ].program = load_program("vs_clip_quad", "fs_deferred_point_light_esm");
1286
1287 color_lighting_[uint8_t(light_type::point)][uint8_t(sm_depth::linear)][uint8_t(sm_impl::hard)].program = load_program("vs_clip_quad", "fs_deferred_point_light_hard_linear");
1288 color_lighting_[uint8_t(light_type::point)][uint8_t(sm_depth::linear)][uint8_t(sm_impl::pcf) ].program = load_program("vs_clip_quad", "fs_deferred_point_light_pcf_linear");
1289 color_lighting_[uint8_t(light_type::point)][uint8_t(sm_depth::linear)][uint8_t(sm_impl::pcss) ].program = load_program("vs_clip_quad", "fs_deferred_point_light_pcss_linear");
1290 color_lighting_[uint8_t(light_type::point)][uint8_t(sm_depth::linear)][uint8_t(sm_impl::vsm) ].program = load_program("vs_clip_quad", "fs_deferred_point_light_vsm_linear");
1291 color_lighting_[uint8_t(light_type::point)][uint8_t(sm_depth::linear)][uint8_t(sm_impl::esm) ].program = load_program("vs_clip_quad", "fs_deferred_point_light_esm_linear");
1292
1293 color_lighting_no_shadow_[uint8_t(light_type::directional)].program = load_program("vs_clip_quad", "fs_deferred_directional_light");
1294 color_lighting_[uint8_t(light_type::directional)][uint8_t(sm_depth::invz)][uint8_t(sm_impl::hard)].program = load_program("vs_clip_quad", "fs_deferred_directional_light_hard");
1295 color_lighting_[uint8_t(light_type::directional)][uint8_t(sm_depth::invz)][uint8_t(sm_impl::pcf) ].program = load_program("vs_clip_quad", "fs_deferred_directional_light_pcf");
1296 color_lighting_[uint8_t(light_type::directional)][uint8_t(sm_depth::invz)][uint8_t(sm_impl::pcss) ].program = load_program("vs_clip_quad", "fs_deferred_directional_light_pcss");
1297 color_lighting_[uint8_t(light_type::directional)][uint8_t(sm_depth::invz)][uint8_t(sm_impl::vsm) ].program = load_program("vs_clip_quad", "fs_deferred_directional_light_vsm");
1298 color_lighting_[uint8_t(light_type::directional)][uint8_t(sm_depth::invz)][uint8_t(sm_impl::esm) ].program = load_program("vs_clip_quad", "fs_deferred_directional_light_esm");
1299
1300 color_lighting_[uint8_t(light_type::directional)][uint8_t(sm_depth::linear)][uint8_t(sm_impl::hard)].program = load_program("vs_clip_quad", "fs_deferred_directional_light_hard_linear");
1301 color_lighting_[uint8_t(light_type::directional)][uint8_t(sm_depth::linear)][uint8_t(sm_impl::pcf) ].program = load_program("vs_clip_quad", "fs_deferred_directional_light_pcf_linear");
1302 color_lighting_[uint8_t(light_type::directional)][uint8_t(sm_depth::linear)][uint8_t(sm_impl::pcss) ].program = load_program("vs_clip_quad", "fs_deferred_directional_light_pcss_linear");
1303 color_lighting_[uint8_t(light_type::directional)][uint8_t(sm_depth::linear)][uint8_t(sm_impl::vsm) ].program = load_program("vs_clip_quad", "fs_deferred_directional_light_vsm_linear");
1304 color_lighting_[uint8_t(light_type::directional)][uint8_t(sm_depth::linear)][uint8_t(sm_impl::esm) ].program = load_program("vs_clip_quad", "fs_deferred_directional_light_esm_linear");
1305 // clang-format on
1306
1307 for(auto& byLightType : color_lighting_no_shadow_)
1308 {
1309 if(byLightType.program)
1310 {
1311 byLightType.cache_uniforms();
1312 }
1313 }
1314 for(auto& byLightType : color_lighting_)
1315 {
1316 for(auto& byDepthType : byLightType)
1317 {
1318 for(auto& bySmImpl : byDepthType)
1319 {
1320 if(bySmImpl.program)
1321 {
1322 bySmImpl.cache_uniforms();
1323 }
1324 }
1325 }
1326 }
1327
1328 ibl_brdf_lut_ = am.get_asset<gfx::texture>("engine:/data/textures/ibl_brdf_lut.png");
1329
1330 return pipeline::init(ctx);
1331}
1332
1334{
1335 return true;
1336}
1337} // namespace rendering
1338} // namespace unravel
btVector3 normal
auto fbo_safe_get(const hpp::string_view &id) const -> const frame_buffer::ptr &
auto fbo_get_or_emplace(const hpp::string_view &id) -> frame_buffer::ptr &
auto fbo_get(const hpp::string_view &id) const -> const frame_buffer::ptr &
auto tex_get_or_emplace(const hpp::string_view &id) -> texture::ptr &
General purpose transformation class designed to maintain each component of the transformation separa...
Definition transform.hpp:27
void run(const camera &camera, gfx::render_view &rview, const run_params &params)
Manages assets, including loading, unloading, and storage.
auto run(const run_params &params) -> gfx::frame_buffer::ptr
Executes the blit: copies params.input → params.output. Returns the actual output framebuffer.
Definition blit_pass.cpp:85
Class representing a camera. Contains functionality for manipulating and updating a camera....
Definition camera.h:35
auto get_far_clip() const -> float
Retrieves the distance from the camera to the far clip plane.
Definition camera.cpp:67
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_viewport_size() const -> const usize32_t &
Retrieves the size of the viewport.
Definition camera.cpp:35
auto get_projection() const -> const math::transform &
Retrieves the current projection matrix.
Definition camera.cpp:203
static auto get_face_camera(std::uint32_t face, const math::transform &transform) -> camera
Retrieves a camera for one of six cube faces.
Definition camera.cpp:822
auto get_view() const -> const math::transform &
Retrieves the current view matrix.
Definition camera.cpp:276
void set_far_clip(float distance)
Sets the far plane distance.
Definition camera.cpp:125
auto get_position() const -> const math::vec3 &
Retrieves the current position of the camera.
Definition camera.cpp:346
void set_viewport_size(const usize32_t &viewportSize)
Sets the size of the viewport.
Definition camera.cpp:24
auto get_frustum() const -> const math::frustum &
Retrieves the current camera object frustum.
Definition camera.cpp:365
auto get_near_clip() const -> float
Retrieves the distance from the camera to the near clip plane.
Definition camera.cpp:62
Class that contains core light data, used for rendering and other purposes.
Base class for materials used in rendering.
Definition material.h:32
Main class representing a 3D mesh with support for different LODs, submeshes, and skinning.
Definition mesh.h:310
auto calculate_screen_rect(const math::transform &world, const camera &cam) const -> irect32_t
Calculates the screen rectangle of the mesh based on its world transform and the camera.
Definition mesh.cpp:1414
Class that contains core data for meshes.
Structure describing a LOD group (set of meshes), LOD transitions, and their materials.
Definition model.h:42
auto get_lod(uint32_t lod) const -> asset_handle< mesh >
Gets the LOD (Level of Detail) mesh for the specified level.
Definition model.cpp:14
auto is_valid() const -> bool
Checks if the model is valid.
Definition model.cpp:9
auto get_lod_limits() const -> const std::vector< urange32_t > &
Gets the LOD limits.
Definition model.cpp:183
void submit(const math::mat4 &world_transform, const pose_mat4 &submesh_transforms, const pose_mat4 &bone_transforms, const std::vector< pose_mat4 > &skinning_matrices, unsigned int lod, const submit_callbacks &callbacks) const
Submits the model for rendering.
Definition model.cpp:193
auto get_lods() const -> const std::vector< asset_handle< mesh > > &
Gets all the LOD meshes.
Definition model.cpp:76
Class for physically-based rendering (PBR) materials.
Definition material.h:100
auto get_surface_data2() const -> math::vec4
Gets additional surface data for the material.
Definition material.h:245
auto get_dither_threshold() const -> const math::vec2 &
Gets the dither threshold of the material.
Definition material.h:281
auto get_emissive_map() const -> const asset_handle< gfx::texture > &
Gets the emissive map of the material.
Definition material.h:389
auto get_subsurface_color() const -> const math::color &
Gets the subsurface color of the material.
Definition material.h:128
auto get_color_map() const -> const asset_handle< gfx::texture > &
Gets the color map of the material.
Definition material.h:299
auto get_surface_data() const -> const math::vec4 &
Gets the surface data of the material.
Definition material.h:236
auto get_roughness_map() const -> const asset_handle< gfx::texture > &
Gets the roughness map of the material.
Definition material.h:335
auto get_metalness_map() const -> const asset_handle< gfx::texture > &
Gets the metalness map of the material.
Definition material.h:353
auto get_tiling() const -> const math::vec2 &
Gets the tiling factor of the material.
Definition material.h:263
auto get_normal_map() const -> const asset_handle< gfx::texture > &
Gets the normal map of the material.
Definition material.h:317
auto get_base_color() const -> const math::color &
Gets the base color of the material.
Definition material.h:110
auto get_emissive_color() const -> const math::color &
Gets the emissive color of the material.
Definition material.h:146
auto get_ao_map() const -> const asset_handle< gfx::texture > &
Gets the ambient occlusion map of the material.
Definition material.h:371
auto run(const run_params &params) -> gfx::texture::ptr
Execute prefilter. Returns the filtered cubemap (output_cube or created internally).
Class that contains core reflection probe data, used for rendering and other purposes.
auto get_probe() const -> const reflection_probe &
Gets the reflection probe object.
auto deinit(rtti::context &ctx) -> bool
void set_debug_pass(int pass) override
Definition pipeline.cpp:525
void build_shadows(scene &scn, const camera &camera, visibility_flags query=visibility_query::not_specified, layer_mask render_mask=layer_mask{layer_reserved::everything_layer})
Definition pipeline.cpp:421
void run_assao_pass(const visibility_set_models_t &visibility_set, const camera &camera, gfx::render_view &rview, delta_t dt, const run_params &rparams)
Definition pipeline.cpp:727
void run_reflection_probe_pass(scene &scn, const camera &camera, gfx::render_view &rview, delta_t dt)
Definition pipeline.cpp:875
auto run_lighting_pass(scene &scn, const camera &camera, gfx::render_view &rview, bool apply_shadows, delta_t dt) -> gfx::frame_buffer::ptr
Definition pipeline.cpp:755
void run_debug_visualization_pass(const camera &camera, gfx::render_view &rview, const gfx::frame_buffer::ptr &output)
auto run_ssr_pass(const camera &camera, gfx::render_view &rview, const gfx::frame_buffer::ptr &output, const run_params &rparams) -> gfx::frame_buffer::ptr
void build_reflections(scene &scn, const camera &camera, delta_t dt)
Definition pipeline.cpp:335
auto run_fxaa_pass(gfx::render_view &rview, const gfx::frame_buffer::ptr &input, const gfx::frame_buffer::ptr &output, const run_params &rparams) -> gfx::frame_buffer::ptr
void run_g_buffer_pass(const visibility_set_models_t &visibility_set, const camera &camera, gfx::render_view &rview, delta_t dt)
Definition pipeline.cpp:597
auto run_atmospherics_pass(gfx::frame_buffer::ptr input, scene &scn, const camera &camera, gfx::render_view &rview, delta_t dt) -> gfx::frame_buffer::ptr
auto run_tonemapping_pass(gfx::render_view &rview, const gfx::frame_buffer::ptr &input, const gfx::frame_buffer::ptr &output, const run_params &rparams) -> gfx::frame_buffer::ptr
auto run_hiz_pass(const camera &camera, gfx::render_view &rview, delta_t dt) -> gfx::texture::ptr
auto init(rtti::context &ctx) -> bool override
auto run_pipeline(scene &scn, const camera &camera, gfx::render_view &rview, delta_t dt, const run_params &params, layer_mask render_mask=layer_mask{layer_reserved::everything_layer}) -> gfx::frame_buffer::ptr override
Renders the entire scene from the camera's perspective.
Definition pipeline.cpp:494
void run_pipeline_impl(const gfx::frame_buffer::ptr &output, scene &scn, const camera &camera, gfx::render_view &rview, delta_t dt, const run_params &params, pipeline_flags pflags, layer_mask render_mask=layer_mask{layer_reserved::everything_layer})
Definition pipeline.cpp:530
virtual auto init(rtti::context &ctx) -> bool
Definition pipeline.cpp:22
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:48
@ not_specified
No specific visibility query.
Definition pipeline.h:72
@ is_dirty
Query for dirty entities.
Definition pipeline.h:73
@ is_reflection_caster
Query for reflection casting entities.
Definition pipeline.h:76
@ is_shadow_caster
Query for shadow casting entities.
Definition pipeline.h:75
prefilter_pass prefilter_pass_
Definition pipeline.h:151
virtual void ui_pass(scene &scn, const camera &camera, gfx::render_view &rview, const gfx::frame_buffer::ptr &output)
Definition pipeline.cpp:177
uint32_t visibility_flags
Type alias for visibility flags.
Definition pipeline.h:79
virtual auto create_run_params(entt::handle camera_ent) const -> rendering::pipeline::run_params
Definition pipeline.cpp:118
Class that contains sky light data.
sky_mode
Enumeration for sky modes.
Component that handles transformations (position, rotation, scale, etc.) in the ACE framework.
auto get_transform_global() const noexcept -> const math::transform &
Gets the global transform.
size< std::uint32_t > usize32_t
std::chrono::duration< float > delta_t
#define APPLOG_WARNING(...)
Definition logging.h:19
Definition cache.hpp:11
void submit(view_id _id, program_handle _handle, int32_t _depth, bool _preserveState)
Definition graphics.cpp:899
uint16_t set_scissor(uint16_t _x, uint16_t _y, uint16_t _width, uint16_t _height)
Definition graphics.cpp:778
void set_state(uint64_t _state, uint32_t _rgba)
Definition graphics.cpp:763
void discard(uint8_t _flags)
Definition graphics.cpp:968
void set_uniform(uniform_handle _handle, const void *_value, uint16_t _num)
Definition graphics.cpp:803
uint32_t get_render_frame()
auto clip_quad(float depth, float width, float height) -> uint64_t
void set_texture(uint8_t _stage, uniform_handle _sampler, texture_handle _handle, uint32_t _flags)
Definition graphics.cpp:889
auto inverse(transform_t< T, Q > const &t) noexcept -> transform_t< T, Q >
hpp::small_vector< entt::handle > visibility_set_models_t
Definition pipeline.h:44
@ everything_layer
Definition layer_mask.h:16
@ sphere
Sphere type reflection probe.
@ box
Box type reflection probe.
@ environment
Environment reflection method.
#define APP_SCOPE_PERF(name)
Create a scoped performance timer that only accepts string literals.
Definition profiler.h:160
entt::entity entity
Represents a handle to an asset, providing access and management functions.
auto is() const -> bool
static void pop_scope()
void set_view_proj(const float *v, const float *p)
gfx::view_id id
Definition render_pass.h:98
void clear(uint16_t _flags, uint32_t _rgba=0x000000ff, float _depth=1.0f, uint8_t _stencil=0) const
static void push_scope(const char *name)
void bind(const frame_buffer *fb=nullptr) const
Storage for box vector values and wraps up common functionality.
Definition bbox.h:21
bbox & mul(const transform &t)
Transforms an axis aligned bounding box by the specified matrix.
Definition bbox.cpp:876
vec4 value
Definition math.h:354
std::uint32_t value_type
Definition basetypes.hpp:11
bool contains(const T &val) const
Definition basetypes.hpp:25
T width() const
std::int32_t value_type
T height() const
T width
Definition basetypes.hpp:55
T height
Definition basetypes.hpp:56
gfx::frame_buffer::ptr input
Source framebuffer (must have a color texture).
Definition blit_pass.h:18
gfx::frame_buffer::ptr output
Optional destination framebuffer. If null, will be created to match input.
Definition blit_pass.h:19
static auto context() -> rtti::context &
Definition engine.cpp:115
gfx::frame_buffer::ptr output
Definition fxaa_pass.h:18
gfx::frame_buffer::ptr input
Definition fxaa_pass.h:17
gfx::texture::ptr depth_buffer
Source depth buffer.
Definition hiz_pass.h:19
const camera * cam
Camera for near/far plane information.
Definition hiz_pass.h:21
gfx::texture::ptr output_hiz
Output Hi-Z texture (must be R32F or R16F format with mips)
Definition hiz_pass.h:20
float range
The range of the point light.
Definition light.h:162
float exponent_falloff
The exponent falloff for the point light.
Definition light.h:164
float get_range() const
Gets the range of the spot light.
Definition light.h:106
float get_outer_angle() const
Gets the outer angle of the spot light.
Definition light.h:121
float get_inner_angle() const
Gets the inner angle of the spot light.
Definition light.h:136
Struct representing a light.
Definition light.h:87
bool casts_shadows
Whether the light casts shadows.
Definition light.h:215
float intensity
The intensity of the light.
Definition light.h:209
light_type type
The type of the light.
Definition light.h:89
math::color color
The color of the light.
Definition light.h:207
point point_data
Data specific to point lights.
Definition light.h:203
float ambient_intensity
The ambient intensity of the light.
Definition light.h:212
spot spot_data
Data specific to spot lights.
Definition light.h:201
Parameters for the submit callbacks.
Definition model.h:132
bool skinned
Indicates if the model is skinned.
Definition model.h:134
Callbacks for submitting the model for rendering.
Definition model.h:126
std::function< void(const params &info, const material &)> setup_params_per_submesh
Callback for setting up per submesh.
Definition model.h:143
std::function< void(const params &info)> setup_begin
Callback for setup begin.
Definition model.h:139
std::function< void(const params &info)> setup_params_per_instance
Callback for setting up per instance.
Definition model.h:141
std::function< void(const params &info)> setup_end
Callback for setup end.
Definition model.h:145
std::array< gfx::texture::ptr, 6 > input_faces
gfx::texture::ptr output_cube_prefiltered
Optional destination cubemap (will be created if null).
gfx::texture::ptr output_cube
Optional destination cubemap (will be created if null).
bool apply_prefilter
If false, copies mips from input to output.
Contains level of detail (LOD) data for an entity.
Definition pipeline.h:37
float current_time
Current time for LOD transition.
Definition pipeline.h:40
std::uint32_t target_lod_index
Target LOD index.
Definition pipeline.h:39
std::uint32_t current_lod_index
Current LOD index.
Definition pipeline.h:38
std::function< void(assao_pass::run_params &params)> fill_assao_params
Definition pipeline.h:85
std::function< void(tonemapping_pass::run_params &params)> fill_hdr_params
Definition pipeline.h:86
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
auto create_handle(entt::entity e) -> entt::handle
Creates an entity in the scene.
Definition scene.cpp:304
bool enable_cone_tracing
Enable cone tracing for glossy reflections.
Definition ssr_pass.h:51
gfx::frame_buffer::ptr output
Optional output buffer.
Definition ssr_pass.h:68
gfx::texture::ptr previous_frame
Previous frame color for reflection sampling.
Definition ssr_pass.h:71
gfx::frame_buffer::ptr g_buffer
G-buffer containing normals.
Definition ssr_pass.h:69
gfx::texture::ptr hiz_buffer
Hi-Z buffer texture.
Definition ssr_pass.h:70
fidelityfx_ssr_settings fidelityfx
FidelityFX SSR settings.
Definition ssr_pass.h:63
gfx::uniform_handle handle
Definition uniform.cpp:9