Antkeeper  0.0.1
astronomy-system.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/color/color.hpp>
38 #include <engine/debug/log.hpp>
39 
42  time_days(0.0),
43  time_centuries(0.0),
44  time_scale(1.0),
45  observer_eid(entt::null),
46  reference_body_eid(entt::null),
47  transmittance_samples(0),
48  sun_light(nullptr),
49  moon_light(nullptr),
50  sky_pass(nullptr),
51  starlight_illuminance{0, 0, 0}
52 {
53  // Construct ENU to EUS transformation
54  enu_to_eus = math::se3<double>
55  {
56  {0, 0, 0},
57  math::dquat::rotate_x(-math::half_pi<double>)
58  };
59 
60  registry.on_construct<::observer_component>().connect<&astronomy_system::on_observer_modified>(this);
61  registry.on_update<::observer_component>().connect<&astronomy_system::on_observer_modified>(this);
62  registry.on_destroy<::observer_component>().connect<&astronomy_system::on_observer_destroyed>(this);
63  registry.on_construct<::celestial_body_component>().connect<&astronomy_system::on_celestial_body_modified>(this);
64  registry.on_update<::celestial_body_component>().connect<&astronomy_system::on_celestial_body_modified>(this);
65  registry.on_destroy<::celestial_body_component>().connect<&astronomy_system::on_celestial_body_destroyed>(this);
66  registry.on_construct<::orbit_component>().connect<&astronomy_system::on_orbit_modified>(this);
67  registry.on_update<::orbit_component>().connect<&astronomy_system::on_orbit_modified>(this);
68  registry.on_destroy<::orbit_component>().connect<&astronomy_system::on_orbit_destroyed>(this);
69  registry.on_construct<::atmosphere_component>().connect<&astronomy_system::on_atmosphere_modified>(this);
70  registry.on_update<::atmosphere_component>().connect<&astronomy_system::on_atmosphere_modified>(this);
71  registry.on_destroy<::atmosphere_component>().connect<&astronomy_system::on_atmosphere_destroyed>(this);
72 }
73 
75 {
76  registry.on_construct<::observer_component>().disconnect<&astronomy_system::on_observer_modified>(this);
77  registry.on_update<::observer_component>().disconnect<&astronomy_system::on_observer_modified>(this);
78  registry.on_destroy<::observer_component>().disconnect<&astronomy_system::on_observer_destroyed>(this);
79  registry.on_construct<::celestial_body_component>().disconnect<&astronomy_system::on_celestial_body_modified>(this);
80  registry.on_update<::celestial_body_component>().disconnect<&astronomy_system::on_celestial_body_modified>(this);
81  registry.on_destroy<::celestial_body_component>().disconnect<&astronomy_system::on_celestial_body_destroyed>(this);
82  registry.on_construct<::orbit_component>().disconnect<&astronomy_system::on_orbit_modified>(this);
83  registry.on_update<::orbit_component>().disconnect<&astronomy_system::on_orbit_modified>(this);
84  registry.on_destroy<::orbit_component>().disconnect<&astronomy_system::on_orbit_destroyed>(this);
85  registry.on_construct<::atmosphere_component>().disconnect<&astronomy_system::on_atmosphere_modified>(this);
86  registry.on_update<::atmosphere_component>().disconnect<&astronomy_system::on_atmosphere_modified>(this);
87  registry.on_destroy<::atmosphere_component>().disconnect<&astronomy_system::on_atmosphere_destroyed>(this);
88 }
89 
90 void astronomy_system::update(float t, float dt)
91 {
92  // Add scaled timestep to current time
93  set_time(time_days + dt * time_scale);
94 
95  // Abort if no valid observer entity or reference body entity
96  if (observer_eid == entt::null || reference_body_eid == entt::null)
97  return;
98 
99  // Get pointer to observer component
100  const auto observer = registry.try_get<observer_component>(observer_eid);
101 
102  // Abort if no observer component
103  if (!observer)
104  return;
105 
106  // Get pointers to reference body components
107  const auto
108  [
109  reference_body,
110  reference_orbit,
111  reference_atmosphere
112  ] = registry.try_get<celestial_body_component, orbit_component, atmosphere_component>(reference_body_eid);
113 
114  // Abort if no reference body or reference orbit
115  if (!reference_body || !reference_orbit)
116  return;
117 
118  // if (sky_pass)
119  // {
120  // sky_pass->set_ground_albedo(math::fvec3{1.0f, 1.0f, 1.0f} * static_cast<float>(reference_body->albedo));
121  // }
122 
123  // Update ICRF to EUS transformation
124  update_icrf_to_eus(*reference_body, *reference_orbit);
125 
126  // Set the transform component translations of orbiting bodies to their topocentric positions
128  (
129  [&](entity::id entity_id, const auto& body, const auto& orbit, auto& transform)
130  {
131  // Skip reference body entity
132  if (entity_id == reference_body_eid || orbit.parent == entt::null)
133  return;
134 
135  // Transform orbital Cartesian position (r) from the ICRF frame to the EUS frame
136  const math::dvec3 r_eus = icrf_to_eus * orbit.position;
137 
138  // Evaluate body orientation polynomials
139  const double body_pole_ra = math::polynomial::horner(body.pole_ra.begin(), body.pole_ra.end(), time_centuries);
140  const double body_pole_dec = math::polynomial::horner(body.pole_dec.begin(), body.pole_dec.end(), time_centuries);
141  const double body_prime_meridian = math::polynomial::horner(body.prime_meridian.begin(), body.prime_meridian.end(), time_days);
142 
143  // Determine body orientation in the ICRF frame
145  (
146  body_pole_ra,
147  body_pole_dec,
148  body_prime_meridian
149  ).r;
150 
151  // Transform body orientation from the ICRF frame to the EUS frame.
152  math::dquat rotation_eus = math::normalize(icrf_to_eus.r * rotation_icrf);
153 
154  // Update local transform
155  transform.local.translation = math::normalize(math::fvec3(r_eus));
156  transform.local.rotation = math::fquat(rotation_eus);
157  transform.local.scale = {1.0f, 1.0f, 1.0f};
158  }
159  );
160 
161  // Update blackbody lighting
163  [&](entity::id entity_id, const auto& blackbody_body, const auto& blackbody_orbit, const auto& blackbody)
164  {
165  // Transform blackbody position from ICRF frame to EUS frame
166  const math::dvec3 blackbody_position_eus = icrf_to_eus * blackbody_orbit.position;
167 
168  // Measure distance and direction, in EUS frame, from observer to blackbody
169  const double observer_blackbody_distance = math::length(blackbody_position_eus);
170  const math::dvec3 observer_blackbody_direction_eus = blackbody_position_eus / observer_blackbody_distance;
171 
172  // Measure blackbody solid angle as seen by observer
173  const double observer_blackbody_angular_radius = astro::angular_radius(blackbody_body.radius, observer_blackbody_distance);
174  const double observer_blackbody_solid_angle = geom::solid_angle::cone(observer_blackbody_angular_radius);
175 
176  // Calculate illuminance from blackbody reaching observer
177  const math::dvec3 observer_blackbody_illuminance = blackbody.color * blackbody.luminance * observer_blackbody_solid_angle;
178 
179  // Calculate illuminance from blackbody reaching observer after atmospheric extinction
180  math::dvec3 observer_blackbody_transmitted_illuminance = observer_blackbody_illuminance;
181  if (reference_atmosphere)
182  {
183  // Construct ray at observer pointing towards the blackbody
184  const geom::ray<double, 3> ray = {{0, 0, 0}, observer_blackbody_direction_eus};
185 
186  // Integrate atmospheric spectral transmittance factor between observer and blackbody
187  math::dvec3 transmittance = integrate_transmittance(*observer, *reference_body, *reference_atmosphere, ray);
188 
189  // Attenuate illuminance from blackbody reaching observer by spectral transmittance factor
190  observer_blackbody_transmitted_illuminance *= transmittance;
191  }
192 
193  // Update sun light
194  if (sun_light != nullptr)
195  {
196  const math::dvec3 blackbody_up_eus = icrf_to_eus.r * math::dvec3{0, 0, 1};
197  sun_light->set_rotation
198  (
200  (
201  math::fvec3(-observer_blackbody_direction_eus),
202  math::fvec3(blackbody_up_eus)
203  )
204  );
205 
206  sun_light->set_illuminance(static_cast<float>(math::max(observer_blackbody_transmitted_illuminance)));
207 
208  const auto max_component = math::max(observer_blackbody_transmitted_illuminance);
209  if (max_component > 0.0)
210  {
211  sun_light->set_color(math::fvec3(observer_blackbody_transmitted_illuminance / max_component));
212  }
213  else
214  {
215  sun_light->set_color({});
216  }
217  }
218 
219  // Upload blackbody params to sky pass
220  if (this->sky_pass)
221  {
222  this->sky_pass->set_sun_position(math::fvec3(blackbody_position_eus));
223  this->sky_pass->set_sun_luminance(math::fvec3(blackbody.color * blackbody.luminance));
224  this->sky_pass->set_sun_illuminance(math::fvec3(observer_blackbody_illuminance), math::fvec3(observer_blackbody_transmitted_illuminance));
225  this->sky_pass->set_sun_angular_radius(static_cast<float>(observer_blackbody_angular_radius));
226  }
227 
228  // Update diffuse reflectors
230  [&](entity::id entity_id, const auto& reflector_body, const auto& reflector_orbit, const auto& reflector, const auto& transform)
231  {
232  // Transform reflector position from ICRF frame to EUS frame
233  const math::dvec3 reflector_position_eus = icrf_to_eus * reflector_orbit.position;
234 
235  // Measure distance and direction, in EUS frame, from observer to reflector
236  const double observer_reflector_distance = math::length(reflector_position_eus);
237  const math::dvec3 observer_reflector_direction_eus = reflector_position_eus / observer_reflector_distance;
238 
239  // Measure distance and direction, in EUS frame, from reflector to blackbody
240  math::dvec3 reflector_blackbody_direction_eus = blackbody_position_eus - reflector_position_eus;
241  const double reflector_blackbody_distance = math::length(reflector_blackbody_direction_eus);
242  reflector_blackbody_direction_eus /= reflector_blackbody_distance;
243 
244  // Measure blackbody solid angle as seen by reflector
245  const double reflector_blackbody_angular_radius = astro::angular_radius(blackbody_body.radius, reflector_blackbody_distance);
246  const double reflector_blackbody_solid_angle = geom::solid_angle::cone(reflector_blackbody_angular_radius);
247 
248  // Calculate blackbody illuminance reaching reflector
249  const math::dvec3 reflector_blackbody_illuminance = blackbody.color * blackbody.luminance * reflector_blackbody_solid_angle;
250 
251  // Measure reflector solid angle as seen by observer
252  const double observer_reflector_angular_radius = astro::angular_radius(reflector_body.radius, observer_reflector_distance);
253  const double observer_reflector_solid_angle = geom::solid_angle::cone(observer_reflector_angular_radius);
254 
255  // Determine phase factor of reflector as seen by observer
256  const double observer_reflector_phase_factor = math::dot(observer_reflector_direction_eus, -reflector_blackbody_direction_eus) * 0.5 + 0.5;
257 
258  // Measure observer reference body solid angle as seen by reflector
259  const double reflector_observer_angular_radius = astro::angular_radius(reference_body->radius, observer_reflector_distance);
260  const double reflector_observer_solid_angle = geom::solid_angle::cone(reflector_observer_angular_radius);
261 
262  // Determine phase factor of observer reference body as by reflector
263  const double reflector_observer_phase_factor = math::dot(-observer_reflector_direction_eus, -observer_blackbody_direction_eus) * 0.5 + 0.5;
264 
265  // Calculate spectral transmittance between observer and reflector factor due to atmospheric extinction
266  math::dvec3 observer_reflector_transmittance = {1, 1, 1};
267  if (reference_atmosphere)
268  {
269  // const geom::ray<double, 3> ray = {{0, 0, 0}, observer_reflector_direction_eus};
270  // observer_reflector_transmittance = integrate_transmittance(*observer, *reference_body, *reference_atmosphere, ray);
271  }
272 
273  // Measure luminance of observer reference body as seen by reflector
274  const math::dvec3 reflector_observer_luminance = observer_blackbody_illuminance * reference_body->albedo * observer_reflector_transmittance * reflector_observer_phase_factor * math::inv_pi<double>;
275 
276  // Measure illuminance from observer reference body reaching reflector
277  const math::dvec3 reflector_observer_illuminance = reflector_observer_luminance * reflector_observer_solid_angle;
278 
279  // Measure luminance of reflector as seen by observer
280  const math::dvec3 observer_reflector_luminance = (reflector_blackbody_illuminance * observer_reflector_phase_factor + reflector_observer_illuminance) * reflector.albedo * observer_reflector_transmittance * math::inv_pi<double>;
281 
282  // Measure illuminance from reflector reaching observer
283  const math::dvec3 observer_reflector_illuminance = observer_reflector_luminance * observer_reflector_solid_angle;
284 
285  if (this->sky_pass)
286  {
287  this->sky_pass->set_moon_position(transform.local.translation);
288  this->sky_pass->set_moon_rotation(transform.local.rotation);
289  this->sky_pass->set_moon_angular_radius(static_cast<float>(observer_reflector_angular_radius));
290  this->sky_pass->set_moon_sunlight_direction(math::fvec3(-reflector_blackbody_direction_eus));
291  this->sky_pass->set_moon_sunlight_illuminance(math::fvec3(reflector_blackbody_illuminance * observer_reflector_transmittance));
292  this->sky_pass->set_moon_planetlight_direction(math::fvec3(observer_reflector_direction_eus));
293  this->sky_pass->set_moon_planetlight_illuminance(math::fvec3(reflector_observer_illuminance * observer_reflector_transmittance));
294  this->sky_pass->set_moon_illuminance(math::fvec3(observer_reflector_illuminance / observer_reflector_transmittance), math::fvec3(observer_reflector_illuminance));
295  }
296 
297  if (moon_light)
298  {
299  const math::fvec3 reflector_up_eus = math::fvec3(icrf_to_eus.r * math::dvec3{0, 0, 1});
300 
301  moon_light->set_illuminance(static_cast<float>(math::max(observer_reflector_illuminance)));
302 
303  const auto max_component = math::max(observer_reflector_illuminance);
304  if (max_component > 0.0)
305  {
306  moon_light->set_color(math::fvec3(observer_reflector_illuminance / max_component));
307  }
308  else
309  {
310  moon_light->set_color({});
311  }
312 
313  moon_light->set_rotation
314  (
316  (
317  math::fvec3(-observer_reflector_direction_eus),
318  reflector_up_eus
319  )
320  );
321  }
322  });
323  });
324 }
325 
327 {
328  time_days = t;
329  time_centuries = time_days * physics::time::jd::centuries_per_day<double>;
330 }
331 
333 {
334  time_scale = scale;
335 }
336 
338 {
339  if (observer_eid != eid)
340  {
341  observer_eid = eid;
342 
343  if (observer_eid != entt::null)
344  observer_modified();
345  else
346  reference_body_eid = entt::null;
347  }
348 }
349 
351 {
352  transmittance_samples = samples;
353 }
354 
356 {
357  sun_light = light;
358 }
359 
361 {
362  moon_light = light;
363 }
364 
366 {
367  starlight_illuminance = illuminance;
368 }
369 
371 {
372  this->sky_pass = pass;
373 
374  if (sky_pass)
375  {
376  if (observer_eid != entt::null)
377  {
378  // Get pointer to observer
379  const auto observer = registry.try_get<observer_component>(reference_body_eid);
380 
381  sky_pass->set_observer_elevation(static_cast<float>(observer->elevation));
382  }
383 
384  if (reference_body_eid != entt::null)
385  {
386  // Get pointer to reference celestial body
387  const auto reference_body = registry.try_get<celestial_body_component>(reference_body_eid);
388 
389  if (reference_body)
390  {
391  sky_pass->set_planet_radius(static_cast<float>(reference_body->radius));
392  // sky_pass->set_ground_albedo(math::fvec3{1.0f, 1.0f, 1.0f} * static_cast<float>(reference_body->albedo));
393  }
394  else
395  {
396  sky_pass->set_planet_radius(0.0f);
397  // sky_pass->set_ground_albedo({0.0f, 0.0f, 0.0f});
398  }
399  }
400  }
401 }
402 
403 void astronomy_system::on_observer_modified(entity::registry& registry, entity::id entity_id)
404 {
405  if (entity_id == observer_eid)
406  observer_modified();
407 }
408 
409 void astronomy_system::on_observer_destroyed(entity::registry& registry, entity::id entity_id)
410 {
411  if (entity_id == observer_eid)
412  observer_modified();
413 }
414 
415 void astronomy_system::on_celestial_body_modified(entity::registry& registry, entity::id entity_id)
416 {
417  if (entity_id == reference_body_eid)
418  reference_body_modified();
419 }
420 
421 void astronomy_system::on_celestial_body_destroyed(entity::registry& registry, entity::id entity_id)
422 {
423  if (entity_id == reference_body_eid)
424  reference_body_modified();
425 }
426 
427 void astronomy_system::on_orbit_modified(entity::registry& registry, entity::id entity_id)
428 {
429  if (entity_id == reference_body_eid)
430  reference_orbit_modified();
431 }
432 
433 void astronomy_system::on_orbit_destroyed(entity::registry& registry, entity::id entity_id)
434 {
435  if (entity_id == reference_body_eid)
436  reference_orbit_modified();
437 }
438 
439 void astronomy_system::on_atmosphere_modified(entity::registry& registry, entity::id entity_id)
440 {
441  if (entity_id == reference_body_eid)
442  reference_atmosphere_modified();
443 }
444 
445 void astronomy_system::on_atmosphere_destroyed(entity::registry& registry, entity::id entity_id)
446 {
447  if (entity_id == reference_body_eid)
448  reference_atmosphere_modified();
449 }
450 
451 void astronomy_system::observer_modified()
452 {
453  // Get pointer to observer component
454  const auto observer = registry.try_get<observer_component>(observer_eid);
455 
456  if (observer)
457  {
458  if (reference_body_eid != observer->reference_body_eid)
459  {
460  // Reference body changed
461  reference_body_eid = observer->reference_body_eid;
462  reference_body_modified();
463  reference_orbit_modified();
464  reference_atmosphere_modified();
465  }
466 
467  if (reference_body_eid != entt::null)
468  {
469  // Get pointer to reference celestial body
470  const auto reference_body = registry.try_get<celestial_body_component>(reference_body_eid);
471 
472  // Update BCBF to EUS transformation
473  if (reference_body)
474  update_bcbf_to_eus(*observer, *reference_body);
475  }
476 
477  // Upload observer elevation to sky pass
478  if (sky_pass)
479  sky_pass->set_observer_elevation(static_cast<float>(observer->elevation));
480  }
481 }
482 
483 void astronomy_system::reference_body_modified()
484 {
485  // Get pointer to reference celestial body
486  const auto reference_body = registry.try_get<celestial_body_component>(reference_body_eid);
487 
488  if (reference_body)
489  {
490  // Get pointer to observer
491  const auto observer = registry.try_get<observer_component>(observer_eid);
492 
493  // Update BCBF to EUS transformation
494  if (observer)
495  update_bcbf_to_eus(*observer, *reference_body);
496  }
497 
498  // Update reference celestial body-related sky pass parameters
499  if (sky_pass)
500  {
501  if (reference_body)
502  sky_pass->set_planet_radius(static_cast<float>(reference_body->radius));
503  else
504  sky_pass->set_planet_radius(0.0f);
505  }
506 }
507 
508 void astronomy_system::reference_orbit_modified()
509 {
510 
511 }
512 
513 void astronomy_system::reference_atmosphere_modified()
514 {
515 
516 }
517 
518 void astronomy_system::update_bcbf_to_eus(const ::observer_component& observer, const ::celestial_body_component& body)
519 {
520  // Construct BCBF to EUS transformation
522  (
523  body.radius + observer.elevation,
524  observer.latitude,
525  observer.longitude
526  ) * enu_to_eus;
527 }
528 
529 void astronomy_system::update_icrf_to_eus(const ::celestial_body_component& body, const ::orbit_component& orbit)
530 {
531  // Evaluate reference body orientation polynomials
532  const double body_pole_ra = math::polynomial::horner(body.pole_ra.begin(), body.pole_ra.end(), time_centuries);
533  const double body_pole_dec = math::polynomial::horner(body.pole_dec.begin(), body.pole_dec.end(), time_centuries);
534  const double body_prime_meridian = math::polynomial::horner(body.prime_meridian.begin(), body.prime_meridian.end(), time_days);
535 
536  // Construct ICRF frame to BCBF transformation
538  (
539  body_pole_ra,
540  body_pole_dec,
541  body_prime_meridian
542  );
543  icrf_to_bcbf.t = icrf_to_bcbf.r * -orbit.position;
544 
546  icrf_to_eus = icrf_to_bcbf * bcbf_to_eus;
547 
548  // Pass ICRF to EUS transformation to sky pass
549  if (sky_pass)
550  {
551  // Upload topocentric frame to sky pass
552  sky_pass->set_icrf_to_eus
553  (
555  {
556  math::fvec3(icrf_to_eus.t),
557  math::fquat(icrf_to_eus.r)
558  }
559  );
560  }
561 }
562 
563 math::dvec3 astronomy_system::integrate_transmittance(const ::observer_component& observer, const ::celestial_body_component& body, const ::atmosphere_component& atmosphere, geom::ray<double, 3> ray) const
564 {
565  math::dvec3 transmittance = {1, 1, 1};
566 
567  // Make ray height relative to center of reference body
568  ray.origin.y() += body.radius + observer.elevation;
569 
570  // Construct sphere representing upper limit of the atmosphere
571  geom::sphere<double> atmosphere_sphere;
572  atmosphere_sphere.center = {0, 0, 0};
573  atmosphere_sphere.radius = body.radius + atmosphere.upper_limit;
574 
575  // Check for intersection between the ray and atmosphere
576  auto intersection = geom::intersection(ray, atmosphere_sphere);
577  if (intersection && std::get<1>(*intersection) > 0.0)
578  {
579  // Determine height at ray origin and cosine of the angle between the ray direction and local zenith direction at ray origin
580  const double height = math::length(ray.origin);
581  const double cos_view_zenith = math::dot(ray.direction, ray.origin) / height;
582 
583  // Precalculate terms re-used in sample height calculation
584  const double sqr_height = height * height;
585  const double height_cos_view_zenith = height * cos_view_zenith;
586  const double two_height_cos_view_zenith = 2.0 * height_cos_view_zenith;
587 
588  // Get distance to upper limit of atmosphere
589  const double sample_end_distance = std::get<1>(*intersection);
590 
591  // Integrate atmospheric particle densities
592  math::dvec3 densities{};
593  double previous_sample_distance = 0.0;
594  for (std::size_t i = 0; i < transmittance_samples; ++i)
595  {
596  // Determine distance along sample ray to sample point and length of the sample
597  const double sample_distance = (static_cast<double>(i) + 0.5) / static_cast<double>(transmittance_samples) * sample_end_distance;
598  const double sample_length = sample_distance - previous_sample_distance;
599  previous_sample_distance = sample_distance;
600 
601  // Calculate sample elevation
602  const double sample_height = std::sqrt(sample_distance * sample_distance + sqr_height + two_height_cos_view_zenith * sample_distance);
603  const double sample_elevation = sample_height - body.radius;
604 
605  // Weigh and sum atmospheric particle densities at sample elevation
606  densities.x() += physics::gas::atmosphere::density::exponential(1.0, sample_elevation, atmosphere.rayleigh_scale_height) * sample_length;
607  densities.y() += physics::gas::atmosphere::density::exponential(1.0, sample_elevation, atmosphere.mie_scale_height) * sample_length;
608  densities.x() += physics::gas::atmosphere::density::triangular(1.0, sample_elevation, atmosphere.ozone_lower_limit, atmosphere.ozone_upper_limit, atmosphere.ozone_mode) * sample_length;
609  }
610 
611  // Calculate extinction coefficients from integrated atmospheric particle densities
612  const math::dvec3 extinction = densities.x() * atmosphere.rayleigh_scattering +
613  densities.y() * atmosphere.mie_extinction +
614  densities.z() * atmosphere.ozone_absorption;
615 
616  // Calculate transmittance factor from extinction coefficients
617  transmittance = {std::exp(-extinction.x()), std::exp(-extinction.y()), std::exp(-extinction.z())};
618  }
619 
620  return transmittance;
621 }
void set_time(double t)
Sets the current time.
void set_moon_light(scene::directional_light *light)
virtual void update(float t, float dt)
Adds the timestep dt, scaled by set time scale, to the current time, then calculates apparent propert...
astronomy_system(entity::registry &registry)
void set_time_scale(double scale)
Sets the factor by which the timestep dt will be scaled before being added to the current time.
void set_sky_pass(::render::sky_pass *pass)
void set_observer(entity::id eid)
Sets the observer entity.
void set_starlight_illuminance(const math::dvec3 &illuminance)
void set_sun_light(scene::directional_light *light)
void set_transmittance_samples(std::size_t samples)
Sets the number of samples to take when integrating atmospheric transmittance.
void set_moon_planetlight_direction(const math::fvec3 &direction)
Definition: sky-pass.cpp:851
void set_sun_position(const math::fvec3 &position)
Definition: sky-pass.cpp:716
void set_moon_sunlight_direction(const math::fvec3 &direction)
Definition: sky-pass.cpp:841
void set_observer_elevation(float elevation)
Definition: sky-pass.cpp:762
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 set_icrf_to_eus(const math::se3< float > &transformation)
Definition: sky-pass.cpp:710
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
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_sun_luminance(const math::fvec3 &luminance)
Definition: sky-pass.cpp:727
void set_planet_radius(float radius)
Definition: sky-pass.cpp:737
Light source with parallel rays and constant intensity.
void set_illuminance(float illuminance) noexcept
Sets the illuminance of the light on a surface perpendicular to the light direction.
void set_color(const math::fvec3 &color) noexcept
Sets the color of the light.
void set_rotation(const quaternion_type &rotation)
Sets the rotation of the object.
Definition: object.hpp:96
Abstract base class for updatable systems.
entity::registry & registry
Registry on which the system operate.
T angular_radius(T radius, T distance)
Finds the angular radius of a celestial object, given its radius and distance.
entt::registry registry
Component registry type.
Definition: registry.hpp:28
entt::entity id
Entity ID type.
Definition: id.hpp:28
T cone(T theta)
Calculates the solid angle of a cone.
Definition: solid-angle.hpp:39
constexpr std::optional< T > intersection(const ray< T, N > &ray, const hyperplane< T, N > &hyperplane) noexcept
Ray-hyperplane intersection test.
constexpr T horner(InputIt first, InputIt last, T x)
Evaluates a polynomial using Horner's method.
Definition: polynomial.hpp:41
quat< float > fquat
Quaternion with single-precision floating-point scalars.
Definition: quaternion.hpp:218
constexpr vector< T, N > max(const vector< T, N > &x, const vector< T, N > &y)
Returns a vector containing the maximum elements of two vectors.
Definition: vector.hpp:1328
quaternion< T > normalize(const quaternion< T > &q)
Normalizes a quaternion.
Definition: quaternion.hpp:679
T length(const quaternion< T > &q)
Calculates the length of a quaternion.
Definition: quaternion.hpp:602
quaternion< T > look_rotation(const vec3< T > &forward, vec3< T > up)
Creates a unit quaternion rotation using forward and up vectors.
Definition: quaternion.hpp:618
constexpr mat4< T > scale(const vec3< T > &v)
Constructs a scale matrix.
vector< T, N > sqrt(const vector< T, N > &x)
Takes the square root of each element.
constexpr T dot(const quaternion< T > &a, const quaternion< T > &b) noexcept
Calculates the dot product of two quaternions.
Definition: quaternion.hpp:572
T exponential(T d0, T z, T sh)
Calculates the density of exponentially-distributed atmospheric particles at a given elevation.
Definition: atmosphere.hpp:221
T triangular(T d0, T z, T a, T b, T c)
Calculates the density of triangularly-distributed atmospheric particles at a given elevation.
Definition: atmosphere.hpp:240
T extinction(T scattering, T albedo)
Calculates an extinction coefficient.
Definition: atmosphere.hpp:121
math::se3< T > to_bci(T ra, T dec, T w)
Constructs an SE(3) transformation from a BCBF frame to a BCI frame.
Definition: frame.hpp:301
math::se3< T > to_enu(T distance, T latitude, T longitude)
Constructs an SE(3) transformation from a BCBF frame to an ENU frame.
Definition: frame.hpp:323
math::se3< T > to_bcbf(T ra, T dec, T w)
Constructs an SE(3) transformation from a BCI frame to a BCBF frame.
Definition: frame.hpp:213
Blackbody radiator.
n-dimensional sphere.
Definition: hypersphere.hpp:37
vector_type center
Hypersphere center.
Definition: hypersphere.hpp:42
T radius
Hypersphere radius.
Definition: hypersphere.hpp:45
Half of a line proceeding from an initial point.
Definition: ray.hpp:38
vector_type direction
Ray direction vector.
Definition: ray.hpp:46
vector_type origin
Ray origin position.
Definition: ray.hpp:43
Quaternion composed of a real scalar part and imaginary vector part.
Definition: quaternion.hpp:39
static quaternion rotate_x(scalar_type angle)
Returns a quaternion representing a rotation about the x-axis.
Definition: quaternion.hpp:110
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
n-dimensional vector.
Definition: vector.hpp:44
constexpr element_type & y() noexcept
Returns a reference to the second element.
Definition: vector.hpp:180