💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

169 lines
6.1 KiB

  1. /*
  2. * Copyright (C) 2021 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. #include "game/system/atmosphere.hpp"
  20. #include "physics/gas/atmosphere.hpp"
  21. #include "physics/gas/ozone.hpp"
  22. #include "physics/number-density.hpp"
  23. namespace game {
  24. namespace system {
  25. atmosphere::atmosphere(entity::registry& registry):
  26. updatable(registry),
  27. rgb_wavelengths{0, 0, 0},
  28. rgb_ozone_cross_sections{0, 0, 0},
  29. active_atmosphere_eid(entt::null),
  30. sky_pass(nullptr)
  31. {
  32. registry.on_construct<game::component::atmosphere>().connect<&atmosphere::on_atmosphere_construct>(this);
  33. registry.on_update<game::component::atmosphere>().connect<&atmosphere::on_atmosphere_update>(this);
  34. registry.on_destroy<game::component::atmosphere>().connect<&atmosphere::on_atmosphere_destroy>(this);
  35. }
  36. atmosphere::~atmosphere()
  37. {
  38. registry.on_construct<game::component::atmosphere>().disconnect<&atmosphere::on_atmosphere_construct>(this);
  39. registry.on_update<game::component::atmosphere>().disconnect<&atmosphere::on_atmosphere_update>(this);
  40. registry.on_destroy<game::component::atmosphere>().disconnect<&atmosphere::on_atmosphere_destroy>(this);
  41. }
  42. void atmosphere::update(double t, double dt)
  43. {}
  44. void atmosphere::set_rgb_wavelengths(const double3& wavelengths)
  45. {
  46. rgb_wavelengths = wavelengths;
  47. // Update ozone cross sections
  48. rgb_ozone_cross_sections =
  49. {
  50. physics::gas::ozone::cross_section_293k<double>(wavelengths.x() * 1e9),
  51. physics::gas::ozone::cross_section_293k<double>(wavelengths.y() * 1e9),
  52. physics::gas::ozone::cross_section_293k<double>(wavelengths.z() * 1e9)
  53. };
  54. // Update atmosphere components
  55. registry.view<component::atmosphere>().each
  56. (
  57. [&](entity::id entity_id, auto& component)
  58. {
  59. update_atmosphere(entity_id);
  60. }
  61. );
  62. }
  63. void atmosphere::set_sky_pass(::render::sky_pass* pass)
  64. {
  65. sky_pass = pass;
  66. update_sky_pass();
  67. }
  68. void atmosphere::set_active_atmosphere(entity::id entity_id)
  69. {
  70. if (entity_id != active_atmosphere_eid)
  71. {
  72. active_atmosphere_eid = entity_id;
  73. update_sky_pass();
  74. }
  75. }
  76. void atmosphere::update_atmosphere(entity::id entity_id)
  77. {
  78. // Get atmosphere component of the entity
  79. game::component::atmosphere* component = registry.try_get<game::component::atmosphere>(entity_id);
  80. // Abort if entity has no atmosphere component
  81. if (!component)
  82. return;
  83. // Calculate Rayleigh scattering coefficients
  84. const double rayleigh_density = physics::number_density(component->rayleigh_concentration);
  85. const double rayleigh_polarization = physics::gas::atmosphere::polarization(component->index_of_refraction, rayleigh_density);
  86. component->rayleigh_scattering =
  87. {
  88. physics::gas::atmosphere::scattering(rayleigh_density, rayleigh_polarization, rgb_wavelengths.x()),
  89. physics::gas::atmosphere::scattering(rayleigh_density, rayleigh_polarization, rgb_wavelengths.y()),
  90. physics::gas::atmosphere::scattering(rayleigh_density, rayleigh_polarization, rgb_wavelengths.z())
  91. };
  92. // Calculate Mie scattering and extinction coefficients
  93. const double mie_density = physics::number_density(component->mie_concentration);
  94. const double mie_polarization = physics::gas::atmosphere::polarization(component->index_of_refraction, mie_density);
  95. component->mie_scattering = physics::gas::atmosphere::scattering(mie_density, mie_polarization);
  96. component->mie_extinction = physics::gas::atmosphere::extinction(component->mie_scattering, component->mie_albedo);
  97. // Calculate ozone absorption coefficients
  98. const double ozone_density = physics::number_density(component->ozone_concentration);
  99. component->ozone_absorption =
  100. {
  101. physics::gas::ozone::absorption(rgb_ozone_cross_sections.x(), ozone_density),
  102. physics::gas::ozone::absorption(rgb_ozone_cross_sections.y(), ozone_density),
  103. physics::gas::ozone::absorption(rgb_ozone_cross_sections.z(), ozone_density)
  104. };
  105. // Update sky pass parameters
  106. if (entity_id == active_atmosphere_eid)
  107. {
  108. update_sky_pass();
  109. }
  110. }
  111. void atmosphere::update_sky_pass()
  112. {
  113. // Abort if no sky pass set
  114. if (!sky_pass)
  115. return;
  116. // Abort if active atmosphere entity is not valid
  117. if (!registry.valid(active_atmosphere_eid))
  118. return;
  119. // Get atmosphere component of the entity
  120. game::component::atmosphere* component = registry.try_get<game::component::atmosphere>(active_atmosphere_eid);
  121. // Abort if entity has no atmosphere component
  122. if (!component)
  123. return;
  124. sky_pass->set_atmosphere_upper_limit(static_cast<float>(component->upper_limit));
  125. sky_pass->set_rayleigh_parameters(static_cast<float>(component->rayleigh_scale_height), math::type_cast<float>(component->rayleigh_scattering));
  126. sky_pass->set_mie_parameters(static_cast<float>(component->mie_scale_height), static_cast<float>(component->mie_scattering), static_cast<float>(component->mie_extinction), static_cast<float>(component->mie_anisotropy));
  127. sky_pass->set_ozone_parameters(static_cast<float>(component->ozone_lower_limit), static_cast<float>(component->ozone_upper_limit), static_cast<float>(component->ozone_mode), math::type_cast<float>(component->ozone_absorption));
  128. sky_pass->set_airglow_illuminance(math::type_cast<float>(component->airglow_illuminance));
  129. }
  130. void atmosphere::on_atmosphere_construct(entity::registry& registry, entity::id entity_id)
  131. {
  132. update_atmosphere(entity_id);
  133. }
  134. void atmosphere::on_atmosphere_update(entity::registry& registry, entity::id entity_id)
  135. {
  136. update_atmosphere(entity_id);
  137. }
  138. void atmosphere::on_atmosphere_destroy(entity::registry& registry, entity::id entity_id)
  139. {
  140. if (entity_id == active_atmosphere_eid)
  141. active_atmosphere_eid = entt::null;
  142. }
  143. } // namespace system
  144. } // namespace game