Antkeeper  0.0.1
sky-pass.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2023 Christopher J. Howard
3  *
4  * This file is part of Antkeeper source code.
5  *
6  * Antkeeper source code is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Antkeeper source code is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
27 #include <engine/gl/texture.hpp>
30 #include <engine/render/model.hpp>
32 #include <engine/scene/camera.hpp>
33 #include <engine/math/vector.hpp>
34 #include <engine/color/color.hpp>
38 #include <bit>
39 #include <cmath>
40 #include <stdexcept>
41 
42 namespace render {
43 
45  pass(pipeline, framebuffer),
46  mouse_position({0.0f, 0.0f}),
47  sky_model(nullptr),
48  sky_material(nullptr),
49  sky_model_vao(nullptr),
50  moon_model(nullptr),
51  moon_model_vao(nullptr),
52  moon_material(nullptr),
53  moon_shader_program(nullptr),
54  stars_model(nullptr),
55  stars_model_vao(nullptr),
56  star_material(nullptr),
57  star_shader_program(nullptr),
58  observer_position_tween({0, 0, 0}, math::lerp<math::fvec3, float>),
59  sun_position_tween(math::fvec3{1.0f, 0.0f, 0.0f}, math::lerp<math::fvec3, float>),
60  sun_luminance_tween(math::fvec3{0.0f, 0.0f, 0.0f}, math::lerp<math::fvec3, float>),
61  sun_illuminance_tween(math::fvec3{0.0f, 0.0f, 0.0f}, math::lerp<math::fvec3, float>),
62  icrf_to_eus_translation({0, 0, 0}, math::lerp<math::fvec3, float>),
63  icrf_to_eus_rotation(math::fquat::identity(), math::nlerp<float>),
64  moon_position_tween(math::fvec3{0, 0, 0}, math::lerp<math::fvec3, float>),
65  moon_rotation_tween(math::fquat::identity(), math::nlerp<float>),
66  moon_angular_radius_tween(0.0f, math::lerp<float, float>),
67  moon_sunlight_direction_tween(math::fvec3{0, 0, 0}, math::lerp<math::fvec3, float>),
68  moon_sunlight_illuminance_tween(math::fvec3{0, 0, 0}, math::lerp<math::fvec3, float>),
69  moon_planetlight_direction_tween(math::fvec3{0, 0, 0}, math::lerp<math::fvec3, float>),
70  moon_planetlight_illuminance_tween(math::fvec3{0, 0, 0}, math::lerp<math::fvec3, float>),
71  moon_illuminance_tween(math::fvec3{0.0f, 0.0f, 0.0f}, math::lerp<math::fvec3, float>),
72  magnification(1.0f)
73 {
74  // Construct LUT sampler
75  m_lut_sampler = std::make_shared<gl::sampler>
76  (
82  );
83 
84  // Construct empty vertex array
85  m_vertex_array = std::make_unique<gl::vertex_array>();
86 
87  // Transmittance LUT
88  {
89  // Construct transmittance LUT texture and framebuffer
90  rebuild_transmittance_lut_framebuffer();
91 
92  // Load transmittance LUT shader template
93  m_transmittance_lut_shader_template = resource_manager->load<gl::shader_template>("sky-transmittance-lut.glsl");
94 
95  // Build transmittance LUT shader program
96  rebuild_transmittance_lut_shader_program();
97 
98  // Build transmittance LUT command buffer
99  rebuild_transmittance_lut_command_buffer();
100  }
101 
102  // Multiscattering LUT
103  {
104  // Construct multiscattering LUT texture and framebuffer
105  rebuild_multiscattering_lut_framebuffer();
106 
107  // Load multiscattering LUT shader template
108  m_multiscattering_lut_shader_template = resource_manager->load<gl::shader_template>("sky-multiscattering-lut.glsl");
109 
110  // Build multiscattering LUT shader program
111  rebuild_multiscattering_lut_shader_program();
112 
113  // Build multiscattering LUT command buffer
114  rebuild_multiscattering_lut_command_buffer();
115  }
116 
117  // Luminance LUT
118  {
119  // Construct luminance LUT texture and framebuffer
120  rebuild_luminance_lut_framebuffer();
121 
122  // Load luminance LUT shader template
123  m_luminance_lut_shader_template = resource_manager->load<gl::shader_template>("sky-luminance-lut.glsl");
124 
125  // Build luminance LUT shader program
126  rebuild_luminance_lut_shader_program();
127 
128  // Build luminance LUT command buffer
129  rebuild_luminance_lut_command_buffer();
130  }
131 
132  // Load sky probe shader template
133  m_sky_probe_shader_template = resource_manager->load<gl::shader_template>("sky-probe.glsl");
134 
135  // Build sky probe shader program
136  m_sky_probe_shader_program = m_sky_probe_shader_template->build({});
137  if (!m_sky_probe_shader_program->linked())
138  {
139  debug::log_error("Failed to build sky probe shader program: {}", m_sky_probe_shader_program->info());
140  debug::log_warning("{}", m_sky_probe_shader_template->configure(gl::shader_stage::vertex));
141  }
142 
143  // Load moon textures
144  m_moon_albedo_map = resource_manager->load<gl::texture_2d>("moon-albedo.tex");
145  m_moon_normal_map = resource_manager->load<gl::texture_2d>("moon-normal.tex");
146 }
147 
149 {
150  if (!(m_layer_mask & ctx.camera->get_layer_mask()))
151  {
152  return;
153  }
154 
158 
159  // Render transmittance LUT (if parameters have changed)
160  if (m_render_transmittance_lut)
161  {
162  for (const auto& command: m_transmittance_lut_command_buffer)
163  {
164  command();
165  }
166 
167  m_render_transmittance_lut = false;
168  }
169 
170  // Render multiscattering LUT (if parameters have changed)
171  if (m_render_multiscattering_lut)
172  {
173  for (const auto& command: m_multiscattering_lut_command_buffer)
174  {
175  command();
176  }
177 
178  m_render_multiscattering_lut = false;
179  }
180 
181  // Construct matrices
182  const scene::camera& camera = *ctx.camera;
183  math::fvec3 model_scale = math::fvec3{1.0f, 1.0f, 1.0f} * camera.get_clip_near() * 2.0f;
184  math::fmat4 model = math::scale(model_scale);
185  math::fmat4 view = math::fmat4(math::fmat3(camera.get_view()));
186  math::fmat4 model_view = view * model;
187  const math::fmat4& projection = camera.get_projection();
188  math::fmat4 view_projection = projection * view;
189  math::fmat4 model_view_projection = projection * model_view;
190  camera_exposure = camera.get_exposure_normalization();
191 
192  // Interpolate observer position
193  observer_position = observer_position_tween.interpolate(ctx.alpha);
194 
195  // Construct tweened ICRF to EUS transformation
196  math::se3<float> icrf_to_eus =
197  {
198  icrf_to_eus_translation.interpolate(ctx.alpha),
199  icrf_to_eus_rotation.interpolate(ctx.alpha)
200  };
201 
202  // Get EUS direction to sun
203  math::fvec3 sun_position = sun_position_tween.interpolate(ctx.alpha);
204  math::fvec3 sun_direction = math::normalize(sun_position);
205 
206  // Interpolate and expose sun luminance and illuminance
207  math::fvec3 sun_illuminance = sun_illuminance_tween.interpolate(ctx.alpha) * camera_exposure;
208  math::fvec3 sun_luminance = sun_luminance_tween.interpolate(ctx.alpha) * camera_exposure;
209 
210  math::fvec3 moon_position = moon_position_tween.interpolate(ctx.alpha);
211  math::fvec3 moon_direction = math::normalize(moon_position);
212  math::fvec3 moon_illuminance = moon_illuminance_tween.interpolate(ctx.alpha) * camera_exposure;
213  float moon_angular_radius = moon_angular_radius_tween.interpolate(ctx.alpha) * magnification;
214 
215  // if (math::max(sun_illuminance) > math::max(moon_illuminance))
216  // {
217  dominant_light_direction = sun_direction;
218  dominant_light_illuminance = sun_illuminance;
219  // }
220  // else
221  // {
222  // dominant_light_direction = moon_direction;
223  // dominant_light_illuminance = moon_illuminance;
224  // }
225 
226 
227  // Render luminance LUT
228  // if (m_render_luminance_lut)
229  {
230  for (const auto& command: m_luminance_lut_command_buffer)
231  {
232  command();
233  }
234  }
235 
236  // Render sky probe
237  for (const auto& command: m_sky_probe_command_buffer)
238  {
239  command();
240  }
241 
244 
245  // Check if any corner of the view frustum is looking at or above the horizon
246  bool sky_visible =
247  (camera.pick(math::fvec2{-1, 1}).direction.y() > 0.0f) ||
248  (camera.pick(math::fvec2{-1, -1}).direction.y() > 0.0f) ||
249  (camera.pick(math::fvec2{ 1, 1}).direction.y() > 0.0f) ||
250  (camera.pick(math::fvec2{ 1, -1}).direction.y() > 0.0f);
251  if (!sky_visible)
252  {
253  // Sky not visible, abort
254  return;
255  }
256 
257  const auto& viewport_dimensions = (m_framebuffer) ? m_framebuffer->dimensions() : m_pipeline->get_default_framebuffer_dimensions();
258  const gl::viewport viewport[1] =
259  {{
260  0.0f,
261  0.0f,
262  static_cast<float>(viewport_dimensions[0]),
263  static_cast<float>(viewport_dimensions[1])
264  }};
265  m_pipeline->set_viewport(0, viewport);
266  math::fvec2 resolution = {viewport[0].width, viewport[1].height};
267 
268  // Draw atmosphere
269  if (sky_model && sky_shader_program)
270  {
271  m_pipeline->bind_shader_program(sky_shader_program.get());
272 
273  // Upload shader parameters
274  if (model_view_projection_var)
275  model_view_projection_var->update(model_view_projection);
276  if (view_var)
277  {
278  view_var->update(view);
279  }
280  if (view_projection_var)
281  {
282  view_projection_var->update(view_projection);
283  }
284  if (inv_view_projection_var)
285  {
286  const auto inv_view_projection = math::fmat4(math::fmat3(camera.get_inv_view())) * camera.get_inv_projection();
287  inv_view_projection_var->update(inv_view_projection);
288  // inv_view_projection_var->update(camera.get_inv_view_projection());
289  }
290  if (camera_position_var)
291  {
292  camera_position_var->update(camera.get_translation());
293  }
294  if (mouse_var)
295  mouse_var->update(mouse_position);
296  if (resolution_var)
297  resolution_var->update(resolution);
298  if (light_direction_var)
299  light_direction_var->update(dominant_light_direction);
300  if (sun_luminance_var)
301  sun_luminance_var->update(sun_luminance);
302  if (sun_angular_radius_var)
303  sun_angular_radius_var->update(sun_angular_radius * magnification);
304  if (atmosphere_radii_var)
305  atmosphere_radii_var->update(atmosphere_radii);
306  if (observer_position_var)
307  observer_position_var->update(observer_position);
308  if (sky_transmittance_lut_var)
309  sky_transmittance_lut_var->update(*m_transmittance_lut_texture);
310  if (sky_transmittance_lut_resolution_var)
311  sky_transmittance_lut_resolution_var->update(math::fvec2(m_transmittance_lut_resolution));
312  if (sky_luminance_lut_var)
313  sky_luminance_lut_var->update(*m_luminance_lut_texture);
314  if (sky_luminance_lut_resolution_var)
315  sky_luminance_lut_resolution_var->update(math::fvec2(m_luminance_lut_resolution));
316 
317  m_pipeline->set_primitive_topology(sky_model_primitive_topology);
318  m_pipeline->bind_vertex_array(sky_model_vao);
319  m_pipeline->bind_vertex_buffers(0, {&sky_model_vbo, 1}, {&sky_model_vertex_offset, 1}, {&sky_model_vertex_stride, 1});
320  m_pipeline->draw(sky_model_vertex_count, 1, sky_model_first_vertex, 0);
321  }
322 
323  // Enable additive blending
326  ({
333  });
334 
335  // Flag moon pixels in stencil buffer
341  (
347  );
348 
349  // Draw moon model
350  //if (moon_position.y() >= -moon_angular_radius)
351  if (moon_shader_program)
352  {
353  float moon_distance = camera.get_clip_near() * 2.0f;
354  float moon_radius = moon_angular_radius * moon_distance;
355 
356  math::transform<float> moon_transform;
357  moon_transform.translation = math::normalize(moon_position) * moon_distance;
358  moon_transform.rotation = moon_rotation_tween.interpolate(ctx.alpha);
359  moon_transform.scale = {moon_radius, moon_radius, moon_radius};
360 
361  model = moon_transform.matrix();
363 
364  m_pipeline->bind_shader_program(moon_shader_program.get());
365  if (moon_model_var)
366  moon_model_var->update(model);
367  if (moon_view_projection_var)
368  moon_view_projection_var->update(view_projection);
369  if (moon_normal_model_var)
370  moon_normal_model_var->update(normal_model);
371  if (moon_camera_position_var)
372  moon_camera_position_var->update(camera.get_translation());
373  if (moon_sunlight_direction_var)
374  moon_sunlight_direction_var->update(math::normalize(moon_sunlight_direction_tween.interpolate(ctx.alpha)));
375  if (moon_sunlight_illuminance_var)
376  moon_sunlight_illuminance_var->update(moon_sunlight_illuminance_tween.interpolate(ctx.alpha) * camera_exposure);
377  if (moon_planetlight_direction_var)
378  moon_planetlight_direction_var->update(math::normalize(moon_planetlight_direction_tween.interpolate(ctx.alpha)));
379  if (moon_planetlight_illuminance_var)
380  moon_planetlight_illuminance_var->update(moon_planetlight_illuminance_tween.interpolate(ctx.alpha) * camera_exposure);
381  if (moon_albedo_map_var && m_moon_albedo_map)
382  moon_albedo_map_var->update(*m_moon_albedo_map);
383  if (moon_normal_map_var && m_moon_normal_map)
384  moon_normal_map_var->update(*m_moon_normal_map);
385  if (moon_observer_position_var)
386  moon_observer_position_var->update(observer_position);
387  if (moon_sky_transmittance_lut_var)
388  moon_sky_transmittance_lut_var->update(*m_transmittance_lut_texture);
389  if (moon_atmosphere_radii_var)
390  moon_atmosphere_radii_var->update(atmosphere_radii);
391 
392  m_pipeline->set_primitive_topology(moon_model_primitive_topology);
393  m_pipeline->bind_vertex_array(moon_model_vao);
394  m_pipeline->bind_vertex_buffers(0, {&moon_model_vbo, 1}, {&moon_model_vertex_offset, 1}, {&moon_model_vertex_stride, 1});
395  m_pipeline->draw(moon_model_vertex_count, 1, moon_model_first_vertex, 0);
396  }
397 
398  // Prevent stars from being drawn in front of the moon
401  (
407  );
408 
409  // Draw stars
410  if (star_shader_program)
411  {
412  float star_distance = camera.get_clip_near() * 2.0f;
413 
414  model = math::fmat4(math::fmat3(icrf_to_eus.r)) * math::scale(math::fvec3{star_distance, star_distance, star_distance});
415 
416  model_view_projection = view_projection * model;
417 
418  m_pipeline->bind_shader_program(star_shader_program.get());
419  if (star_model_view_projection_var)
420  star_model_view_projection_var->update(model_view_projection);
421  if (star_exposure_var)
422  star_exposure_var->update(camera_exposure);
423  if (star_inv_resolution_var)
424  star_inv_resolution_var->update(1.0f / resolution);
425 
426  m_pipeline->set_primitive_topology(stars_model_primitive_topology);
427  m_pipeline->bind_vertex_array(stars_model_vao);
428  m_pipeline->bind_vertex_buffers(0, {&stars_model_vbo, 1}, {&stars_model_vertex_offset, 1}, {&stars_model_vertex_stride, 1});
429  m_pipeline->draw(stars_model_vertex_count, 1, stars_model_first_vertex, 0);
430  }
431 
433 }
434 
436 {
437  if (m_transmittance_lut_sample_count != count)
438  {
439  m_transmittance_lut_sample_count = count;
440 
441  // Rebuild transmittance LUT shader program and command buffer
442  rebuild_transmittance_lut_shader_program();
443  rebuild_transmittance_lut_command_buffer();
444 
445  // Trigger rendering of transmittance LUT
446  m_render_transmittance_lut = true;
447  }
448 }
449 
451 {
452  if (m_transmittance_lut_resolution.x() != resolution.x() || m_transmittance_lut_resolution.y() != resolution.y())
453  {
454  m_transmittance_lut_resolution = resolution;
455 
456  rebuild_transmittance_lut_framebuffer();
457 
458  // Trigger rendering of transmittance LUT
459  m_render_transmittance_lut = true;
460  }
461 }
462 
464 {
465  if (m_multiscattering_lut_direction_sample_count != count)
466  {
467  m_multiscattering_lut_direction_sample_count = count;
468 
469  // Rebuild multiscattering LUT shader program and command buffer
470  rebuild_multiscattering_lut_shader_program();
471  rebuild_multiscattering_lut_command_buffer();
472 
473  // Trigger rendering of multiscattering LUT
474  m_render_multiscattering_lut = true;
475  }
476 }
477 
479 {
480  if (m_multiscattering_lut_scatter_sample_count != count)
481  {
482  m_multiscattering_lut_scatter_sample_count = count;
483 
484  // Rebuild multiscattering LUT shader program and command buffer
485  rebuild_multiscattering_lut_shader_program();
486  rebuild_multiscattering_lut_command_buffer();
487 
488  // Trigger rendering of multiscattering LUT
489  m_render_multiscattering_lut = true;
490  }
491 }
492 
494 {
495  if (m_multiscattering_lut_resolution.x() != resolution.x() || m_multiscattering_lut_resolution.y() != resolution.y())
496  {
497  m_multiscattering_lut_resolution = resolution;
498 
499  rebuild_multiscattering_lut_framebuffer();
500 
501  // Trigger rendering of multiscattering LUT
502  m_render_multiscattering_lut = true;
503  }
504 }
505 
507 {
508  if (m_luminance_lut_sample_count != count)
509  {
510  m_luminance_lut_sample_count = count;
511 
512  // Rebuild luminance LUT shader program and command buffer
513  rebuild_luminance_lut_shader_program();
514  rebuild_luminance_lut_command_buffer();
515 
516  // Trigger rendering of luminance LUT
517  m_render_luminance_lut = true;
518  }
519 }
520 
522 {
523  if (m_luminance_lut_resolution.x() != resolution.x() || m_luminance_lut_resolution.y() != resolution.y())
524  {
525  m_luminance_lut_resolution = resolution;
526 
527  rebuild_luminance_lut_framebuffer();
528 
529  // Trigger rendering of luminance LUT
530  m_render_luminance_lut = true;
531  }
532 }
533 
534 void sky_pass::set_sky_model(std::shared_ptr<render::model> model)
535 {
536  sky_model = model;
537  sky_shader_program = nullptr;
538 
539  if (sky_model)
540  {
541  sky_model_vao = model->get_vertex_array().get();
542  sky_model_vbo = model->get_vertex_buffer().get();
543 
544  for (const auto& group: model->get_groups())
545  {
546  sky_model_primitive_topology = group.primitive_topology;
547  sky_model_first_vertex = group.first_vertex;
548  sky_model_vertex_count = group.vertex_count;
549  sky_material = group.material.get();
550  }
551  sky_model_vertex_offset = sky_model->get_vertex_offset();
552  sky_model_vertex_stride = sky_model->get_vertex_stride();
553 
554  if (sky_material)
555  {
556  sky_shader_program = sky_material->get_shader_template()->build();
557 
558  if (sky_shader_program->linked())
559  {
560  model_view_projection_var = sky_shader_program->variable("model_view_projection");
561  view_var = sky_shader_program->variable("view");
562  view_projection_var = sky_shader_program->variable("view_projection");
563  inv_view_projection_var = sky_shader_program->variable("inv_view_projection");
564  camera_position_var = sky_shader_program->variable("camera_position");
565  mouse_var = sky_shader_program->variable("mouse");
566  resolution_var = sky_shader_program->variable("resolution");
567  light_direction_var = sky_shader_program->variable("light_direction");
568  sun_luminance_var = sky_shader_program->variable("sun_luminance");
569  sun_angular_radius_var = sky_shader_program->variable("sun_angular_radius");
570  atmosphere_radii_var = sky_shader_program->variable("atmosphere_radii");
571  observer_position_var = sky_shader_program->variable("observer_position");
572  sky_transmittance_lut_var = sky_shader_program->variable("sky_transmittance_lut");
573  sky_transmittance_lut_resolution_var = sky_shader_program->variable("sky_transmittance_lut_resolution");
574  sky_luminance_lut_var = sky_shader_program->variable("sky_luminance_lut");
575  sky_luminance_lut_resolution_var = sky_shader_program->variable("sky_luminance_lut_resolution");
576  }
577  else
578  {
579  debug::log_error("Failed to build sky shader program: {}", sky_shader_program->info());
580  debug::log_warning("{}", sky_material->get_shader_template()->configure(gl::shader_stage::vertex));
581  }
582  }
583  }
584  else
585  {
586  sky_model_vao = nullptr;
587  }
588 }
589 
590 void sky_pass::set_moon_model(std::shared_ptr<render::model> model)
591 {
592  moon_model = model;
593  moon_shader_program = nullptr;
594 
595  if (moon_model)
596  {
597  moon_model_vao = model->get_vertex_array().get();
598  moon_model_vbo = model->get_vertex_buffer().get();
599 
600  for (const auto& group: model->get_groups())
601  {
602  moon_model_primitive_topology = group.primitive_topology;
603  moon_model_first_vertex = group.first_vertex;
604  moon_model_vertex_count = group.vertex_count;
605  moon_material = group.material.get();
606  }
607  moon_model_vertex_offset = moon_model->get_vertex_offset();
608  moon_model_vertex_stride = moon_model->get_vertex_stride();
609 
610  if (moon_material)
611  {
612  moon_shader_program = moon_material->get_shader_template()->build();
613 
614  if (moon_shader_program->linked())
615  {
616  moon_model_var = moon_shader_program->variable("model");
617  moon_view_projection_var = moon_shader_program->variable("view_projection");
618  moon_normal_model_var = moon_shader_program->variable("normal_model");
619  moon_camera_position_var = moon_shader_program->variable("camera_position");
620  moon_sunlight_direction_var = moon_shader_program->variable("sunlight_direction");
621  moon_sunlight_illuminance_var = moon_shader_program->variable("sunlight_illuminance");
622  moon_planetlight_direction_var = moon_shader_program->variable("planetlight_direction");
623  moon_planetlight_illuminance_var = moon_shader_program->variable("planetlight_illuminance");
624  moon_albedo_map_var = moon_shader_program->variable("albedo_map");
625  moon_normal_map_var = moon_shader_program->variable("normal_map");
626  moon_observer_position_var = moon_shader_program->variable("observer_position");
627  moon_sky_transmittance_lut_var = moon_shader_program->variable("sky_transmittance_lut");
628  moon_atmosphere_radii_var = moon_shader_program->variable("atmosphere_radii");
629  }
630  else
631  {
632  debug::log_error("Failed to build moon shader program: {}", moon_shader_program->info());
633  debug::log_warning("{}", moon_material->get_shader_template()->configure(gl::shader_stage::vertex));
634  }
635  }
636  }
637  else
638  {
639  moon_model = nullptr;
640  }
641 }
642 
643 void sky_pass::set_stars_model(std::shared_ptr<render::model> model)
644 {
645  stars_model = model;
646  star_shader_program = nullptr;
647 
648  if (stars_model)
649  {
650  stars_model_vao = model->get_vertex_array().get();
651  stars_model_vbo = model->get_vertex_buffer().get();
652 
653  for (const auto& group: model->get_groups())
654  {
655  stars_model_primitive_topology = group.primitive_topology;
656  stars_model_first_vertex = group.first_vertex;
657  stars_model_vertex_count = group.vertex_count;
658  star_material = group.material.get();
659  }
660  stars_model_vertex_offset = stars_model->get_vertex_offset();
661  stars_model_vertex_stride = stars_model->get_vertex_stride();
662 
663  if (star_material)
664  {
665  star_shader_program = star_material->get_shader_template()->build();
666 
667  if (star_shader_program->linked())
668  {
669  star_model_view_projection_var = star_shader_program->variable("model_view_projection");
670  star_exposure_var = star_shader_program->variable("camera_exposure");
671  star_inv_resolution_var = star_shader_program->variable("inv_resolution");
672  }
673  else
674  {
675  debug::log_error("Failed to build star shader program: {}", star_shader_program->info());
676  debug::log_warning("{}", star_material->get_shader_template()->configure(gl::shader_stage::vertex));
677  }
678  }
679  }
680  else
681  {
682  stars_model = nullptr;
683  }
684 }
685 
687 {
688  observer_position_tween.update();
689  sun_position_tween.update();
690  sun_luminance_tween.update();
691  sun_illuminance_tween.update();
692  icrf_to_eus_translation.update();
693  icrf_to_eus_rotation.update();
694 
695  moon_position_tween.update();
696  moon_rotation_tween.update();
697  moon_angular_radius_tween.update();
698  moon_sunlight_direction_tween.update();
699  moon_sunlight_illuminance_tween.update();
700  moon_planetlight_direction_tween.update();
701  moon_planetlight_illuminance_tween.update();
702  moon_illuminance_tween.update();
703 }
704 
705 void sky_pass::set_magnification(float magnification)
706 {
707  this->magnification = magnification;
708 }
709 
710 void sky_pass::set_icrf_to_eus(const math::se3<float>& transformation)
711 {
712  icrf_to_eus_translation[1] = transformation.t;
713  icrf_to_eus_rotation[1] = transformation.r;
714 }
715 
717 {
718  sun_position_tween[1] = position;
719 }
720 
721 void sky_pass::set_sun_illuminance(const math::fvec3& illuminance, const math::fvec3& transmitted_illuminance)
722 {
723  sun_illuminance_tween[1] = illuminance;
724  sun_transmitted_illuminance = transmitted_illuminance;
725 }
726 
728 {
729  sun_luminance_tween[1] = luminance;
730 }
731 
733 {
734  sun_angular_radius = radius;
735 }
736 
737 void sky_pass::set_planet_radius(float radius)
738 {
739  atmosphere_radii[0] = radius;
740  atmosphere_radii[1] = atmosphere_radii[0] + atmosphere_upper_limit;
741  atmosphere_radii[2] = atmosphere_radii[0] * atmosphere_radii[0];
742  atmosphere_radii[3] = atmosphere_radii[1] * atmosphere_radii[1];
743 
744  observer_position_tween[1] = {0.0f, atmosphere_radii.x() + observer_elevation, 0.0f};
745 
746  // Trigger transmittance and multiscattering LUT render
747  m_render_transmittance_lut = true;
748  m_render_multiscattering_lut = true;
749 }
750 
752 {
753  atmosphere_upper_limit = limit;
754  atmosphere_radii[1] = atmosphere_radii[0] + atmosphere_upper_limit;
755  atmosphere_radii[3] = atmosphere_radii[1] * atmosphere_radii[1];
756 
757  // Trigger transmittance and multiscattering LUT render
758  m_render_transmittance_lut = true;
759  m_render_multiscattering_lut = true;
760 }
761 
762 void sky_pass::set_observer_elevation(float elevation)
763 {
764  observer_elevation = elevation;
765  observer_position_tween[1] = {0.0f, atmosphere_radii.x() + observer_elevation, 0.0f};
766 }
767 
769 {
770  rayleigh_parameters =
771  {
772  -1.0f / scale_height,
773  scattering.x(),
774  scattering.y(),
775  scattering.z()
776  };
777 
778  // Trigger transmittance and multiscattering LUT render
779  m_render_transmittance_lut = true;
780  m_render_multiscattering_lut = true;
781 }
782 
783 void sky_pass::set_mie_parameters(float scale_height, float scattering, float extinction, float anisotropy)
784 {
785  mie_parameters =
786  {
787  -1.0f / scale_height,
788  scattering,
789  extinction,
790  anisotropy
791  };
792 
793  // Trigger transmittance and multiscattering LUT render
794  m_render_transmittance_lut = true;
795  m_render_multiscattering_lut = true;
796 }
797 
798 void sky_pass::set_ozone_parameters(float lower_limit, float upper_limit, float mode, const math::fvec3& absorption)
799 {
800  ozone_distribution =
801  {
802  1.0f / (lower_limit - mode),
803  1.0f / (upper_limit - mode),
804  mode
805  };
806  ozone_absorption = absorption;
807 
808  // Trigger transmittance and multiscattering LUT render
809  m_render_transmittance_lut = true;
810  m_render_multiscattering_lut = true;
811 }
812 
814 {
815  airglow_luminance = luminance;
816 }
817 
819 {
820  m_ground_albedo = albedo;
821 
822  // Trigger multiscattering LUT render
823  m_render_multiscattering_lut = true;
824 }
825 
827 {
828  moon_position_tween[1] = position;
829 }
830 
832 {
833  moon_rotation_tween[1] = rotation;
834 }
835 
837 {
838  moon_angular_radius_tween[1] = angular_radius;
839 }
840 
842 {
843  moon_sunlight_direction_tween[1] = direction;
844 }
845 
847 {
848  moon_sunlight_illuminance_tween[1] = illuminance;
849 }
850 
852 {
853  moon_planetlight_direction_tween[1] = direction;
854 }
855 
857 {
858  moon_planetlight_illuminance_tween[1] = illuminance;
859 }
860 
861 void sky_pass::set_moon_illuminance(const math::fvec3& illuminance, const math::fvec3& transmitted_illuminance)
862 {
863  moon_illuminance_tween[1] = illuminance;
864  moon_transmitted_illuminance = transmitted_illuminance;
865 }
866 
867 void sky_pass::set_sky_probe(std::shared_ptr<scene::light_probe> probe)
868 {
869  m_sky_probe = probe;
870 
871  if (m_sky_probe && m_sky_probe->get_luminance_texture())
872  {
873  const auto& luminance_texture = m_sky_probe->get_luminance_texture();
874 
875  const auto face_size = luminance_texture->get_image_view()->get_image()->get_dimensions()[0];
876  const auto mip_count = static_cast<std::uint32_t>(std::bit_width(face_size));
877 
878  m_sky_probe_framebuffers.resize(mip_count);
879  for (std::uint32_t i = 0; i < mip_count; ++i)
880  {
881  const gl::framebuffer_attachment attachments[1] =
882  {{
884  luminance_texture->get_image_view(),
885  i
886  }};
887  m_sky_probe_framebuffers[i] = std::make_unique<gl::framebuffer>(attachments, face_size >> i, face_size >> i);
888  }
889  }
890  else
891  {
892  m_sky_probe_framebuffers.clear();
893  }
894 
895  rebuild_sky_probe_command_buffer();
896 }
897 
898 void sky_pass::rebuild_transmittance_lut_framebuffer()
899 {
900  // Rebuild transmittance LUT texture
901  m_transmittance_lut_texture = std::make_shared<gl::texture_2d>
902  (
903  std::make_shared<gl::image_view_2d>
904  (
905  std::make_shared<gl::image_2d>
906  (
908  m_transmittance_lut_resolution.x(),
909  m_transmittance_lut_resolution.y()
910  )
911  ),
912  m_lut_sampler
913  );
914 
915  // Rebuild transmittance LUT framebuffer
916  const gl::framebuffer_attachment attachments[1] =
917  {{
919  m_transmittance_lut_texture->get_image_view(),
920  0
921  }};
922  m_transmittance_lut_framebuffer = std::make_shared<gl::framebuffer>(attachments, m_transmittance_lut_resolution.x(), m_transmittance_lut_resolution.y());
923 }
924 
925 void sky_pass::rebuild_transmittance_lut_shader_program()
926 {
927  m_transmittance_lut_shader_program = m_transmittance_lut_shader_template->build
928  (
929  {
930  {"SAMPLE_COUNT", std::to_string(m_transmittance_lut_sample_count)}
931  }
932  );
933  if (!m_transmittance_lut_shader_program->linked())
934  {
935  debug::log_error("Failed to build sky transmittance LUT shader program: {}", m_transmittance_lut_shader_program->info());
936  debug::log_warning("{}", m_transmittance_lut_shader_template->configure(gl::shader_stage::vertex));
937  }
938 }
939 
940 void sky_pass::rebuild_transmittance_lut_command_buffer()
941 {
942  m_transmittance_lut_command_buffer.clear();
943 
944  if (!m_transmittance_lut_shader_program->linked() || !m_transmittance_lut_texture)
945  {
946  return;
947  }
948 
949  // Bind framebuffer and shader program
950  m_transmittance_lut_command_buffer.emplace_back
951  (
952  [&]()
953  {
954  const gl::viewport viewport[1] =
955  {{
956  0.0f,
957  0.0f,
958  static_cast<float>(m_transmittance_lut_resolution.x()),
959  static_cast<float>(m_transmittance_lut_resolution.y())
960  }};
961  m_pipeline->set_viewport(0, viewport);
962 
963  m_pipeline->bind_framebuffer(m_transmittance_lut_framebuffer.get());
964  m_pipeline->bind_shader_program(m_transmittance_lut_shader_program.get());
965  }
966  );
967 
968  // Update shader variables
969  if (auto atmosphere_radii_var = m_transmittance_lut_shader_program->variable("atmosphere_radii"))
970  {
971  m_transmittance_lut_command_buffer.emplace_back([&, atmosphere_radii_var](){atmosphere_radii_var->update(atmosphere_radii);});
972  }
973  if (auto rayleigh_parameters_var = m_transmittance_lut_shader_program->variable("rayleigh_parameters"))
974  {
975  m_transmittance_lut_command_buffer.emplace_back([&, rayleigh_parameters_var](){rayleigh_parameters_var->update(rayleigh_parameters);});
976  }
977  if (auto mie_parameters_var = m_transmittance_lut_shader_program->variable("mie_parameters"))
978  {
979  m_transmittance_lut_command_buffer.emplace_back([&, mie_parameters_var](){mie_parameters_var->update(mie_parameters);});
980  }
981  if (auto ozone_distribution_var = m_transmittance_lut_shader_program->variable("ozone_distribution"))
982  {
983  m_transmittance_lut_command_buffer.emplace_back([&, ozone_distribution_var](){ozone_distribution_var->update(ozone_distribution);});
984  }
985  if (auto ozone_absorption_var = m_transmittance_lut_shader_program->variable("ozone_absorption"))
986  {
987  m_transmittance_lut_command_buffer.emplace_back([&, ozone_absorption_var](){ozone_absorption_var->update(ozone_absorption);});
988  }
989  if (auto resolution_var = m_transmittance_lut_shader_program->variable("resolution"))
990  {
991  m_transmittance_lut_command_buffer.emplace_back([&, resolution_var](){resolution_var->update(math::fvec2(m_transmittance_lut_resolution));});
992  }
993 
994  m_transmittance_lut_command_buffer.emplace_back
995  (
996  [&]()
997  {
998  // Draw fullscreen triangle
999  m_pipeline->bind_vertex_array(m_vertex_array.get());
1001  m_pipeline->draw(3, 1, 0, 0);
1002  }
1003  );
1004 }
1005 
1006 void sky_pass::rebuild_multiscattering_lut_framebuffer()
1007 {
1008  // Rebuild multiscattering LUT texture
1009  m_multiscattering_lut_texture = std::make_shared<gl::texture_2d>
1010  (
1011  std::make_shared<gl::image_view_2d>
1012  (
1013  std::make_shared<gl::image_2d>
1014  (
1016  m_multiscattering_lut_resolution.x(),
1017  m_multiscattering_lut_resolution.y()
1018  )
1019  ),
1020  m_lut_sampler
1021  );
1022 
1023  // Rebuild multiscattering LUT framebuffer and attach texture
1024  const gl::framebuffer_attachment attachments[1] =
1025  {{
1027  m_multiscattering_lut_texture->get_image_view(),
1028  0
1029  }};
1030  m_multiscattering_lut_framebuffer = std::make_shared<gl::framebuffer>(attachments, m_multiscattering_lut_resolution.x(), m_multiscattering_lut_resolution.y());
1031 }
1032 
1033 void sky_pass::rebuild_multiscattering_lut_shader_program()
1034 {
1035  m_multiscattering_lut_shader_program = m_multiscattering_lut_shader_template->build
1036  (
1037  {
1038  {"DIRECTION_SAMPLE_COUNT", std::to_string(m_multiscattering_lut_direction_sample_count)},
1039  {"SCATTER_SAMPLE_COUNT", std::to_string(m_multiscattering_lut_scatter_sample_count)}
1040  }
1041  );
1042  if (!m_multiscattering_lut_shader_program->linked())
1043  {
1044  debug::log_error("Failed to build sky multiscattering LUT shader program: {}", m_multiscattering_lut_shader_program->info());
1045  debug::log_warning("{}", m_multiscattering_lut_shader_template->configure(gl::shader_stage::vertex));
1046  }
1047 }
1048 
1049 void sky_pass::rebuild_multiscattering_lut_command_buffer()
1050 {
1051  m_multiscattering_lut_command_buffer.clear();
1052 
1053  if (!m_multiscattering_lut_shader_program->linked() || !m_multiscattering_lut_texture)
1054  {
1055  return;
1056  }
1057 
1058  // Bind framebuffer and shader program
1059  m_multiscattering_lut_command_buffer.emplace_back
1060  (
1061  [&]()
1062  {
1063  const gl::viewport viewport[1] =
1064  {{
1065  0.0f,
1066  0.0f,
1067  static_cast<float>(m_multiscattering_lut_resolution.x()),
1068  static_cast<float>(m_multiscattering_lut_resolution.y())
1069  }};
1070  m_pipeline->set_viewport(0, viewport);
1071 
1072  m_pipeline->bind_framebuffer(m_multiscattering_lut_framebuffer.get());
1073  m_pipeline->bind_shader_program(m_multiscattering_lut_shader_program.get());
1074  }
1075  );
1076 
1077  // Update shader variables
1078  if (auto atmosphere_radii_var = m_multiscattering_lut_shader_program->variable("atmosphere_radii"))
1079  {
1080  m_multiscattering_lut_command_buffer.emplace_back([&, atmosphere_radii_var](){atmosphere_radii_var->update(atmosphere_radii);});
1081  }
1082  if (auto rayleigh_parameters_var = m_multiscattering_lut_shader_program->variable("rayleigh_parameters"))
1083  {
1084  m_multiscattering_lut_command_buffer.emplace_back([&, rayleigh_parameters_var](){rayleigh_parameters_var->update(rayleigh_parameters);});
1085  }
1086  if (auto mie_parameters_var = m_multiscattering_lut_shader_program->variable("mie_parameters"))
1087  {
1088  m_multiscattering_lut_command_buffer.emplace_back([&, mie_parameters_var](){mie_parameters_var->update(mie_parameters);});
1089  }
1090  if (auto ozone_distribution_var = m_multiscattering_lut_shader_program->variable("ozone_distribution"))
1091  {
1092  m_multiscattering_lut_command_buffer.emplace_back([&, ozone_distribution_var](){ozone_distribution_var->update(ozone_distribution);});
1093  }
1094  if (auto ozone_absorption_var = m_multiscattering_lut_shader_program->variable("ozone_absorption"))
1095  {
1096  m_multiscattering_lut_command_buffer.emplace_back([&, ozone_absorption_var](){ozone_absorption_var->update(ozone_absorption);});
1097  }
1098  if (auto ground_albedo_var = m_multiscattering_lut_shader_program->variable("ground_albedo"))
1099  {
1100  m_multiscattering_lut_command_buffer.emplace_back([&, ground_albedo_var](){ground_albedo_var->update(m_ground_albedo);});
1101  }
1102  if (auto resolution_var = m_multiscattering_lut_shader_program->variable("resolution"))
1103  {
1104  m_multiscattering_lut_command_buffer.emplace_back([&, resolution_var](){resolution_var->update(math::fvec2(m_multiscattering_lut_resolution));});
1105  }
1106  if (auto transmittance_lut_var = m_multiscattering_lut_shader_program->variable("transmittance_lut"))
1107  {
1108  m_multiscattering_lut_command_buffer.emplace_back([&, transmittance_lut_var](){transmittance_lut_var->update(*m_transmittance_lut_texture);});
1109  }
1110 
1111  m_multiscattering_lut_command_buffer.emplace_back
1112  (
1113  [&]()
1114  {
1115  // Draw fullscreen triangle
1116  m_pipeline->bind_vertex_array(m_vertex_array.get());
1118  m_pipeline->draw(3, 1, 0, 0);
1119  }
1120  );
1121 }
1122 
1123 void sky_pass::rebuild_luminance_lut_framebuffer()
1124 {
1125  // Rebuild luminance LUT texture
1126  m_luminance_lut_texture = std::make_shared<gl::texture_2d>
1127  (
1128  std::make_shared<gl::image_view_2d>
1129  (
1130  std::make_shared<gl::image_2d>
1131  (
1133  m_luminance_lut_resolution.x(),
1134  m_luminance_lut_resolution.y()
1135  )
1136  ),
1137  m_lut_sampler
1138  );
1139 
1140  // Rebuild luminance LUT framebuffer
1141  const gl::framebuffer_attachment attachments[1] =
1142  {{
1144  m_luminance_lut_texture->get_image_view(),
1145  0
1146  }};
1147  m_luminance_lut_framebuffer = std::make_shared<gl::framebuffer>(attachments, m_luminance_lut_resolution.x(), m_luminance_lut_resolution.y());
1148 }
1149 
1150 void sky_pass::rebuild_luminance_lut_shader_program()
1151 {
1152  m_luminance_lut_shader_program = m_luminance_lut_shader_template->build
1153  (
1154  {
1155  {"SAMPLE_COUNT", std::to_string(m_luminance_lut_sample_count)}
1156  }
1157  );
1158  if (!m_luminance_lut_shader_program->linked())
1159  {
1160  debug::log_error("Failed to build sky luminance LUT shader program: {}", m_luminance_lut_shader_program->info());
1161  debug::log_warning("{}", m_luminance_lut_shader_template->configure(gl::shader_stage::vertex));
1162  }
1163 }
1164 
1165 void sky_pass::rebuild_luminance_lut_command_buffer()
1166 {
1167  m_luminance_lut_command_buffer.clear();
1168 
1169  if (!m_luminance_lut_shader_program->linked() || !m_luminance_lut_texture)
1170  {
1171  return;
1172  }
1173 
1174  // Bind framebuffer and shader program
1175  m_luminance_lut_command_buffer.emplace_back
1176  (
1177  [&]()
1178  {
1179  const gl::viewport viewport[1] =
1180  {{
1181  0.0f,
1182  0.0f,
1183  static_cast<float>(m_luminance_lut_resolution.x()),
1184  static_cast<float>(m_luminance_lut_resolution.y())
1185  }};
1186  m_pipeline->set_viewport(0, viewport);
1187 
1188  m_pipeline->bind_framebuffer(m_luminance_lut_framebuffer.get());
1189  m_pipeline->bind_shader_program(m_luminance_lut_shader_program.get());
1190  }
1191  );
1192 
1193  // Update shader variables
1194  if (auto light_direction_var = m_luminance_lut_shader_program->variable("light_direction"))
1195  {
1196  m_luminance_lut_command_buffer.emplace_back([&, light_direction_var](){light_direction_var->update(dominant_light_direction);});
1197  }
1198  if (auto light_illuminance_var = m_luminance_lut_shader_program->variable("light_illuminance"))
1199  {
1200  m_luminance_lut_command_buffer.emplace_back([&, light_illuminance_var](){light_illuminance_var->update(dominant_light_illuminance);});
1201  }
1202  if (auto atmosphere_radii_var = m_luminance_lut_shader_program->variable("atmosphere_radii"))
1203  {
1204  m_luminance_lut_command_buffer.emplace_back([&, atmosphere_radii_var](){atmosphere_radii_var->update(atmosphere_radii);});
1205  }
1206  if (auto observer_position_var = m_luminance_lut_shader_program->variable("observer_position"))
1207  {
1208  m_luminance_lut_command_buffer.emplace_back([&, observer_position_var](){observer_position_var->update(observer_position);});
1209  }
1210  if (auto rayleigh_parameters_var = m_luminance_lut_shader_program->variable("rayleigh_parameters"))
1211  {
1212  m_luminance_lut_command_buffer.emplace_back([&, rayleigh_parameters_var](){rayleigh_parameters_var->update(rayleigh_parameters);});
1213  }
1214  if (auto mie_parameters_var = m_luminance_lut_shader_program->variable("mie_parameters"))
1215  {
1216  m_luminance_lut_command_buffer.emplace_back([&, mie_parameters_var](){mie_parameters_var->update(mie_parameters);});
1217  }
1218  if (auto ozone_distribution_var = m_luminance_lut_shader_program->variable("ozone_distribution"))
1219  {
1220  m_luminance_lut_command_buffer.emplace_back([&, ozone_distribution_var](){ozone_distribution_var->update(ozone_distribution);});
1221  }
1222  if (auto ozone_absorption_var = m_luminance_lut_shader_program->variable("ozone_absorption"))
1223  {
1224  m_luminance_lut_command_buffer.emplace_back([&, ozone_absorption_var](){ozone_absorption_var->update(ozone_absorption);});
1225  }
1226  if (auto airglow_luminance_var = m_luminance_lut_shader_program->variable("airglow_luminance"))
1227  {
1228  m_luminance_lut_command_buffer.emplace_back([&, airglow_luminance_var](){airglow_luminance_var->update(airglow_luminance * camera_exposure);});
1229  }
1230  if (auto resolution_var = m_luminance_lut_shader_program->variable("resolution"))
1231  {
1232  m_luminance_lut_command_buffer.emplace_back([&, resolution_var](){resolution_var->update(math::fvec2(m_luminance_lut_resolution));});
1233  }
1234  if (auto transmittance_lut_var = m_luminance_lut_shader_program->variable("transmittance_lut"))
1235  {
1236  m_luminance_lut_command_buffer.emplace_back([&, transmittance_lut_var](){transmittance_lut_var->update(*m_transmittance_lut_texture);});
1237  }
1238  if (auto multiscattering_lut_var = m_luminance_lut_shader_program->variable("multiscattering_lut"))
1239  {
1240  m_luminance_lut_command_buffer.emplace_back([&, multiscattering_lut_var](){multiscattering_lut_var->update(*m_multiscattering_lut_texture);});
1241  }
1242 
1243  m_luminance_lut_command_buffer.emplace_back
1244  (
1245  [&]()
1246  {
1247  // Draw fullscreen triangle
1248  m_pipeline->bind_vertex_array(m_vertex_array.get());
1250  m_pipeline->draw(3, 1, 0, 0);
1251  }
1252  );
1253 }
1254 
1255 void sky_pass::rebuild_sky_probe_command_buffer()
1256 {
1257  m_sky_probe_command_buffer.clear();
1258 
1259  if (!m_sky_probe_shader_program->linked() || m_sky_probe_framebuffers.empty())
1260  {
1261  return;
1262  }
1263 
1264  // Bind sky probe framebuffer and shader program
1265  m_sky_probe_command_buffer.emplace_back
1266  (
1267  [&]()
1268  {
1269  const auto resolution = m_sky_probe->get_luminance_texture()->get_image_view()->get_image()->get_dimensions()[0];
1270  const gl::viewport viewport[1] =
1271  {{
1272  0.0f,
1273  0.0f,
1274  static_cast<float>(resolution),
1275  static_cast<float>(resolution)
1276  }};
1277  m_pipeline->set_viewport(0, viewport);
1278 
1279  m_pipeline->bind_framebuffer(m_sky_probe_framebuffers[0].get());
1280  m_pipeline->bind_shader_program(m_sky_probe_shader_program.get());
1281  m_pipeline->bind_vertex_array(m_vertex_array.get());
1282  }
1283  );
1284 
1285  if (auto luminance_lut_var = m_sky_probe_shader_program->variable("luminance_lut"))
1286  {
1287  m_sky_probe_command_buffer.emplace_back([&, luminance_lut_var](){luminance_lut_var->update(*m_luminance_lut_texture);});
1288  }
1289  if (auto light_direction_var = m_sky_probe_shader_program->variable("light_direction"))
1290  {
1291  m_sky_probe_command_buffer.emplace_back([&, light_direction_var](){light_direction_var->update(dominant_light_direction);});
1292  }
1293  if (auto light_illuminance_var = m_sky_probe_shader_program->variable("light_illuminance"))
1294  {
1295  m_sky_probe_command_buffer.emplace_back([&, light_illuminance_var](){light_illuminance_var->update(dominant_light_illuminance);});
1296  }
1297  if (auto observer_position_var = m_sky_probe_shader_program->variable("observer_position"))
1298  {
1299  m_sky_probe_command_buffer.emplace_back([&, observer_position_var](){observer_position_var->update(observer_position);});
1300  }
1301  if (auto atmosphere_radii_var = m_sky_probe_shader_program->variable("atmosphere_radii"))
1302  {
1303  m_sky_probe_command_buffer.emplace_back([&, atmosphere_radii_var](){atmosphere_radii_var->update(atmosphere_radii);});
1304  }
1305  if (auto ground_albedo_var = m_sky_probe_shader_program->variable("ground_albedo"))
1306  {
1307  m_sky_probe_command_buffer.emplace_back([&, ground_albedo_var](){ground_albedo_var->update(m_ground_albedo);});
1308  }
1309 
1310  // Draw point
1311  m_sky_probe_command_buffer.emplace_back
1312  (
1313  [&]()
1314  {
1316  m_pipeline->draw(1, 1, 0, 0);
1317  m_sky_probe->set_luminance_outdated(true);
1318  m_sky_probe->set_illuminance_outdated(true);
1319  }
1320  );
1321 }
1322 
1323 } // namespace render
constexpr const std::array< std::uint32_t, 2 > & dimensions() const noexcept
Returns the dimensions of the framebuffer.
Definition: framebuffer.hpp:67
Graphics pipeline interface.
Definition: pipeline.hpp:48
void set_stencil_op(std::uint8_t face_mask, stencil_op fail_op, stencil_op pass_op, stencil_op depth_fail_op, gl::compare_op compare_op)
Sets the stencil operations.
Definition: pipeline.cpp:702
void set_primitive_topology(primitive_topology topology)
Sets the primitive topology to use for drawing.
Definition: pipeline.cpp:356
void clear_attachments(std::uint8_t mask, const clear_value &value)
Clears the color, depth, or stencil buffers of current attachments.
Definition: pipeline.cpp:1053
void bind_shader_program(const gl::shader_program *shader_program)
Sets the vertex input.
Definition: pipeline.cpp:292
void bind_framebuffer(const gl::framebuffer *framebuffer)
Sets the vertex input.
Definition: pipeline.cpp:275
void set_stencil_write_mask(std::uint8_t face_mask, std::uint32_t write_mask)
Sets the stencil write mask.
Definition: pipeline.cpp:896
void set_color_blend_enabled(bool enabled)
Controls whether blending is enabled for the corresponding color attachment.
Definition: pipeline.cpp:953
void set_cull_mode(cull_mode mode)
Sets the triangle culling mode.
Definition: pipeline.cpp:503
void set_stencil_test_enabled(bool enabled)
Controls whether stencil testing is enabled.
Definition: pipeline.cpp:685
void set_viewport(std::uint32_t first_viewport, std::span< const viewport > viewports)
Sets one or more viewports.
Definition: pipeline.cpp:381
void set_stencil_reference(std::uint8_t face_mask, std::uint32_t reference)
Sets the stencil reference value.
Definition: pipeline.cpp:841
void bind_vertex_buffers(std::uint32_t first_binding, std::span< const vertex_buffer *const > buffers, std::span< const std::size_t > offsets, std::span< const std::size_t > strides)
Binds vertex buffers.
Definition: pipeline.cpp:326
void set_color_blend_equation(const color_blend_equation &equation)
Sets the color blend factors and operations.
Definition: pipeline.cpp:970
void draw(std::uint32_t vertex_count, std::uint32_t instance_count, std::uint32_t first_vertex, std::uint32_t first_instance)
Draws primitives.
Definition: pipeline.cpp:1028
constexpr const std::array< std::uint32_t, 2 > & get_default_framebuffer_dimensions() const noexcept
Returns the dimensions of the default framebuffer.
Definition: pipeline.hpp:383
void set_depth_test_enabled(bool enabled)
Controls whether depth testing is enabled.
Definition: pipeline.cpp:649
void bind_vertex_array(const vertex_array *array)
Binds a vertex array.
Definition: pipeline.cpp:309
void set_stencil_compare_mask(std::uint8_t face_mask, std::uint32_t compare_mask)
Sets the stencil compare mask.
Definition: pipeline.cpp:786
Template used to for generating one or more shader variants from a single source.
std::unique_ptr< gl::shader_program > build(const dictionary_type &definitions={}) const
Configures and compiles shader objects, then links them into a shader program.
virtual void update(bool value) const
Updates the value of the variable.
2D texture.
Definition: texture.hpp:141
const std::shared_ptr< gl::shader_template > & get_shader_template() const noexcept
Returns the shader template with which this material is associated.
Definition: material.hpp:134
material()=default
Constructs a material.
const std::shared_ptr< gl::vertex_buffer > & get_vertex_buffer() const noexcept
Returns the vertex buffer associated with this model.
Definition: model.hpp:96
const std::vector< model_group > & get_groups() const noexcept
Returns the model's model groups.
Definition: model.hpp:136
const std::shared_ptr< gl::vertex_array > & get_vertex_array() const noexcept
Returns the vertex array associated with this model.
Definition: model.hpp:82
Render pass.
Definition: pass.hpp:34
gl::pipeline * m_pipeline
Definition: pass.hpp:63
const gl::framebuffer * m_framebuffer
Definition: pass.hpp:64
void set_magnification(float scale)
Definition: sky-pass.cpp:705
void set_sky_probe(std::shared_ptr< scene::light_probe > probe)
Definition: sky-pass.cpp:867
void set_luminance_lut_sample_count(std::uint16_t count)
Sets the number of luminance integration samples.
Definition: sky-pass.cpp:506
void set_mie_parameters(float scale_height, float scattering, float extinction, float anisotropy)
Definition: sky-pass.cpp:783
void set_moon_planetlight_direction(const math::fvec3 &direction)
Definition: sky-pass.cpp:851
void set_multiscattering_lut_direction_sample_count(std::uint16_t count)
Sets the number of multiscattering directions to sample.
Definition: sky-pass.cpp:463
void set_sun_position(const math::fvec3 &position)
Definition: sky-pass.cpp:716
void set_ground_albedo(const math::fvec3 &albedo)
Definition: sky-pass.cpp:818
void set_transmittance_lut_resolution(const math::vec2< std::uint16_t > &resolution)
Sets the resolution of the transmittance LUT.
Definition: sky-pass.cpp:450
void set_rayleigh_parameters(float scale_height, const math::fvec3 &scattering)
Definition: sky-pass.cpp:768
void set_moon_sunlight_direction(const math::fvec3 &direction)
Definition: sky-pass.cpp:841
void set_ozone_parameters(float lower_limit, float upper_limit, float mode, const math::fvec3 &absorption)
Definition: sky-pass.cpp:798
void set_multiscattering_lut_scatter_sample_count(std::uint16_t count)
Sets the number of multiscattering scatter events to sample per sample direction.
Definition: sky-pass.cpp:478
void set_transmittance_lut_sample_count(std::uint16_t count)
Sets the number of transmittance integration samples.
Definition: sky-pass.cpp:435
void set_airglow_luminance(const math::fvec3 &luminance)
Definition: sky-pass.cpp:813
void set_observer_elevation(float elevation)
Definition: sky-pass.cpp:762
void set_multiscattering_lut_resolution(const math::vec2< std::uint16_t > &resolution)
Sets the resolution of the multiscattering LUT.
Definition: sky-pass.cpp:493
void set_moon_sunlight_illuminance(const math::fvec3 &illuminance)
Definition: sky-pass.cpp:846
void set_moon_rotation(const math::fquat &rotation)
Definition: sky-pass.cpp:831
void update_tweens()
Definition: sky-pass.cpp:686
void set_icrf_to_eus(const math::se3< float > &transformation)
Definition: sky-pass.cpp:710
void set_moon_model(std::shared_ptr< render::model > model)
Definition: sky-pass.cpp:590
void set_atmosphere_upper_limit(float limit)
Definition: sky-pass.cpp:751
void set_luminance_lut_resolution(const math::vec2< std::uint16_t > &resolution)
Sets the resolution of the luminance LUT.
Definition: sky-pass.cpp:521
void render(render::context &ctx) override
Definition: sky-pass.cpp:148
void set_sun_illuminance(const math::fvec3 &illuminance, const math::fvec3 &transmitted_illuminance)
Definition: sky-pass.cpp:721
void set_moon_angular_radius(float angular_radius)
Definition: sky-pass.cpp:836
void set_moon_planetlight_illuminance(const math::fvec3 &illuminance)
Definition: sky-pass.cpp:856
void set_sun_angular_radius(float radius)
Definition: sky-pass.cpp:732
sky_pass(gl::pipeline *pipeline, const gl::framebuffer *framebuffer, resource_manager *resource_manager)
Definition: sky-pass.cpp:44
void set_moon_position(const math::fvec3 &position)
Definition: sky-pass.cpp:826
void set_moon_illuminance(const math::fvec3 &illuminance, const math::fvec3 &transmitted_illuminance)
Definition: sky-pass.cpp:861
void set_sky_model(std::shared_ptr< render::model > model)
Definition: sky-pass.cpp:534
void set_sun_luminance(const math::fvec3 &luminance)
Definition: sky-pass.cpp:727
void set_planet_radius(float radius)
Definition: sky-pass.cpp:737
void set_stars_model(std::shared_ptr< render::model > model)
Definition: sky-pass.cpp:643
Manages the loading, caching, and saving of resources.
std::shared_ptr< T > load(const std::filesystem::path &path)
Loads and caches a resource.
constexpr const math::fmat4 & get_projection() const noexcept
Returns the camera's projection matrix.
Definition: camera.hpp:235
constexpr const math::fmat4 & get_view() const noexcept
Returns the camera's view matrix.
Definition: camera.hpp:223
geom::ray< float, 3 > pick(const math::fvec2 &ndc) const
Constructs a picking ray from normalized device coordinates (NDC).
Definition: camera.cpp:26
constexpr float get_clip_near() const noexcept
Returns the signed distance to the camera's near clipping plane.
Definition: camera.hpp:187
constexpr float get_exposure_normalization() const noexcept
Returns the camera's exposure normalization factor.
Definition: camera.hpp:217
constexpr const math::fmat4 & get_inv_view() const noexcept
Returns the inverse of the camera's view matrix.
Definition: camera.hpp:229
constexpr const math::fmat4 & get_inv_projection() const noexcept
Returns the inverse of the camera's projection matrix.
Definition: camera.hpp:241
constexpr std::uint32_t get_layer_mask() const noexcept
Returns the layer mask of the object.
Definition: object.hpp:121
constexpr const vector_type & get_translation() const noexcept
Returns the translation of the object.
Definition: object.hpp:133
void update()
Sets state 0 = state 1.
Definition: tween.hpp:181
value_type interpolate(scalar_type a) const
Returns an interpolated state between state 0 and state 1.
Definition: tween.hpp:163
T angular_radius(T radius, T distance)
Finds the angular radius of a celestial object, given its radius and distance.
constexpr int count(T x) noexcept
Returns the number of set bits in a value, known as a population count or Hamming weight.
Definition: bit-math.hpp:211
Commands which operate on entity::id components.
Definition: commands.cpp:28
log_message< log_message_severity::warning, Args... > log_warning
Formats and logs a warning message.
Definition: log.hpp:130
log_message< log_message_severity::error, Args... > log_error
Formats and logs an error message.
Definition: log.hpp:144
@ clamp_to_edge
Clamp to edge wrap mode.
@ color_attachment_bit
Framebuffer color attachment.
@ back
Back-facing triangles are discarded.
@ vertex
Vertex shader stage.
@ stencil_face_front_and_back
Both sets of stencil state are updated.
@ linear
Linear filtering.
@ linear
Linear filtering.
@ keep
Keeps the current value.
@ replace
Sets the value to reference.
@ point_list
Separate point primitives.
@ triangle_list
Separate triangle primitives.
@ color_clear_bit
Indicates the color buffer should be cleared.
Definition: clear-bits.hpp:31
@ depth_clear_bit
Indicates the depth buffer should be cleared.
Definition: clear-bits.hpp:34
@ stencil_clear_bit
Indicates the stencil buffer should be cleared.
Definition: clear-bits.hpp:37
@ not_equal
Comparison evaluates reference != test.
@ always
Comparison always evaluates true.
quaternion< T > normalize(const quaternion< T > &q)
Normalizes a quaternion.
Definition: quaternion.hpp:679
quaternion< T > rotation(const vec3< T > &from, const vec3< T > &to, T tolerance=T{1e-6})
Constructs a quaternion representing the minimum rotation from one direction to another direction.
Definition: quaternion.hpp:691
constexpr mat4< T > scale(const vec3< T > &v)
Constructs a scale matrix.
constexpr matrix< T, N, M >::column_vector_type & get(matrix< T, N, M > &m) noexcept
Extracts the Ith column from a matrix.
constexpr matrix< T, M, N > transpose(const matrix< T, N, M > &m) noexcept
Calculates the transpose of a matrix.
constexpr matrix< T, N, N > inverse(const matrix< T, N, N > &m) noexcept
Calculates the inverse of a square matrix.
T extinction(T scattering, T albedo)
Calculates an extinction coefficient.
Definition: atmosphere.hpp:121
T absorption(T scattering, T albedo)
Calculates an absorption coefficient.
Definition: atmosphere.hpp:105
T scattering(T density, T polarization, T wavelength)
Calculates a wavelength-dependent scattering coefficient.
Definition: atmosphere.hpp:69
High-level rendering.
Viewport position, dimensions, and depth range.
Definition: viewport.hpp:31
float width
Width of the viewport.
Definition: viewport.hpp:39
float height
Height of the viewport.
Definition: viewport.hpp:42
n by m column-major matrix.
Definition: math/matrix.hpp:44
Quaternion composed of a real scalar part and imaginary vector part.
Definition: quaternion.hpp:39
static constexpr quaternion identity() noexcept
Returns a rotation identity quaternion.
Definition: quaternion.hpp:200
SE(3) proper rigid transformation (rototranslation).
Definition: se3.hpp:35
quaternion_type r
Quaternion representing the rotation component of the transformation.
Definition: se3.hpp:53
vector_type t
Vector representing the translation component of the transformation.
Definition: se3.hpp:50
vector_type scale
Scale vector.
Definition: transform.hpp:56
constexpr matrix_type matrix() const noexcept
Constructs a matrix representing the transformation.
Definition: transform.hpp:87
vector_type translation
Translation vector.
Definition: transform.hpp:50
quaternion_type rotation
Rotation quaternion.
Definition: transform.hpp:53
n-dimensional vector.
Definition: vector.hpp:44
constexpr element_type & x() noexcept
Returns a reference to the first element.
Definition: vector.hpp:164
constexpr element_type & y() noexcept
Returns a reference to the second element.
Definition: vector.hpp:180
Context of a renderer.
Definition: context.hpp:40
const scene::camera * camera
Pointer to the camera.
Definition: context.hpp:42
float alpha
Subframe interpolation factor.
Definition: context.hpp:54