💿🐜 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.

252 lines
7.3 KiB

  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. #ifndef ANTKEEPER_PHYSICS_GAS_ATMOSPHERE_HPP
  20. #define ANTKEEPER_PHYSICS_GAS_ATMOSPHERE_HPP
  21. #include "physics/constants.hpp"
  22. #include "math/numbers.hpp"
  23. #include <algorithm>
  24. #include <cmath>
  25. namespace physics {
  26. namespace gas {
  27. /// Atmosphere-related functions.
  28. namespace atmosphere {
  29. /**
  30. * Calculates a particle polarizability factor.
  31. *
  32. * @param ior Atmospheric index of refraction.
  33. * @param density Molecular number density, in mol/m-3.
  34. * @return Polarizability factor.
  35. *
  36. * @see Elek, O., & Kmoch, P. (2010). Real-time spectral scattering in large-scale natural participating media. Proceedings of the 26th Spring Conference on Computer Graphics - SCCG 10. doi:10.1145/1925059.1925074
  37. * @see Elek, Oskar. (2009). Rendering Parametrizable Planetary Atmospheres with Multiple Scattering in Real-Time.
  38. */
  39. template <class T>
  40. T polarization(T ior, T density)
  41. {
  42. constexpr T k = T(2) * math::pi<T> * math::pi<T>;
  43. const T ior2m1 = ior * ior - T(1);
  44. const T num = k * ior2m1 * ior2m1;
  45. const T den = T(3) * density * density;
  46. return num / den;
  47. }
  48. /**
  49. * Calculates a wavelength-dependent scattering coefficient.
  50. *
  51. * @param density Molecular number density of the particles, in mol/m-3.
  52. * @param polarization Particle polarizability factor.
  53. * @param wavelength Wavelength of light, in meters.
  54. *
  55. * @return Scattering coefficient.
  56. *
  57. * @see atmosphere::polarization
  58. *
  59. * @see Elek, O., & Kmoch, P. (2010). Real-time spectral scattering in large-scale natural participating media. Proceedings of the 26th Spring Conference on Computer Graphics - SCCG 10. doi:10.1145/1925059.1925074
  60. * @see Elek, Oskar. (2009). Rendering Parametrizable Planetary Atmospheres with Multiple Scattering in Real-Time.
  61. */
  62. template <class T>
  63. T scattering(T density, T polarization, T wavelength)
  64. {
  65. const T wavelength2 = wavelength * wavelength;
  66. return math::four_pi<T> * (density / (wavelength2 * wavelength2)) * polarization;
  67. }
  68. /**
  69. * Calculates a wavelength-independent scattering coefficient.
  70. *
  71. * @param density Molecular number density of the particles, in mol/m-3.
  72. * @param polarization Particle polarizability factor.
  73. *
  74. * @return Scattering coefficient.
  75. *
  76. * @see atmosphere::polarization
  77. *
  78. * @see Elek, O., & Kmoch, P. (2010). Real-time spectral scattering in large-scale natural participating media. Proceedings of the 26th Spring Conference on Computer Graphics - SCCG 10. doi:10.1145/1925059.1925074
  79. * @see Elek, Oskar. (2009). Rendering Parametrizable Planetary Atmospheres with Multiple Scattering in Real-Time.
  80. */
  81. template <class T>
  82. T scattering(T density, T polarization)
  83. {
  84. return math::four_pi<T> * density * polarization;
  85. }
  86. /**
  87. * Calculates an absorption coefficient.
  88. *
  89. * @param scattering Scattering coefficient.
  90. * @param albedo Single-scattering albedo.
  91. *
  92. * @return Absorption coefficient.
  93. *
  94. * @see https://en.wikipedia.org/wiki/Single-scattering_albedo
  95. */
  96. template <class T>
  97. T absorption(T scattering, T albedo)
  98. {
  99. return scattering * (T(1) / albedo - T(1));
  100. }
  101. /**
  102. * Calculates an extinction coefficient.
  103. *
  104. * @param scattering Scattering coefficient.
  105. * @param albedo Single-scattering albedo.
  106. *
  107. * @return Extinction coefficient.
  108. *
  109. * @see https://en.wikipedia.org/wiki/Single-scattering_albedo
  110. */
  111. template <class T>
  112. T extinction(T scattering, T albedo)
  113. {
  114. return scattering / albedo;
  115. }
  116. /**
  117. * Approximates the optical depth of exponentially-distributed atmospheric particles between two points using the trapezoidal rule.
  118. *
  119. * @param a Start point.
  120. * @param b End point.
  121. * @param r Radius of the planet.
  122. * @param sh Scale height of the atmospheric particles.
  123. * @param n Number of samples.
  124. * @return Optical depth between @p a and @p b.
  125. */
  126. template <class T>
  127. T optical_depth_exp(const math::vector3<T>& a, const math::vector3<T>& b, T r, T sh, std::size_t n)
  128. {
  129. sh = T(-1) / sh;
  130. const T h = math::length(b - a) / T(n);
  131. math::vector3<T> dy = (b - a) / T(n);
  132. math::vector3<T> y = a + dy;
  133. T f_x = std::exp((math::length(a) - r) * sh);
  134. T f_y = std::exp((math::length(y) - r) * sh);
  135. T sum = (f_x + f_y);
  136. for (std::size_t i = 1; i < n; ++i)
  137. {
  138. f_x = f_y;
  139. y += dy;
  140. f_y = std::exp((math::length(y) - r) * sh);
  141. sum += (f_x + f_y);
  142. }
  143. return sum / T(2) * h;
  144. }
  145. /**
  146. * Approximates the optical depth of triangularly-distributed atmospheric particles between two points using the trapezoidal rule.
  147. *
  148. * @param p0 Start point.
  149. * @param p1 End point.
  150. * @param r Radius of the planet.
  151. * @param a Distribution lower limit.
  152. * @param b Distribution upper limit.
  153. * @param c Distribution upper mode.
  154. * @param n Number of samples.
  155. * @return Optical depth between @p a and @p b.
  156. */
  157. template <class T>
  158. T optical_depth_tri(const math::vector3<T>& p0, const math::vector3<T>& p1, T r, T a, T b, T c, std::size_t n)
  159. {
  160. a = T(1) / (a - c);
  161. b = T(1) / (b - c);
  162. const T h = math::length(p1 - p0) / T(n);
  163. math::vector3<T> dy = (p1 - p0) / T(n);
  164. math::vector3<T> y = p0 + dy;
  165. T z = math::length(p0) - r;
  166. T f_x = std::max(T(0), std::max(T(0), c - z) * a - std::max(T(0), z - c) * b + T(1));
  167. z = math::length(y) - r;
  168. T f_y = std::max(T(0), std::max(T(0), c - z) * a - std::max(T(0), z - c) * b + T(1));
  169. T sum = (f_x + f_y);
  170. for (std::size_t i = 1; i < n; ++i)
  171. {
  172. f_x = f_y;
  173. y += dy;
  174. z = math::length(y) - r;
  175. f_y = std::max(T(0), std::max(T(0), c - z) * a - std::max(T(0), z - c) * b + T(1));
  176. sum += (f_x + f_y);
  177. }
  178. return sum / T(2) * h;
  179. }
  180. /// Atmospheric density functions.
  181. namespace density {
  182. /**
  183. * Calculates the density of exponentially-distributed atmospheric particles at a given elevation.
  184. *
  185. * @param d0 Density at sea level.
  186. * @param z Height above sea level.
  187. * @param sh Scale height of the particle type.
  188. *
  189. * @return Particle density at elevation @p z.
  190. *
  191. * @see https://en.wikipedia.org/wiki/Barometric_formula
  192. * @see https://en.wikipedia.org/wiki/Scale_height
  193. */
  194. template <class T>
  195. T exponential(T d0, T z, T sh)
  196. {
  197. return d0 * std::exp(-z / sh);
  198. }
  199. /**
  200. * Calculates the density of triangularly-distributed atmospheric particles at a given elevation.
  201. *
  202. * @param d0 Density at sea level.
  203. * @param z Height above sea level.
  204. * @param a Distribution lower limit.
  205. * @param b Distribution upper limit.
  206. * @param c Distribution mode.
  207. *
  208. * @return Particle density at elevation @p z.
  209. *
  210. * @see https://en.wikipedia.org/wiki/Triangular_distribution
  211. */
  212. template <class T>
  213. T triangular(T d0, T z, T a, T b, T c)
  214. {
  215. return d0 * max(T(0), max(T(0), c - z) / (a - c) - max(T(0), z - c) / (b - c) + T(1));
  216. }
  217. } // namespace density
  218. } // namespace atmosphere
  219. } // namespace gas
  220. } // namespace physics
  221. #endif // ANTKEEPER_PHYSICS_GAS_ATMOSPHERE_HPP