Browse Source

Add sky illuminance lut to sky pass. Improve calculation of atmospheric scattering coefficients. Revise color namespace. Improve vector and matrix classes.

master
C. J. Howard 1 year ago
parent
commit
e8b5693fb1
56 changed files with 2720 additions and 1453 deletions
  1. +1
    -0
      CMakeLists.txt
  2. +91
    -0
      src/color/aces.hpp
  3. +0
    -99
      src/color/acescg.hpp
  4. +106
    -0
      src/color/cat.hpp
  5. +13
    -23
      src/color/cct.hpp
  6. +4
    -1
      src/color/color.hpp
  7. +152
    -0
      src/color/illuminant.hpp
  8. +1
    -4
      src/color/index.hpp
  9. +156
    -0
      src/color/rgb.hpp
  10. +41
    -119
      src/color/srgb.hpp
  11. +4
    -13
      src/color/ucs.hpp
  12. +11
    -30
      src/color/xyy.hpp
  13. +47
    -168
      src/color/xyz.hpp
  14. +2
    -2
      src/config.hpp.in
  15. +16
    -16
      src/entity/components/atmosphere.hpp
  16. +10
    -4
      src/entity/components/observer.hpp
  17. +378
    -270
      src/entity/systems/astronomy.cpp
  18. +72
    -29
      src/entity/systems/astronomy.hpp
  19. +29
    -32
      src/entity/systems/atmosphere.cpp
  20. +0
    -7
      src/entity/systems/atmosphere.hpp
  21. +13
    -3
      src/entity/systems/blackbody.cpp
  22. +8
    -0
      src/entity/systems/blackbody.hpp
  23. +2
    -0
      src/entity/systems/terrain.cpp
  24. +147
    -0
      src/game/ant/swarm.cpp
  25. +34
    -0
      src/game/ant/swarm.hpp
  26. +1
    -3
      src/game/context.hpp
  27. +10
    -0
      src/game/controls.cpp
  28. +3
    -0
      src/game/controls.hpp
  29. +13
    -0
      src/game/load.cpp
  30. +6
    -17
      src/game/state/boot.cpp
  31. +46
    -0
      src/game/state/main-menu.cpp
  32. +90
    -89
      src/game/state/nuptial-flight.cpp
  33. +2
    -2
      src/game/tools.cpp
  34. +114
    -35
      src/game/world.cpp
  35. +3
    -0
      src/game/world.hpp
  36. +2
    -3
      src/geom/sphere.hpp
  37. +5
    -0
      src/gl/texture-2d.cpp
  38. +9
    -0
      src/gl/texture-2d.hpp
  39. +74
    -74
      src/math/matrix-functions.hpp
  40. +12
    -12
      src/math/matrix-operators.hpp
  41. +12
    -0
      src/math/matrix-type.hpp
  42. +69
    -71
      src/math/vector-functions.hpp
  43. +28
    -29
      src/math/vector-operators.hpp
  44. +77
    -59
      src/math/vector-type.hpp
  45. +36
    -42
      src/physics/gas/atmosphere.hpp
  46. +527
    -19
      src/physics/gas/ozone.hpp
  47. +3
    -3
      src/physics/light/exposure.hpp
  48. +8
    -0
      src/physics/time/jd.hpp
  49. +10
    -1
      src/render/context.hpp
  50. +3
    -3
      src/render/passes/ground-pass.cpp
  51. +3
    -3
      src/render/passes/material-pass.cpp
  52. +154
    -129
      src/render/passes/sky-pass.cpp
  53. +42
    -27
      src/render/passes/sky-pass.hpp
  54. +3
    -0
      src/render/renderer.cpp
  55. +15
    -10
      src/resources/entity-archetype-loader.cpp
  56. +2
    -2
      src/resources/material-loader.cpp

+ 1
- 0
CMakeLists.txt View File

@ -1,5 +1,6 @@
cmake_minimum_required(VERSION 3.7)
option(VERSION_STRING "Project version string" "0.0.0")
project(antkeeper VERSION ${VERSION_STRING} LANGUAGES CXX)

+ 91
- 0
src/color/aces.hpp View File

@ -0,0 +1,91 @@
/*
* Copyright (C) 2021 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_COLOR_ACES_HPP
#define ANTKEEPER_COLOR_ACES_HPP
#include "color/rgb.hpp"
#include "math/math.hpp"
namespace color {
/// ACES color spaces.
namespace aces {
/// CIE xy chromaticity coordinates of the ACES white point (~D60).
template <class T>
constexpr math::vector2<T> white_point = {T{0.32168}, {0.33767}};
/// ACES AP0 color space.
template <class T>
constexpr rgb::color_space<T> ap0
(
{T{0.7347}, T{ 0.2653}},
{T{0.0000}, T{ 1.0000}},
{T{0.0001}, T{-0.0770}},
aces::white_point<T>,
nullptr,
nullptr
);
/// ACES AP1 color space.
template <class T>
constexpr rgb::color_space<T> ap1
(
{T{0.713}, T{0.293}},
{T{0.165}, T{0.830}},
{T{0.128}, T{0.044}},
aces::white_point<T>,
nullptr,
nullptr
);
/**
* Constructs a saturation adjustment matrix.
*
* @param s Saturation adjustment factor.
* @param to_y Color space to CIE XYZ luminance vector.
*
* @return Saturation adjustment matrix.
*/
template <class T>
constexpr math::matrix<T, 3, 3> adjust_saturation(T s, const math::vector3<T>& to_y)
{
const math::vector3<T> v = to_y * (T{1} - s);
return math::matrix<T, 3, 3>
{
v[0] + s, v[0], v[0],
v[1], v[1] + s, v[1],
v[2], v[2], v[2] + s
};
}
/// ACES AP1 RRT saturation adjustment matrix.
template <class T>
constexpr math::matrix<T, 3, 3> ap1_rrt_sat = aces::adjust_saturation(T{0.96}, ap1<T>.to_y);
/// ACES AP1 ODT saturation adjustment matrix.
template <class T>
constexpr math::matrix<T, 3, 3> ap1_odt_sat = aces::adjust_saturation(T{0.93}, ap1<T>.to_y);
} // namespace aces
} // namespace color
#endif // ANTKEEPER_COLOR_ACES_HPP

+ 0
- 99
src/color/acescg.hpp View File

@ -1,99 +0,0 @@
/*
* Copyright (C) 2021 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_COLOR_ACESCG_HPP
#define ANTKEEPER_COLOR_ACESCG_HPP
#include "math/math.hpp"
namespace color {
/// Functions which operate in the ACEScg colorspace.
namespace acescg {
/// CIE chromaticity coordinates of the ACEScg white point (~D60).
template <class T>
constexpr math::vector2<T> whitepoint = {0.32168, 0.33767};
/**
* Calculates the luminance of an ACEScg color.
*
* @param x ACEScg color.
* @return return Luminance of @p x.
*/
template <class T>
T luminance(const math::vector3<T>& x);
/**
* Transforms an ACEScg color into the linear sRGB colorspace using the Bradford chromatic adaption transform.
*
* @param x ACEScg color.
* @return return Linear sRGB color.
*
* @see https://www.colour-science.org/apps/
*/
template <class T>
math::vector3<T> to_srgb(const math::vector3<T>& x);
/**
* Transforms an ACEScg color into the CIE XYZ colorspace.
*
* @param x ACEScg color.
* @return return CIE XYZ color.
*/
template <class T>
math::vector3<T> to_xyz(const math::vector3<T>& x);
template <class T>
T luminance(const math::vector3<T>& x)
{
static const math::vector3<T> luma = {0.272228716780914, 0.674081765811148, 0.053689517407937};
return math::dot(x, luma);
}
template <class T>
math::vector3<T> to_srgb(const math::vector3<T>& x)
{
static const math::matrix3<T> acescg_to_srgb
{{
{ 1.704858676289160, -0.130076824208823, -0.023964072927574},
{-0.621716021885330, 1.140735774822504, -0.128975508299318},
{-0.083299371729058, -0.010559801677511, 1.153014018916862}
}};
return acescg_to_srgb * x;
}
template <class T>
math::vector3<T> to_xyz(const math::vector3<T>& x)
{
static const math::matrix3<T> acescg_to_xyz
{{
{0.662454181108505, 0.272228716780914, -0.005574649490394},
{0.134004206456433, 0.674081765811148, 0.004060733528983},
{0.156187687004908, 0.053689517407937, 1.010339100312997}
}};
return acescg_to_xyz * x;
}
} // namespace acescg
} // namespace color
#endif // ANTKEEPER_COLOR_ACESCG_HPP

+ 106
- 0
src/color/cat.hpp View File

@ -0,0 +1,106 @@
/*
* Copyright (C) 2021 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_COLOR_CAT_HPP
#define ANTKEEPER_COLOR_CAT_HPP
#include "math/math.hpp"
namespace color {
/// Chromatic adaption transforms (CAT).
namespace cat {
/**
* Bradford cone response matrix.
*
* @see Specification ICC.1:2010 (Profile version 4.3.0.0). Image technology colour management Architecture, profile format, and data structure, Annex E.3, pp. 102.
* @see http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
*/
template <class T>
constexpr math::matrix<T, 3, 3> bradford =
{
0.8951, -0.7502, 0.0389,
0.2664, 1.7135, -0.0685,
-0.1614, 0.0367, 1.0296
};
/**
* von Kries cone response matrix.
*
* @see http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
*/
template <class T>
constexpr math::matrix<T, 3, 3> von_kries =
{
0.40024, -0.22630, 0.00000
0.70760, 1.16532, 0.00000
-0.08081, 0.04570, 0.91822
};
/**
* XYZ scaling cone response matrix.
*
* @see http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
*/
template <class T>
constexpr math::matrix<T, 3, 3> xyz_scaling =
{
T{1}, T{0}. T{0},
T{0}, T{1}. T{0},
T{0}, T{0}. T{1}
};
/**
* Constructs a chromatic adaptation transform (CAT) matrix.
*
* @param w0 CIE xy chromaticity coordinates of the source illuminant.
* @param w1 CIE xy chromaticity coordinates of the destination illuminant.
* @param cone_response Cone response matrix.
*
* @return CAT matrix.
*
* @see Specification ICC.1:2010 (Profile version 4.3.0.0). Image technology colour management Architecture, profile format, and data structure, Annex E.3, pp. 102.
* @see http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
*/
template <class T>
constexpr math::matrix<T, 3, 3> matrix(const math::vector2<T>& w0, const math::vector2<T>& w1, const math::matrix<T, 3, 3>& cone_response = bradford<T>)
{
// Convert CIE xy chromaticity coordinates to CIE XYZ colors
const math::vector3<T> w0_xyz = {w0[0] / w0[1], T{1}, (T{1} - w0[0] - w0[1]) / w0[1]};
const math::vector3<T> w1_xyz = {w1[0] / w1[1], T{1}, (T{1} - w1[0] - w1[1]) / w1[1]};
// Calculate cone response of CIE XYZ colors
const math::vector3<T> w0_cone_response = cone_response * w0_xyz;
const math::vector3<T> w1_cone_response = cone_response * w1_xyz;
const math::matrix<T, 3, 3> scale =
{
w1_cone_response[0] / w0_cone_response[0], T{0}, T{0},
T{0}, w1_cone_response[1] / w0_cone_response[1], T{0},
T{0}, T{0}, w1_cone_response[2] / w0_cone_response[2],
};
return math::inverse(cone_response) * scale * cone_response;
}
} // namespace cat
} // namespace color
#endif // ANTKEEPER_COLOR_CAT_HPP

+ 13
- 23
src/color/cct.hpp View File

@ -38,7 +38,15 @@ namespace cct {
* @see Krystek, M. (1985), An algorithm to calculate correlated colour temperature. Color Res. Appl., 10: 38-40.
*/
template <class T>
math::vector2<T> to_ucs(T t);
math::vector2<T> to_ucs(T t)
{
const T tt = t * t;
return math::vector2<T>
{
(T{0.860117757} + T{1.54118254e-4} * t + T{1.28641212e-7} * tt) / (T{1} + T{8.42420235e-4} * t + T{7.08145163e-7} * tt),
(T{0.317398726} + T{4.22806245e-5} * t + T{4.20481691e-8} * tt) / (T{1} - T{2.89741816e-5} * t + T{1.61456053e-7} * tt)
};
}
/**
* Calculates CIE xyY colorspace chromaticity coordinates given a correlated color temperature using Krystek's algorithm.
@ -47,7 +55,10 @@ math::vector2 to_ucs(T t);
* @return CIE xyY color with `Y = 1`.
*/
template <class T>
math::vector3<T> to_xyy(T t);
math::vector3<T> to_xyy(T t)
{
return ucs::to_xyy(to_ucs(t), T{1});
}
/**
* Calculates CIE XYZ colorspace chromaticity coordinates given a correlated color temperature using Krystek's algorithm.
@ -55,27 +66,6 @@ math::vector3 to_xyy(T t);
* @param t Correlated color temperature, in Kelvin.
* @return CIE XYZ color with `Y = 1`.
*/
template <class T>
math::vector3<T> to_xyz(T t);
template <class T>
math::vector2<T> to_ucs(T t)
{
// Approximate the Planckian locus in CIE 1960 UCS colorspace (Krystek's algorithm)
const T tt = t * t;
return math::vector2<T>
{
(T(0.860117757) + T(1.54118254e-4) * t + T(1.28641212e-7) * tt) / (T(1.0) + T(8.42420235e-4) * t + T(7.08145163e-7) * tt),
(T(0.317398726) + T(4.22806245e-5) * t + T(4.20481691e-8) * tt) / (T(1.0) - T(2.89741816e-5) * t + T(1.61456053e-7) * tt)
};
}
template <class T>
math::vector3<T> to_xyy(T t)
{
return ucs::to_xyy(to_ucs(t), T(1.0));
}
template <class T>
math::vector3<T> to_xyz(T t)
{

+ 4
- 1
src/color/color.hpp View File

@ -23,12 +23,15 @@
/// Color manipulation functions.
namespace color {}
#include "acescg.hpp"
#include "aces.hpp"
#include "cct.hpp"
#include "index.hpp"
#include "rgb.hpp"
#include "srgb.hpp"
#include "ucs.hpp"
#include "xyy.hpp"
#include "xyz.hpp"
#include "cat.hpp"
#include "illuminant.hpp"
#endif // ANTKEEPER_COLOR_HPP

+ 152
- 0
src/color/illuminant.hpp View File

@ -0,0 +1,152 @@
/*
* Copyright (C) 2021 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_COLOR_ILLUMINANT_HPP
#define ANTKEEPER_COLOR_ILLUMINANT_HPP
#include "math/math.hpp"
namespace color {
/**
* CIE standard illuminants.
*
* @see https://en.wikipedia.org/wiki/Standard_illuminant
*/
namespace illuminant {
/// CIE 1931 2 Degree Standard Observer illuminants.
namespace deg2 {
template <class T>
constexpr math::vector2<T> a = {T{0.44757}, T{0.40745}};
template <class T>
constexpr math::vector2<T> b = {T{0.34842}, T{0.35161}};
template <class T>
constexpr math::vector2<T> c = {T{0.31006}, T{0.31616}};
template <class T>
constexpr math::vector2<T> d50 = {T{0.34567}, T{0.35850}};
template <class T>
constexpr math::vector2<T> d55 = {T{0.33242}, T{0.34743}};
template <class T>
constexpr math::vector2<T> d65 = {T{0.31271}, T{0.32902}};
template <class T>
constexpr math::vector2<T> d75 = {T{0.29902}, T{0.31485}};
template <class T>
constexpr math::vector2<T> d93 = {T{0.28315}, T{0.29711}};
template <class T>
constexpr math::vector2<T> e = {T{0.33333}, T{0.33333}};
template <class T>
constexpr math::vector2<T> f1 = {T{0.31310}, T{0.33727}};
template <class T>
constexpr math::vector2<T> f2 = {T{0.37208}, T{0.37529}};
template <class T>
constexpr math::vector2<T> f3 = {T{0.40910}, T{0.39430}};
template <class T>
constexpr math::vector2<T> f4 = {T{0.44018}, T{0.40329}};
template <class T>
constexpr math::vector2<T> f5 = {T{0.31379}, T{0.34531}};
template <class T>
constexpr math::vector2<T> f6 = {T{0.37790}, T{0.38835}};
template <class T>
constexpr math::vector2<T> f7 = {T{0.31292}, T{0.32933}};
template <class T>
constexpr math::vector2<T> f8 = {T{0.34588}, T{0.35875}};
template <class T>
constexpr math::vector2<T> f9 = {T{0.37417}, T{0.37281}};
template <class T>
constexpr math::vector2<T> f10 = {T{0.34609}, T{0.35986}};
template <class T>
constexpr math::vector2<T> f11 = {T{0.38052}, T{0.37713}};
template <class T>
constexpr math::vector2<T> f12 = {T{0.43695}, T{0.40441}};
template <class T>
constexpr math::vector2<T> led_b1 = {T{0.4560}, T{0.4078}};
template <class T>
constexpr math::vector2<T> led_b2 = {T{0.4357}, T{0.4012}};
template <class T>
constexpr math::vector2<T> led_b3 = {T{0.3756}, T{0.3723}};
template <class T>
constexpr math::vector2<T> led_b4 = {T{0.3422}, T{0.3502}};
template <class T>
constexpr math::vector2<T> led_b5 = {T{0.3118}, T{0.3236}};
template <class T>
constexpr math::vector2<T> led_bh1 = {T{0.4474}, T{0.4066}};
template <class T>
constexpr math::vector2<T> led_rgb1 = {T{0.4557}, T{0.4211}};
template <class T>
constexpr math::vector2<T> led_v1 = {T{0.4560}, T{0.4548}};
template <class T>
constexpr math::vector2<T> led_v2 = {T{0.3781}, T{0.3775}};
} // deg2
/// CIE 1964 10 Degree Standard Observer illuminants.
namespace deg10 {
template <class T>
constexpr math::vector2<T> a = {T{0.45117}, T{0.40594}};
template <class T>
constexpr math::vector2<T> b = {T{0.34980}, T{0.35270}};
template <class T>
constexpr math::vector2<T> c = {T{0.31039}, T{0.31905}};
template <class T>
constexpr math::vector2<T> d50 = {T{0.34773}, T{0.35952}};
template <class T>
constexpr math::vector2<T> d55 = {T{0.33411}, T{0.34877}};
template <class T>
constexpr math::vector2<T> d65 = {T{0.31382}, T{0.33100}};
template <class T>
constexpr math::vector2<T> d75 = {T{0.29968}, T{0.31740}};
template <class T>
constexpr math::vector2<T> d93 = {T{0.28327}, T{0.30043}};
template <class T>
constexpr math::vector2<T> e = {T{0.33333}, T{0.33333}};
template <class T>
constexpr math::vector2<T> f1 = {T{0.31811}, T{0.33559}};
template <class T>
constexpr math::vector2<T> f2 = {T{0.37925}, T{0.36733}};
template <class T>
constexpr math::vector2<T> f3 = {T{0.41761}, T{0.38324}};
template <class T>
constexpr math::vector2<T> f4 = {T{0.44920}, T{0.39074}};
template <class T>
constexpr math::vector2<T> f5 = {T{0.31975}, T{0.34246}};
template <class T>
constexpr math::vector2<T> f6 = {T{0.38660}, T{0.37847}};
template <class T>
constexpr math::vector2<T> f7 = {T{0.31569}, T{0.32960}};
template <class T>
constexpr math::vector2<T> f8 = {T{0.34902}, T{0.35939}};
template <class T>
constexpr math::vector2<T> f9 = {T{0.37829}, T{0.37045}};
template <class T>
constexpr math::vector2<T> f10 = {T{0.35090}, T{0.35444}};
template <class T>
constexpr math::vector2<T> f11 = {T{0.38541}, T{0.37123}};
template <class T>
constexpr math::vector2<T> f12 = {T{0.44256}, T{0.39717}};
} // namespace deg10
} // namespace illuminant
} // namespace color
#endif // ANTKEEPER_COLOR_ILLUMINANT_HPP

+ 1
- 4
src/color/index.hpp View File

@ -33,13 +33,10 @@ namespace index {
*
* @see Ballesteros, F. J. (2012). "New insights into black bodies". EPL 97 (2012) 34008.
*/
template <class T>
T bv_to_cct(T bv);
template <class T>
T bv_to_cct(T bv)
{
return T(4600.0) * (T(1.0) / (T(0.92) * bv + T(1.7)) + T(1.0) / (T(0.92) * bv + T(0.62)));
return T{4600} * (T{1} / (T{0.92} * bv + T{1.7}) + T{1} / (T{0.92} * bv + T{0.62}));
}
} // namespace index

+ 156
- 0
src/color/rgb.hpp View File

@ -0,0 +1,156 @@
/*
* Copyright (C) 2021 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_COLOR_RGB_HPP
#define ANTKEEPER_COLOR_RGB_HPP
#include "color/cat.hpp"
#include "math/math.hpp"
namespace color {
/// Functions which operate on various RGB colorspaces.
namespace rgb {
/**
* Constructs a matrix which transforms an RGB color into a CIE XYZ color.
*
* @param r CIE xy chromaticity coordinates of the red primary.
* @param g CIE xy chromaticity coordinates of the green primary.
* @param b CIE xy chromaticity coordinates of the blue primary.
* @param w CIE xy chromaticity coordinates of the white point.
*
* @return Matrix which transforms an RGB color into a CIE XYZ color.
*
* @see https://www.ryanjuckett.com/rgb-color-space-conversion/
* @see https://mina86.com/2019/srgb-xyz-matrix/
*/
template <class T>
constexpr math::matrix<T, 3, 3> to_xyz(const math::vector2<T>& r, const math::vector2<T>& g, const math::vector2<T>& b, const math::vector2<T>& w)
{
const math::matrix<T, 3, 3> m =
{
r[0], r[1], T{1} - (r[0] + r[1]),
g[0], g[1], T{1} - (g[0] + g[1]),
b[0], b[1], T{1} - (b[0] + b[1])
};
const math::vector3<T> scale = math::inverse(m) * math::vector3<T>{w[0] / w[1], T{1}, (T{1} - (w[0] + w[1])) / w[1]};
return math::matrix<T, 3, 3>
{
m[0][0] * scale[0], m[0][1] * scale[0], m[0][2] * scale[0],
m[1][0] * scale[1], m[1][1] * scale[1], m[1][2] * scale[1],
m[2][0] * scale[2], m[2][1] * scale[2], m[2][2] * scale[2],
};
}
/**
* RGB color space.
*/
template <class T>
struct color_space
{
/// Transfer function function pointer type.
typedef math::vector3<T> (*transfer_function_type)(const math::vector3<T>&);
/// CIE xy chromaticity coordinates of the red primary.
const math::vector2<T> r;
/// CIE xy chromaticity coordinates of the green primary.
const math::vector2<T> g;
/// CIE xy chromaticity coordinates of the blue primary.
const math::vector2<T> b;
/// CIE xy chromaticity coordinates of the white point.
const math::vector2<T> w;
/// Function pointer to the electro-optical transfer function.
const transfer_function_type eotf;
/// Function pointer to the inverse electro-optical transfer function.
const transfer_function_type inverse_eotf;
/// Matrix which transforms an RGB color to a CIE XYZ color.
const math::matrix3x3<T> to_xyz;
/// Matrix which transforms a CIE XYZ color to an RGB color.
const math::matrix3x3<T> from_xyz;
/// Vector which gives the luminance of an RGB color via dot product.
const math::vector3<T> to_y;
/**
* Constructs an RGB color space.
*
* @param r CIE xy chromaticity coordinates of the red primary.
* @param g CIE xy chromaticity coordinates of the green primary.
* @param b CIE xy chromaticity coordinates of the blue primary.
* @param w CIE xy chromaticity coordinates of the white point.
*/
constexpr color_space(const math::vector2<T>& r, const math::vector2<T>& g, const math::vector2<T>& b, const math::vector2<T>& w, transfer_function_type eotf, transfer_function_type inverse_eotf);
/**
* Measures the luminance of a linear RGB color.
*
* @param x Linear RGB color.
* @return return Luminance of @p x.
*/
constexpr T luminance(const math::vector3<T>& x) const;
};
template <class T>
constexpr color_space<T>::color_space(const math::vector2<T>& r, const math::vector2<T>& g, const math::vector2<T>& b, const math::vector2<T>& w, transfer_function_type eotf, transfer_function_type inverse_eotf):
r(r),
g(g),
b(b),
w(w),
eotf(eotf),
inverse_eotf(inverse_eotf),
to_xyz(color::rgb::to_xyz<T>(r, g, b, w)),
from_xyz(math::inverse(to_xyz)),
to_y{to_xyz[0][1], to_xyz[1][1], to_xyz[2][1]}
{}
template <class T>
constexpr T color_space<T>::luminance(const math::vector3<T>& x) const
{
return math::dot(x, to_y);
}
/**
* Constructs a matrix which transforms a color from one RGB color space to another RGB color space.
*
* @param s0 Source color space.
* @param s1 Destination color space.
* @param cone_response Chromatic adaptation transform cone response matrix.
*
* @return Color space transformation matrix.
*/
template <class T>
constexpr math::matrix3x3<T> to_rgb(const color_space<T>& s0, const color_space<T>& s1, const math::matrix3x3<T>& cone_response = color::cat::bradford<T>)
{
return s1.from_xyz * color::cat::matrix(s0.w, s1.w, cone_response) * s0.to_xyz;
}
} // namespace rgb
} // namespace color
#endif // ANTKEEPER_COLOR_RGB_HPP

+ 41
- 119
src/color/srgb.hpp View File

@ -20,149 +20,71 @@
#ifndef ANTKEEPER_COLOR_SRGB_HPP
#define ANTKEEPER_COLOR_SRGB_HPP
#include "color/rgb.hpp"
#include "color/illuminant.hpp"
#include "math/math.hpp"
#include <cmath>
namespace color {
/// Functions which operate in the sRGB colorspace.
namespace srgb {
/// CIE chromaticity coordinates of the sRGB white point (D65)
template <class T>
constexpr math::vector2<T> whitepoint = {0.31271, 0.32902};
/**
* Performs the sRGB Electro-Optical Transfer Function (EOTF), also known as the sRGB decoding function.
* sRGB electro-optical transfer function (EOTF), also known as the sRGB decoding function.
*
* @param v sRGB electrical signal (gamma-encoded sRGB).
*
* @return Corresponding luminance of the signal (linear sRGB).
*/
/// @{
float eotf(float v);
double eotf(double v);
template <class T>
math::vector3<T> eotf(const math::vector3<T>& v);
/// @}
math::vector3<T> srgb_eotf(const math::vector3<T>& v)
{
auto f = [](T x) -> T
{
return x < T{0.04045} ? x / T{12.92} : std::pow((x + T{0.055}) / T{1.055}, T{2.4});
};
return math::vector3<T>
{
f(v[0]),
f(v[1]),
f(v[2])
};
}
/**
* Performs the sRGB inverse Electro-Optical Transfer Function (EOTF), also known as the sRGB encoding function.
* sRGB inverse electro-optical transfer function (EOTF), also known as the sRGB encoding function.
*
* @param l sRGB luminance (linear sRGB).
* @return Corresponding electrical signal (gamma-encoded sRGB).
*/
/// @{
float eotf_inverse(float v);
double eotf_inverse(double v);
template <class T>
math::vector3<T> eotf_inverse(const math::vector3<T>& l);
/// @}
/**
* Calculates the luminance of a linear sRGB color.
*
* @param x Linear sRGB color.
* @return return Luminance of @p x.
*/
template <class T>
T luminance(const math::vector3<T>& x);
/**
* Transforms a linear sRGB color into the ACEScg colorspace using the Bradford chromatic adaption transform.
*
* @param x Linear sRGB color.
* @return ACEScg color.
*
* @see https://www.colour-science.org/apps/
*/
template <class T>
math::vector3<T> to_acescg(const math::vector3<T>& x);
/**
* Transforms a linear sRGB color into the CIE XYZ colorspace.
*
* @param x Linear sRGB color.
* @return CIE XYZ color.
* @return Corresponding electrical signal (gamma-encoded sRGB).
*/
template <class T>
math::vector3<T> to_xyz(const math::vector3<T>& x);
inline float eotf(float v)
{
return (v < 0.04045f) ? (v / 12.92f) : std::pow((v + 0.055f) / 1.055f, 2.4f);
}
inline double eotf(double v)
math::vector3<T> srgb_inverse_eotf(const math::vector3<T>& l)
{
return (v < 0.04045) ? (v / 12.92) : std::pow((v + 0.055) / 1.055, 2.4);
}
template <class T>
math::vector3<T> eotf(const math::vector3<T>& v)
{
return math::vector3<T>
{
eotf(v[0]),
eotf(v[1]),
eotf(v[2])
};
}
inline float eotf_inverse(float l)
{
return (l <= 0.0031308f) ? (l * 12.92f) : (std::pow(l, 1.0f / 2.4f) * 1.055f - 0.055f);
}
inline double eotf_inverse(double l)
{
return (l <= 0.0031308) ? (l * 12.92) : (std::pow(l, 1.0 / 2.4) * 1.055 - 0.055);
}
template <class T>
math::vector3<T> eotf_inverse(const math::vector3<T>& l)
{
return math::vector3<T>
{
eotf_inverse(l[0]),
eotf_inverse(l[1]),
eotf_inverse(l[2])
};
}
template <class T>
T luminance(const math::vector3<T>& x)
{
static const math::vector3<T> luma = {0.212639005871510, 0.715168678767756, 0.072192315360734};
return math::dot(x, luma);
}
template <class T>
math::vector3<T> to_acescg(const math::vector3<T>& x)
{
static const math::matrix3<T> srgb_to_acescg
{{
{0.613132422390542, 0.070124380833917, 0.020587657528185},
{0.339538015799666, 0.916394011313573, 0.109574571610682},
{0.047416696048269, 0.013451523958235, 0.869785404035327}
}};
auto f = [](T x) -> T
{
return x <= T{0.0031308} ? x * T{12.92} : std::pow(x, T{1} / T{2.4}) * T{1.055} - T{0.055};
};
return srgb_to_acescg * x;
return math::vector3<T>
{
f(l[0]),
f(l[1]),
f(l[2])
};
}
/// sRGB color space.
template <class T>
math::vector3<T> to_xyz(const math::vector3<T>& x)
{
static const math::matrix3<T> srgb_to_xyz
{{
{0.412390799265959, 0.212639005871510, 0.019330818715592},
{0.357584339383878, 0.715168678767756, 0.119194779794626},
{0.180480788401834, 0.072192315360734, 0.950532152249661}
}};
return srgb_to_xyz * x;
}
constexpr rgb::color_space<T> srgb
(
{T{0.64}, T{0.33}},
{T{0.30}, T{0.60}},
{T{0.15}, T{0.06}},
color::illuminant::deg2::d65<T>,
&srgb_eotf<T>,
&srgb_inverse_eotf
);
} // namespace srgb
} // namespace color
#endif // ANTKEEPER_COLOR_SRGB_HPP

+ 4
- 13
src/color/ucs.hpp View File

@ -31,23 +31,14 @@ namespace ucs {
* Transforms CIE 1960 UCS chromaticity coordinates into the CIE xyY colorspace.
*
* @param uv CIE 1960 UCS chromaticity coordinates.
* @param luminance Luminance or `Y` value of the resulting xyY color.
* @param y Luminance or `Y` value of the resulting xyY color.
* @return CIE xyY color.
*/
template <class T>
math::vector3<T> to_xyy(const math::vector2<T>& uv, T luminance = T(1.0));
template <class T>
math::vector3<T> to_xyy(const math::vector2<T>& uv, T luminance)
constexpr math::vector3<T> to_xyy(const math::vector2<T>& uv, T y = T{1})
{
const T inverse_denom = T(1.0) / (T(2.0) * uv[0] - T(8.0) * uv[1] + T(4.0));
return math::vector3<T>
{
(T(3.0) * uv[0]) * inverse_denom,
(T(2.0) * uv[1]) * inverse_denom,
luminance
};
const T d = T{1} / (T{2} * uv[0] - T{8} * uv[1] + T{4});
return math::vector3<T>{(T{3} * uv[0]) * d, (T{2} * uv[1]) * d, y};
}
} // namespace ucs

+ 11
- 30
src/color/xyy.hpp View File

@ -34,7 +34,10 @@ namespace xyy {
* @return return Luminance of @p x.
*/
template <class T>
T luminance(const math::vector3<T>& x);
constexpr inline T luminance(const math::vector3<T>& x)
{
return x[2];
}
/**
* Transforms a CIE xyY color into the CIE 1960 UCS colorspace.
@ -43,7 +46,11 @@ T luminance(const math::vector3& x);
* @return CIE 1960 UCS color.
*/
template <class T>
math::vector2<T> to_ucs(const math::vector3<T>& x);
constexpr math::vector2<T> to_ucs(const math::vector3<T>& x)
{
const T d = T({1} / (T{-2} * x[0] + T{12} * x[1] + T{3}));
return math::vector2<T>{(T{4} * x[0]) * d, (T{6} * x[1]) * d};
}
/**
* Transforms a CIE xyY color into the CIE XYZ colorspace.
@ -52,35 +59,9 @@ math::vector2 to_ucs(const math::vector3& x);
* @return CIE XYZ color.
*/
template <class T>
math::vector3<T> to_xyz(const math::vector3<T>& x);
template <class T>
inline T luminance(const math::vector3<T>& x)
{
return x[2];
}
template <class T>
math::vector2<T> to_ucs(const math::vector3<T>& x)
{
const T inverse_denom = T(1.0) / (T(-2.0) * x[0] + T(12.0) * x[1] + T(3.0));
return math::vector2<T>
{
(T(4.0) * x[0]) * inverse_denom,
(T(6.0) * x[1]) * inverse_denom
};
}
template <class T>
math::vector3<T> to_xyz(const math::vector3<T>& x)
constexpr math::vector3<T> to_xyz(const math::vector3<T>& x)
{
return math::vector3<T>
{
(x[0] * x[2]) / x[1],
x[2],
((T(1.0) - x[0] - x[1]) * x[2]) / x[1]
};
return math::vector3<T>{(x[0] * x[2]) / x[1], x[2], ((T{1} - x[0] - x[1]) * x[2]) / x[1]};
}
} // namespace xyy

+ 47
- 168
src/color/xyz.hpp View File

@ -25,7 +25,7 @@
namespace color {
/**
* Functions which operate in the CIE XYZ colorspace.
* Functions which operate in the CIE XYZ color space.
*
* @see https://en.wikipedia.org/wiki/CIE_1931_color_space
*/
@ -38,22 +38,23 @@ namespace xyz {
* @return return Luminance of @p x.
*/
template <class T>
T luminance(const math::vector3<T>& x);
constexpr inline T luminance(const math::vector3<T>& x)
{
return x[1];
}
/**
* Fitted piecewise gaussian approximation to the CIE 1931 standard observer color matching function.
* Transforms a CIE XYZ color into the CIE xyY color space.
*
* @param lambda Wavelength of light, in nanometers.
* @return Matching CIE XYZ color.
*
* @see match_x(T)
* @see match_y(T)
* @see match_z(T)
*
* @see Wyman, C., Sloan, P.J., & Shirley, P. (2013). Simple Analytic Approximations to the CIE XYZ Color Matching Functions.
* @param x CIE XYZ color.
* @return CIE xyY color.
*/
template <class T>
math::vector3<T> match(T lambda);
constexpr math::vector3<T> to_xyy(const math::vector3<T>& x)
{
const T sum = x[0] + x[1] + x[2];
return math::vector3<T>{x[0] / sum, x[1] / sum, x[1]}
}
/**
* CIE 1931 standard observer color matching function for the X tristimulus value.
@ -63,98 +64,6 @@ math::vector3 match(T lambda);
*
* @see match(T)
*/
template <class T>
T match_x(T lambda);
/**
* CIE 1931 standard observer color matching function for the Y tristimulus value.
*
* @param lambda Wavelength of light, in nanometers.
* @return Matching Y tristimulus value.
*
* @see match(T)
*/
template <class T>
T match_y(T lambda);
/**
* CIE 1931 standard observer color matching function for the Z tristimulus value.
*
* @param lambda Wavelength of light, in nanometers.
* @return Matching Z tristimulus value.
*
* @see match(T)
*/
template <class T>
T match_z(T lambda);
/**
* Transforms a CIE XYZ color into the ACEScg colorspace.
*
* @param x CIE XYZ color.
* @return ACEScg color.
*/
template <class T>
math::vector3<T> to_acescg(const math::vector3<T>& x);
/**
* Transforms a CIE XYZ color into the linear sRGB colorspace.
*
* @param x CIE XYZ color.
* @return Linear sRGB color.
*/
template <class T>
math::vector3<T> to_srgb(const math::vector3<T>& x);
/**
* Transforms a CIE XYZ color into the CIE xyY colorspace.
*
* @param x CIE XYZ color.
* @return CIE xyY color.
*/
template <class T>
math::vector3<T> to_xyy(const math::vector3<T>& x);
/// Chromatic Adaptation Transforms (CATs).
namespace cat {
/**
* Transforms a CIE XYZ color with an ACES (~D60) illuminant to a CIE XYZ color with a D65 illuminant using the Bradford chromatic adaption transform.
*
* @param x CIE XYZ color with an ACES (~D60) illuminant.
* @return CIE XYZ color with a D65 illuminant.
*/
template <class T>
math::vector3<T> aces_to_d65(const math::vector3<T>& x);
/**
* Transforms a CIE XYZ color with a D65 illuminant to a CIE XYZ color with an ACES (~D60) illuminant using the Bradford chromatic adaption transform.
*
* @param x CIE XYZ color with a D65 illuminant.
* @return CIE XYZ color with an ACES (~D60) illuminant.
*/
template <class T>
math::vector3<T> d65_to_aces(const math::vector3<T>& x);
} // namespace cat
template <class T>
inline T luminance(const math::vector3<T>& x)
{
return x[1];
}
template <class T>
math::vector3<T> match(T lambda)
{
return math::vector3<T>
{
match_x<T>(lambda),
match_y<T>(lambda),
match_z<T>(lambda)
};
}
template <class T>
T match_x(T lambda)
{
@ -169,6 +78,14 @@ T match_x(T lambda)
return x0 + x1 + x2;
}
/**
* CIE 1931 standard observer color matching function for the Y tristimulus value.
*
* @param lambda Wavelength of light, in nanometers.
* @return Matching Y tristimulus value.
*
* @see match(T)
*/
template <class T>
T match_y(T lambda)
{
@ -181,6 +98,14 @@ T match_y(T lambda)
return y0 + y1;
}
/**
* CIE 1931 standard observer color matching function for the Z tristimulus value.
*
* @param lambda Wavelength of light, in nanometers.
* @return Matching Z tristimulus value.
*
* @see match(T)
*/
template <class T>
T match_z(T lambda)
{
@ -193,74 +118,28 @@ T match_z(T lambda)
return z0 + z1;
}
/**
* Fitted piecewise gaussian approximation to the CIE 1931 standard observer color matching function.
*
* @param lambda Wavelength of light, in nanometers.
* @return Matching CIE XYZ color.
*
* @see match_x(T)
* @see match_y(T)
* @see match_z(T)
*
* @see Wyman, C., Sloan, P.J., & Shirley, P. (2013). Simple Analytic Approximations to the CIE XYZ Color Matching Functions.
*/
template <class T>
math::vector3<T> to_acescg(const math::vector3<T>& x)
{
static const math::matrix3<T> xyz_to_acescg
{{
{ 1.641023379694326, -0.663662858722983, 0.011721894328375},
{-0.324803294184790, 1.615331591657338, -0.008284441996237},
{-0.236424695237612, 0.016756347685530, 0.988394858539022}
}};
return xyz_to_acescg * x;
}
template <class T>
math::vector3<T> to_srgb(const math::vector3<T>& x)
{
static const math::matrix3<T> xyz_to_srgb
{{
{ 3.240969941904523, -0.969243636280880, 0.055630079696994},
{-1.537383177570094, 1.875967501507721, -0.203976958888977},
{-0.498610760293003, 0.041555057407176, 1.056971514242879}
}};
return xyz_to_srgb * x;
}
template <class T>
math::vector3<T> to_xyy(const math::vector3<T>& x)
math::vector3<T> match(T lambda)
{
const T sum = x[0] + x[1] + x[2];
return math::vector3<T>
{
x[0] / sum
x[1] / sum,
x[1]
};
}
namespace cat {
template <class T>
math::vector3<T> aces_to_d65(const math::vector3<T>& x)
{
static const math::matrix3<T> cat_aces_to_d65
{{
{ 0.987225397551079, -0.007603864790602, 0.003066041131217},
{-0.006114800968213, 1.001874800208719, -0.005084242870792},
{ 0.015926393295811, 0.005322023893623, 1.081519155692042}
}};
return cat_aces_to_d65 * x;
}
template <class T>
math::vector3<T> d65_to_aces(const math::vector3<T>& x)
{
static const math::matrix3<T> cat_d65_to_aces
{{
{ 1.013033366661459, 0.007703617525351, -0.002835673220262},
{ 0.006107049021859, 0.998150224406968, 0.004675010768250},
{-0.014947927269674, -0.005025218608126, 0.924644077051100}
}};
return cat_d65_to_aces * x;
}
} // namespace cat
match_x<T>(lambda),
match_y<T>(lambda),
match_z<T>(lambda)
};
}
} // namespace xyz
} // namespace color

+ 2
- 2
src/config.hpp.in View File

@ -44,7 +44,7 @@ constexpr float menu_fade_out_duration = 0.125f;
constexpr float menu_mouseover_padding = 0.1f;
/// Opacity of the menu background.
constexpr float menu_bg_opacity = 2.0f / 3.0f;
constexpr float menu_bg_opacity = 2.0f / 4.0f;
/// RGBA color of active menu items.
constexpr float4 menu_active_color{1.0f, 1.0f, 1.0f, 1.0f};
@ -66,7 +66,7 @@ constexpr float nuptial_flight_fade_in_duration = 5.0f;
#define MATERIAL_PASS_MAX_AMBIENT_LIGHT_COUNT 1
#define MATERIAL_PASS_MAX_POINT_LIGHT_COUNT 1
#define MATERIAL_PASS_MAX_DIRECTIONAL_LIGHT_COUNT 2
#define MATERIAL_PASS_MAX_DIRECTIONAL_LIGHT_COUNT 3
#define MATERIAL_PASS_MAX_SPOTLIGHT_COUNT 1
#define MATERIAL_PASS_MAX_BONE_COUNT 64
#define TERRAIN_PATCH_SIZE 200.0f

+ 16
- 16
src/entity/components/atmosphere.hpp View File

@ -34,32 +34,35 @@ struct atmosphere
/// Index of refraction of air at sea level.
double index_of_refraction;
/// Molar concentration of air at sea level, in mol/m-3.
double air_concentration;
/// Molar concentration of Rayleigh particles at sea level, in mol/m-3.
double rayleigh_concentration;
/// Scale height of the exponential distribution of Rayleigh particles, in meters.
double rayleigh_scale_height;
/// Molecular density of Rayleigh particles at sea level.
double rayleigh_density;
/// (Dependent) Rayleigh scattering coefficients.
double3 rayleigh_scattering;
/// Molar concentration of Mie particles at sea level, in mol/m-3.
double mie_concentration;
/// Scale height of the exponential distribution of Mie particles, in meters.
double mie_scale_height;
/// Molecular density of Mie particles at sea level.
double mie_density;
/// Mie phase function anisotropy factor.
double mie_anisotropy;
/// Mie single-scattering albedo.
double mie_albedo;
/// (Dependent) Mie scattering coefficient.
double mie_scattering;
/// (Dependent) Mie absorption coefficient.
double mie_absorption;
/// (Dependent) Mie extinction coefficient.
double mie_extinction;
/// Mie phase function anisotropy factor.
double mie_anisotropy;
/// Concentration of ozone in the atmosphere, unitless.
double ozone_concentration;
/// Elevation of the lower limit of the triangular distribution of ozone particles, in meters.
double ozone_lower_limit;
@ -70,14 +73,11 @@ struct atmosphere
/// Elevation of the mode of the triangular distribution of ozone particles, in meters.
double ozone_mode;
/// Concentration of ozone in the atmosphere, unitless.
double ozone_concentration;
/// (Dependent) Ozone absorption coefficients.
double3 ozone_absorption;
/// Airglow, in lux.
double airglow;
/// Airglow illuminance, in lux.
double3 airglow_illuminance;
};
} // namespace component

+ 10
- 4
src/entity/components/observer.hpp View File

@ -21,20 +21,26 @@
#define ANTKEEPER_ENTITY_COMPONENT_OBSERVER_HPP
#include "entity/id.hpp"
#include "utility/fundamental-types.hpp"
#include "scene/camera.hpp"
namespace entity {
namespace component {
/// Observer
/**
*
*/
struct observer
{
/// Entity ID of a celestial body to which the observer position is relative.
entity::id reference_body_eid;
/// Elevation of the observer, in radians.
double elevation;
/// Latitude of the observer, in radians.
double latitude;
/// Longitude of the observer, in radians.
double longitude;
scene::camera* camera;
};
} // namespace component

+ 378
- 270
src/entity/systems/astronomy.cpp View File

@ -27,6 +27,7 @@
#include "color/color.hpp"
#include "physics/orbit/orbit.hpp"
#include "physics/time/ut1.hpp"
#include "physics/time/jd.hpp"
#include "physics/light/photometry.hpp"
#include "physics/light/luminosity.hpp"
#include "physics/light/refraction.hpp"
@ -40,107 +41,107 @@
namespace entity {
namespace system {
template <class T>
math::vector3<T> transmittance(T depth_r, T depth_m, T depth_o, const math::vector3<T>& extinction_r, T extinction_m, const math::vector3<T>& extinction_o)
{
math::vector3<T> transmittance_r = extinction_r * depth_r;
math::vector3<T> transmittance_m = math::vector3<T>{extinction_m, extinction_m, extinction_m} * depth_m;
math::vector3<T> transmittance_o = extinction_o * depth_o;
math::vector3<T> t = transmittance_r + transmittance_m + transmittance_o;
t.x = std::exp(-t.x);
t.y = std::exp(-t.y);
t.z = std::exp(-t.z);
return t;
}
astronomy::astronomy(entity::registry& registry):
updatable(registry),
time(0.0),
time_days(0.0),
time_centuries(0.0),
time_scale(1.0),
reference_entity(entt::null),
observer_location{0, 0, 0},
observer_eid(entt::null),
reference_body_eid(entt::null),
transmittance_samples(0),
sun_light(nullptr),
sky_light(nullptr),
moon_light(nullptr),
camera(nullptr),
bounce_light(nullptr),
bounce_albedo{0, 0, 0},
sky_pass(nullptr),
exposure_offset(0.0),
starlight_illuminance(0.0)
starlight_illuminance{0, 0, 0}
{
// Construct transformation which transforms coordinates from ENU to EUS
// Construct ENU to EUS transformation
enu_to_eus = math::transformation::se3<double>
{
{0, 0, 0},
math::quaternion<double>::rotate_x(-math::half_pi<double>)
};
registry.on_construct<entity::component::celestial_body>().connect<&astronomy::on_celestial_body_construct>(this);
registry.on_replace<entity::component::celestial_body>().connect<&astronomy::on_celestial_body_replace>(this);
registry.on_construct<entity::component::observer>().connect<&astronomy::on_observer_modified>(this);
registry.on_replace<entity::component::observer>().connect<&astronomy::on_observer_modified>(this);
registry.on_destroy<entity::component::observer>().connect<&astronomy::on_observer_destroyed>(this);
registry.on_construct<entity::component::celestial_body>().connect<&astronomy::on_celestial_body_modified>(this);
registry.on_replace<entity::component::celestial_body>().connect<&astronomy::on_celestial_body_modified>(this);
registry.on_destroy<entity::component::celestial_body>().connect<&astronomy::on_celestial_body_destroyed>(this);
registry.on_construct<entity::component::orbit>().connect<&astronomy::on_orbit_modified>(this);
registry.on_replace<entity::component::orbit>().connect<&astronomy::on_orbit_modified>(this);
registry.on_destroy<entity::component::orbit>().connect<&astronomy::on_orbit_destroyed>(this);
registry.on_construct<entity::component::atmosphere>().connect<&astronomy::on_atmosphere_modified>(this);
registry.on_replace<entity::component::atmosphere>().connect<&astronomy::on_atmosphere_modified>(this);
registry.on_destroy<entity::component::atmosphere>().connect<&astronomy::on_atmosphere_destroyed>(this);
}
astronomy::~astronomy()
{
registry.on_construct<entity::component::celestial_body>().disconnect<&astronomy::on_celestial_body_construct>(this);
registry.on_replace<entity::component::celestial_body>().disconnect<&astronomy::on_celestial_body_replace>(this);
registry.on_construct<entity::component::observer>().disconnect<&astronomy::on_observer_modified>(this);
registry.on_replace<entity::component::observer>().disconnect<&astronomy::on_observer_modified>(this);
registry.on_destroy<entity::component::observer>().disconnect<&astronomy::on_observer_destroyed>(this);
registry.on_construct<entity::component::celestial_body>().disconnect<&astronomy::on_celestial_body_modified>(this);
registry.on_replace<entity::component::celestial_body>().disconnect<&astronomy::on_celestial_body_modified>(this);
registry.on_destroy<entity::component::celestial_body>().disconnect<&astronomy::on_celestial_body_destroyed>(this);
registry.on_construct<entity::component::orbit>().disconnect<&astronomy::on_orbit_modified>(this);
registry.on_replace<entity::component::orbit>().disconnect<&astronomy::on_orbit_modified>(this);
registry.on_destroy<entity::component::orbit>().disconnect<&astronomy::on_orbit_destroyed>(this);
registry.on_construct<entity::component::atmosphere>().disconnect<&astronomy::on_atmosphere_modified>(this);
registry.on_replace<entity::component::atmosphere>().disconnect<&astronomy::on_atmosphere_modified>(this);
registry.on_destroy<entity::component::atmosphere>().disconnect<&astronomy::on_atmosphere_destroyed>(this);
}
void astronomy::update(double t, double dt)
{
double total_illuminance = 0.0;
double sky_light_illuminance = 0.0;
double3 sky_light_illuminance = {0.0, 0.0, 0.0};
// Add scaled timestep to current time
set_time(time + dt * time_scale);
set_time(time_days + dt * time_scale);
// Abort if no reference body
if (reference_entity == entt::null)
// Abort if no valid observer entity or reference body entity
if (observer_eid == entt::null || reference_body_eid == entt::null)
return;
// Abort if either reference body or orbit have not been set
if (!registry.has<entity::component::orbit>(reference_entity) || !registry.has<entity::component::celestial_body>(reference_entity))
return;
const entity::component::orbit& reference_orbit = registry.get<entity::component::orbit>(reference_entity);
const entity::component::celestial_body& reference_body = registry.get<entity::component::celestial_body>(reference_entity);
math::transformation::se3<double> icrf_to_bci{{-reference_orbit.position}, math::quaternion<double>::identity};
// Get pointer to observer component
const auto observer = registry.try_get<component::observer>(observer_eid);
const double days_from_epoch = time;
const double centuries_from_epoch = days_from_epoch / 36525.0;
// Abort if no observer component
if (!observer)
return;
// Evaluate reference body orientation polynomials
const double reference_body_pole_ra = math::polynomial::horner(reference_body.pole_ra.begin(), reference_body.pole_ra.end(), centuries_from_epoch);
const double reference_body_pole_dec = math::polynomial::horner(reference_body.pole_dec.begin(), reference_body.pole_dec.end(), centuries_from_epoch);
const double reference_body_prime_meridian = math::polynomial::horner(reference_body.prime_meridian.begin(), reference_body.prime_meridian.end(), days_from_epoch);
// Get pointers to reference body components
const auto
[
reference_body,
reference_orbit,
reference_atmosphere
] = registry.try_get<component::celestial_body, component::orbit, component::atmosphere>(reference_body_eid);
// Construct transformation from the ICRF frame to the reference body BCBF frame
icrf_to_bcbf = physics::orbit::frame::bci::to_bcbf
(
reference_body_pole_ra,
reference_body_pole_dec,
reference_body_prime_meridian
);
icrf_to_bcbf.t = icrf_to_bcbf.r * -reference_orbit.position;
// Abort if no reference body or reference orbit
if (!reference_body || !reference_orbit)
return;
icrf_to_enu = icrf_to_bcbf * bcbf_to_enu;
icrf_to_eus = icrf_to_enu * enu_to_eus;
// Update ICRF to EUS transformation
update_icrf_to_eus(*reference_body, *reference_orbit);
// Set the transform component translations of orbiting bodies to their topocentric positions
registry.view<component::celestial_body, component::orbit, component::transform>().each(
[&](entity::id entity_id, const auto& body, const auto& orbit, auto& transform)
{
// Skip reference entity
if (entity_id == this->reference_entity)
// Skip reference body entity
if (entity_id == reference_body_eid)
return;
// Transform orbital Cartesian position (r) from the ICRF frame to the EUS frame
const double3 r_eus = icrf_to_eus * orbit.position;
// Evaluate body orientation polynomials
const double body_pole_ra = math::polynomial::horner(body.pole_ra.begin(), body.pole_ra.end(), centuries_from_epoch);
const double body_pole_dec = math::polynomial::horner(body.pole_dec.begin(), body.pole_dec.end(), centuries_from_epoch);
const double body_prime_meridian = math::polynomial::horner(body.prime_meridian.begin(), body.prime_meridian.end(), days_from_epoch);
const double body_pole_ra = math::polynomial::horner(body.pole_ra.begin(), body.pole_ra.end(), time_centuries);
const double body_pole_dec = math::polynomial::horner(body.pole_dec.begin(), body.pole_dec.end(), time_centuries);
const double body_prime_meridian = math::polynomial::horner(body.prime_meridian.begin(), body.prime_meridian.end(), time_days);
// Determine body orientation in the ICRF frame
math::quaternion<double> rotation_icrf = physics::orbit::frame::bcbf::to_bci
@ -160,133 +161,80 @@ void astronomy::update(double t, double dt)
transform.local.rotation = math::type_cast<float>(rotation_eus);
transform.local.scale = {1.0f, 1.0f, 1.0f};
}
/*
if (orbit.parent != entt::null)
{
// RA-DEC
const double3 r_bci = icrf_to_bci * orbit.position;
double3 r_bci_spherical = physics::orbit::frame::bci::spherical(r_bci);
if (r_bci_spherical.z < 0.0)
r_bci_spherical.z += math::two_pi<double>;
const double dec = math::degrees(r_bci_spherical.y);
const double ra = math::degrees(r_bci_spherical.z);
// AZ-EL
const double3 r_enu = icrf_to_enu * orbit.position;
double3 r_enu_spherical = physics::orbit::frame::enu::spherical(r_enu);
if (r_enu_spherical.z < 0.0)
r_enu_spherical.z += math::two_pi<double>;
const double el = math::degrees(r_enu_spherical.y);
const double az = math::degrees(r_enu_spherical.z);
std::cout << "t: " << this->time << "; ra: " << ra << "; dec: " << dec << std::endl;
std::cout << "t: " << this->time << "; az: " << az << "; el: " << el << std::endl;
}
*/
});
constexpr double3 bounce_normal = {0, 1, 0};
double3 bounce_illuminance = {0, 0, 0};
// Update blackbody lighting
registry.view<component::celestial_body, component::orbit, component::blackbody>().each(
[&](entity::id entity_id, const auto& body, const auto& orbit, const auto& blackbody)
[&](entity::id entity_id, const auto& blackbody_body, const auto& blackbody_orbit, const auto& blackbody)
{
// Calculate blackbody inertial basis
//double3 blackbody_forward_icrf = math::normalize(reference_orbit.icrf_position - orbit.icrf_position);
double3 blackbody_up_icrf = {0, 0, 1};
// Transform blackbody position from ICRF frame to EUS frame
const double3 blackbody_position_eus = icrf_to_eus * blackbody_orbit.position;
// Transform blackbody ICRF position and basis into EUS frame
double3 blackbody_position_eus = icrf_to_eus * orbit.position;
double3 blackbody_position_enu = icrf_to_enu * orbit.position;
double3 blackbody_forward_eus = math::normalize(-blackbody_position_eus);
double3 blackbody_up_eus = icrf_to_eus.r * blackbody_up_icrf;
// Measure distance and direction, in EUS frame, from observer to blackbody
const double observer_blackbody_distance = math::length(blackbody_position_eus);
const double3 observer_blackbody_direction_eus = blackbody_position_eus / observer_blackbody_distance;
// Calculate distance from observer to blackbody
double blackbody_distance = math::length(blackbody_position_eus) - body.radius;
// Measure blackbody solid angle as seen by observer
const double observer_blackbody_angular_radius = astro::angular_radius(blackbody_body.radius, observer_blackbody_distance);
const double observer_blackbody_solid_angle = geom::solid_angle::cone(observer_blackbody_angular_radius);
// Calculate blackbody solid angle
const double blackbody_angular_radius = astro::angular_radius(body.radius, blackbody_distance);
const double blackbody_solid_angle = geom::solid_angle::cone(blackbody_angular_radius);
// Calculate illuminance from blackbody reaching observer
const double3 observer_blackbody_illuminance = blackbody.luminance * observer_blackbody_solid_angle;
// Calculate blackbody illuminance
const double3 blackbody_illuminance = blackbody.luminance * blackbody_solid_angle;
// Init atmospheric transmittance
double3 atmospheric_transmittance = {1.0, 1.0, 1.0};
// Get atmosphere component of reference body (if any)
if (this->registry.has<entity::component::atmosphere>(reference_entity))
// Calculate illuminance from blackbody reaching observer after atmospheric extinction
double3 observer_blackbody_transmitted_illuminance = observer_blackbody_illuminance;
if (reference_atmosphere)
{
const entity::component::atmosphere& reference_atmosphere = registry.get<entity::component::atmosphere>(reference_entity);
// Altitude of observer in meters
geom::ray<double> sample_ray;
sample_ray.origin = {0, reference_body.radius + observer_location[0], 0};
sample_ray.direction = math::normalize(blackbody_position_eus);
geom::sphere<double> exosphere;
exosphere.center = {0, 0, 0};
exosphere.radius = reference_body.radius + reference_atmosphere.upper_limit;
auto intersection_result = geom::ray_sphere_intersection(sample_ray, exosphere);
// Construct ray at observer pointing towards the blackbody
const geom::ray<double> ray = {{0, 0, 0}, observer_blackbody_direction_eus};
if (std::get<0>(intersection_result))
{
double3 sample_start = sample_ray.origin;
double3 sample_end = sample_ray.extrapolate(std::get<2>(intersection_result));
double optical_depth_r = physics::gas::atmosphere::optical_depth_exp(sample_start, sample_end, reference_body.radius, reference_atmosphere.rayleigh_scale_height, 16);
double optical_depth_m = physics::gas::atmosphere::optical_depth_exp(sample_start, sample_end, reference_body.radius, reference_atmosphere.mie_scale_height, 16);
double optical_depth_o = physics::gas::atmosphere::optical_depth_tri(sample_start, sample_end, reference_body.radius, reference_atmosphere.ozone_lower_limit, reference_atmosphere.ozone_upper_limit, reference_atmosphere.ozone_mode, 16);
atmospheric_transmittance = transmittance(optical_depth_r, optical_depth_m, optical_depth_o, reference_atmosphere.rayleigh_scattering, reference_atmosphere.mie_scattering + reference_atmosphere.mie_absorption, reference_atmosphere.ozone_absorption);
}
// Integrate atmospheric spectral transmittance factor between observer and blackbody
const double3 transmittance = integrate_transmittance(*observer, *reference_body, *reference_atmosphere, ray);
// Add airglow to sky light illuminance
sky_light_illuminance += reference_atmosphere.airglow;
// Attenuate illuminance from blackbody reaching observer by spectral transmittance factor
observer_blackbody_transmitted_illuminance *= transmittance;
}
// Blackbody illuminance transmitted through the atmosphere
const double3 transmitted_blackbody_illuminance = blackbody_illuminance * atmospheric_transmittance;
// Add atmosphere-transmitted blackbody illuminance to total illuminance
total_illuminance += (transmitted_blackbody_illuminance.x + transmitted_blackbody_illuminance.y + transmitted_blackbody_illuminance.z) / 3.0;
// Update sun light
if (sun_light != nullptr)
{
sun_light->set_translation(math::normalize(math::type_cast<float>(blackbody_position_eus)));
const double3 blackbody_up_eus = icrf_to_eus.r * double3{0, 0, 1};
sun_light->set_rotation
(
math::look_rotation
(
math::type_cast<float>(blackbody_forward_eus),
math::type_cast<float>(-observer_blackbody_direction_eus),
math::type_cast<float>(blackbody_up_eus)
)
);
sun_light->set_color(math::type_cast<float>(transmitted_blackbody_illuminance));
sun_light->set_color(math::type_cast<float>(observer_blackbody_transmitted_illuminance));
// Bounce sun light
bounce_illuminance += std::max(0.0, math::dot(bounce_normal, -observer_blackbody_direction_eus)) * observer_blackbody_transmitted_illuminance * bounce_albedo;
}
// Update sky light
if (sky_light != nullptr)
{
// Calculate sky illuminance
double3 blackbody_position_enu_spherical = physics::orbit::frame::enu::spherical(blackbody_position_enu);
double3 blackbody_position_enu_spherical = physics::orbit::frame::enu::spherical(enu_to_eus.inverse() * blackbody_position_eus);
const double sky_illuminance = 25000.0 * std::max<double>(0.0, std::sin(blackbody_position_enu_spherical.y));
// Add sky illuminance to sky light illuminance
sky_light_illuminance += sky_illuminance;
sky_light_illuminance += {sky_illuminance, sky_illuminance, sky_illuminance};
// Add starlight illuminance to sky light illuminance
sky_light_illuminance += starlight_illuminance;
// Add sky light illuminance to total illuminance
total_illuminance += sky_light_illuminance;
//std::cout << "sky light illum: " << sky_light_illuminance << std::endl;
// Update sky light
sky_light->set_color(float3{1.0f, 1.0f, 1.0f} * static_cast<float>(sky_light_illuminance));
sky_light->set_color(math::type_cast<float>(sky_light_illuminance));
// Bounce sky light
bounce_illuminance += sky_light_illuminance * bounce_albedo;
}
// Upload blackbody params to sky pass
@ -294,143 +242,109 @@ void astronomy::update(double t, double dt)
{
this->sky_pass->set_sun_position(math::type_cast<float>(blackbody_position_eus));
this->sky_pass->set_sun_luminance(math::type_cast<float>(blackbody.luminance));
this->sky_pass->set_sun_illuminance(math::type_cast<float>(blackbody_illuminance));
this->sky_pass->set_sun_angular_radius(static_cast<float>(blackbody_angular_radius));
this->sky_pass->set_sun_illuminance(math::type_cast<float>(observer_blackbody_illuminance), math::type_cast<float>(observer_blackbody_transmitted_illuminance));
this->sky_pass->set_sun_angular_radius(static_cast<float>(observer_blackbody_angular_radius));
}
const double3& blackbody_icrf_position = orbit.position;
// Update diffuse reflectors
this->registry.view<component::celestial_body, component::orbit, component::diffuse_reflector, component::transform>().each(
[&](entity::id entity_id, const auto& reflector_body, const auto& reflector_orbit, const auto& reflector, const auto& transform)
{
// Calculate distance to blackbody and direction of incoming light
double3 blackbody_light_direction_icrf = reflector_orbit.position - blackbody_icrf_position;
double blackbody_distance = math::length(blackbody_light_direction_icrf);
blackbody_light_direction_icrf = blackbody_light_direction_icrf / blackbody_distance;
// Transform reflector position from ICRF frame to EUS frame
const double3 reflector_position_eus = icrf_to_eus * reflector_orbit.position;
// Measure distance and direction, in EUS frame, from observer to reflector
const double observer_reflector_distance = math::length(reflector_position_eus);
const double3 observer_reflector_direction_eus = reflector_position_eus / observer_reflector_distance;
// Transform blackbody light direction from the ICRF frame to the EUS frame
double3 blackbody_light_direction_eus = icrf_to_eus.r * blackbody_light_direction_icrf;
// Measure distance and direction, in EUS frame, from reflector to blackbody
double3 reflector_blackbody_direction_eus = blackbody_position_eus - reflector_position_eus;
const double reflector_blackbody_distance = math::length(reflector_blackbody_direction_eus);
reflector_blackbody_direction_eus /= reflector_blackbody_distance;
// Calculate blackbody solid angle
const double blackbody_angular_radius = astro::angular_radius(body.radius, blackbody_distance);
const double blackbody_solid_angle = geom::solid_angle::cone(blackbody_angular_radius);
// Measure blackbody solid angle as seen by reflector
const double reflector_blackbody_angular_radius = astro::angular_radius(blackbody_body.radius, reflector_blackbody_distance);
const double reflector_blackbody_solid_angle = geom::solid_angle::cone(reflector_blackbody_angular_radius);
// Calculate blackbody illuminance
// Calculate blackbody illuminance reaching reflector
const double3 reflector_blackbody_illuminance = blackbody.luminance * reflector_blackbody_solid_angle;
double3 view_direction_icrf = reflector_orbit.position - reference_orbit.position;
const double reflector_distance = math::length(view_direction_icrf);
view_direction_icrf = view_direction_icrf / reflector_distance;
// Measure reflector solid angle as seen by observer
const double observer_reflector_angular_radius = astro::angular_radius(reflector_body.radius, observer_reflector_distance);
const double observer_reflector_solid_angle = geom::solid_angle::cone(observer_reflector_angular_radius);
const double3 sunlight_illuminance = blackbody.luminance * blackbody_solid_angle;
const double reflector_angular_radius = astro::angular_radius(reflector_body.radius, reflector_distance);
const double reflector_solid_angle = geom::solid_angle::cone(reflector_angular_radius);
const double reflector_phase_factor = dot(view_direction_icrf, blackbody_light_direction_icrf) * 0.5 + 0.5;
// Determine phase factor of reflector as seen by observer
const double observer_reflector_phase_factor = dot(observer_reflector_direction_eus, -reflector_blackbody_direction_eus) * 0.5 + 0.5;
const double3 planet_luminance = (sunlight_illuminance * reference_body.albedo) / math::pi<double>;
const double planet_angular_radius = astro::angular_radius(reference_body.radius, reflector_distance);
const double planet_solid_angle = geom::solid_angle::cone(planet_angular_radius);
const double planet_phase_factor = math::dot(-view_direction_icrf, math::normalize(reference_orbit.position - blackbody_icrf_position)) * 0.5 + 0.5;
const double3 planetlight_illuminance = planet_luminance * planet_solid_angle * planet_phase_factor;
double3 planetlight_direction_eus = math::normalize(icrf_to_eus.r * view_direction_icrf);
// Measure observer reference body solid angle as seen by reflector
const double reflector_observer_angular_radius = astro::angular_radius(reference_body->radius, observer_reflector_distance);
const double reflector_observer_solid_angle = geom::solid_angle::cone(reflector_observer_angular_radius);
const double3 reflected_sunlight_luminance = (sunlight_illuminance * reflector.albedo) / math::pi<double>;
const double3 reflected_sunlight_illuminance = reflected_sunlight_luminance * reflector_solid_angle * reflector_phase_factor;
const double3 reflected_planetlight_luminance = (planetlight_illuminance * reflector.albedo) / math::pi<double>;
const double3 reflected_planetlight_illuminance = reflected_planetlight_luminance * reflector_solid_angle;
// Determine phase factor of observer reference body as by reflector
const double reflector_observer_phase_factor = dot(-observer_reflector_direction_eus, -observer_blackbody_direction_eus) * 0.5 + 0.5;
/*
std::cout << "reflected sunlight illuminance: " << reflected_sunlight_illuminance << std::endl;
std::cout << "planetlight illuminance: " << planetlight_illuminance << std::endl;
std::cout << "planet luminance: " << planet_luminance << std::endl;
std::cout << "reflected planetlight luminance: " << reflected_planetlight_luminance << std::endl;
std::cout << "reflected planetlight illuminance: " << reflected_planetlight_illuminance << std::endl;
std::cout << "reflector phase: " << reflector_phase_factor << std::endl;
std::cout << "planet phase: " << planet_phase_factor << std::endl;
*/
// Calculate spectral transmittance between observer and reflector factor due to atmospheric extinction
double3 observer_reflector_transmittance = {1, 1, 1};
if (reference_atmosphere)
{
const geom::ray<double> ray = {{0, 0, 0}, observer_reflector_direction_eus};
observer_reflector_transmittance = integrate_transmittance(*observer, *reference_body, *reference_atmosphere, ray);
}
// Measure luminance of observer reference body as seen by reflector
const double3 reflector_observer_luminance = observer_blackbody_illuminance * reference_body->albedo * observer_reflector_transmittance * reflector_observer_phase_factor * math::inverse_pi<double>;
// Measure illuminance from observer reference body reaching reflector
const double3 reflector_observer_illuminance = reflector_observer_luminance * reflector_observer_solid_angle;
// Measure luminance of reflector as seen by observer
const double3 observer_reflector_luminance = (reflector_blackbody_illuminance * observer_reflector_phase_factor + reflector_observer_illuminance) * reflector.albedo * observer_reflector_transmittance * math::inverse_pi<double>;
// Measure illuminance from reflector reaching observer
const double3 observer_reflector_illuminance = observer_reflector_luminance * observer_reflector_solid_angle;
if (this->sky_pass)
{
this->sky_pass->set_moon_position(transform.local.translation);
this->sky_pass->set_moon_rotation(transform.local.rotation);
this->sky_pass->set_moon_angular_radius(static_cast<float>(reflector_angular_radius));
this->sky_pass->set_moon_sunlight_direction(math::type_cast<float>(blackbody_light_direction_eus));
this->sky_pass->set_moon_sunlight_illuminance(math::type_cast<float>(sunlight_illuminance));
this->sky_pass->set_moon_planetlight_direction(math::type_cast<float>(planetlight_direction_eus));
this->sky_pass->set_moon_planetlight_illuminance(math::type_cast<float>(planetlight_illuminance));
this->sky_pass->set_moon_angular_radius(static_cast<float>(observer_reflector_angular_radius));
this->sky_pass->set_moon_sunlight_direction(math::type_cast<float>(-reflector_blackbody_direction_eus));
this->sky_pass->set_moon_sunlight_illuminance(math::type_cast<float>(reflector_blackbody_illuminance * observer_reflector_transmittance));
this->sky_pass->set_moon_planetlight_direction(math::type_cast<float>(observer_reflector_direction_eus));
this->sky_pass->set_moon_planetlight_illuminance(math::type_cast<float>(reflector_observer_illuminance * observer_reflector_transmittance));
this->sky_pass->set_moon_illuminance(math::type_cast<float>(observer_reflector_illuminance / observer_reflector_transmittance), math::type_cast<float>(observer_reflector_illuminance));
}
if (this->moon_light)
{
float3 reflector_up_eus = math::type_cast<float>(icrf_to_eus.r * double3{0, 0, 1});
double3 reflected_illuminance = reflected_sunlight_illuminance + reflected_planetlight_illuminance;
//reflected_illuminance *= std::max<double>(0.0, std::sin(transform.local.translation.y));
total_illuminance += (reflected_illuminance.x + reflected_illuminance.y + reflected_illuminance.z) / 3.0;
const float3 reflector_up_eus = math::type_cast<float>(icrf_to_eus.r * double3{0, 0, 1});
this->moon_light->set_color(math::type_cast<float>(reflected_illuminance));
this->moon_light->set_color(math::type_cast<float>(observer_reflector_illuminance));
this->moon_light->set_rotation
(
math::look_rotation
(
math::normalize(-transform.local.translation),
math::type_cast<float>(-observer_reflector_direction_eus),
reflector_up_eus
)
);
// Bounce moon light
bounce_illuminance += std::max(0.0, math::dot(bounce_normal, -observer_reflector_direction_eus)) * observer_reflector_illuminance * bounce_albedo;
}
/*
std::cout << "moon: sun solid angle: " << blackbody_solid_angle << std::endl;
std::cout << "moon: sun illuminance: " << blackbody_illuminance << std::endl;
std::cout << "moon: moon luminance: " << reflector_luminance << std::endl;
std::cout << "sun brightness: " << sun_brightness << std::endl;
std::cout << "vega brightness: " << vega_brightness << std::endl;
std::cout << "earth: moon distance: " << reflector_distance << std::endl;
std::cout << "earth: moon solid angle: " << reflector_solid_angle << std::endl;
std::cout << "earth: moon phase: " << reflector_phase << std::endl;
std::cout << "earth: moon phase angle: " << math::degrees(reflector_phase_angle) << std::endl;
std::cout << "earth: moon illum %: " << reflector_illumination_factor * 100.0 << std::endl;
std::cout << "earth: moon illuminance: " << reflector_illuminance << std::endl;
std::cout << "earth: moon phase-modulated illuminance: " << reflector_illuminance * reflector_illumination_factor << std::endl;
*/
});
});
// Update sky pass topocentric frame
if (sky_pass != nullptr)
if (bounce_light)
{
// Upload topocentric frame to sky pass
sky_pass->set_icrf_to_eus
(
math::transformation::se3<float>
{
math::type_cast<float>(icrf_to_eus.t),
math::type_cast<float>(icrf_to_eus.r)
}
);
// Upload observer elevation to sky pass
sky_pass->set_observer_elevation(observer_location[0]);
sky_pass->set_planet_radius(static_cast<float>(reference_body.radius));
}
// Auto-exposure
if (camera)
{
const double calibration = 250.0;
const double ev100 = std::log2((total_illuminance * 100.0) / calibration);
//std::cout << "LUX: " << total_illuminance << std::endl;
//std::cout << "EV100: " << ev100 << std::endl;
//camera->set_exposure(exposure_offset);
bounce_light->set_color(math::type_cast<float>(bounce_illuminance));
}
}
void astronomy::set_time(double time)
void astronomy::set_time(double t)
{
this->time = time;
time_days = t;
time_centuries = time_days * physics::time::jd::centuries_per_day<double>;
}
void astronomy::set_time_scale(double scale)
@ -438,16 +352,22 @@ void astronomy::set_time_scale(double scale)
time_scale = scale;
}
void astronomy::set_reference_body(entity::id entity_id)
void astronomy::set_observer(entity::id eid)
{
reference_entity = entity_id;
update_bcbf_to_enu();
if (observer_eid != eid)
{
observer_eid = eid;
if (observer_eid != entt::null)
observer_modified();
else
reference_body_eid = entt::null;
}
}
void astronomy::set_observer_location(const double3& location)
void astronomy::set_transmittance_samples(std::size_t samples)
{
observer_location = location;
update_bcbf_to_enu();
transmittance_samples = samples;
}
void astronomy::set_sun_light(scene::directional_light* light)
@ -465,17 +385,17 @@ void astronomy::set_moon_light(scene::directional_light* light)
moon_light = light;
}
void astronomy::set_camera(scene::camera* camera)
void astronomy::set_bounce_light(scene::directional_light* light)
{
this->camera = camera;
bounce_light = light;
}
void astronomy::set_exposure_offset(float offset)
void astronomy::set_bounce_albedo(const double3& albedo)
{
exposure_offset = offset;
bounce_albedo = albedo;
}
void astronomy::set_starlight_illuminance(double illuminance)
void astronomy::set_starlight_illuminance(const double3& illuminance)
{
starlight_illuminance = illuminance;
}
@ -483,37 +403,225 @@ void astronomy::set_starlight_illuminance(double illuminance)
void astronomy::set_sky_pass(::render::sky_pass* pass)
{
this->sky_pass = pass;
if (sky_pass)
{
if (observer_eid != entt::null)
{
// Get pointer to observer
const auto observer = registry.try_get<component::observer>(reference_body_eid);
sky_pass->set_observer_elevation(static_cast<float>(observer->elevation));
}
if (reference_body_eid != entt::null)
{
// Get pointer to reference celestial body
const auto reference_body = registry.try_get<component::celestial_body>(reference_body_eid);
if (reference_body)
sky_pass->set_planet_radius(static_cast<float>(reference_body->radius));
else
sky_pass->set_planet_radius(0.0f);
}
}
}
void astronomy::on_celestial_body_construct(entity::registry& registry, entity::id entity_id, entity::component::celestial_body& celestial_body)
void astronomy::on_observer_modified(entity::registry& registry, entity::id entity_id, entity::component::observer& component)
{
if (entity_id == reference_entity)
update_bcbf_to_enu();
if (entity_id == observer_eid)
observer_modified();
}
void astronomy::on_celestial_body_replace(entity::registry& registry, entity::id entity_id, entity::component::celestial_body& celestial_body)
void astronomy::on_observer_destroyed(entity::registry& registry, entity::id entity_id)
{
if (entity_id == reference_entity)
update_bcbf_to_enu();
if (entity_id == observer_eid)
observer_modified();
}
void astronomy::update_bcbf_to_enu()
void astronomy::on_celestial_body_modified(entity::registry& registry, entity::id entity_id, entity::component::celestial_body& component)
{
double radial_distance = observer_location[0];
if (entity_id == reference_body_eid)
reference_body_modified();
}
void astronomy::on_celestial_body_destroyed(entity::registry& registry, entity::id entity_id)
{
if (entity_id == reference_body_eid)
reference_body_modified();
}
void astronomy::on_orbit_modified(entity::registry& registry, entity::id entity_id, entity::component::orbit& component)
{
if (entity_id == reference_body_eid)
reference_orbit_modified();
}
void astronomy::on_orbit_destroyed(entity::registry& registry, entity::id entity_id)
{
if (entity_id == reference_body_eid)
reference_orbit_modified();
}
void astronomy::on_atmosphere_modified(entity::registry& registry, entity::id entity_id, entity::component::atmosphere& component)
{
if (entity_id == reference_body_eid)
reference_atmosphere_modified();
}
void astronomy::on_atmosphere_destroyed(entity::registry& registry, entity::id entity_id)
{
if (entity_id == reference_body_eid)
reference_atmosphere_modified();
}
void astronomy::observer_modified()
{
// Get pointer to observer component
const auto observer = registry.try_get<component::observer>(observer_eid);
if (reference_entity)
if (observer)
{
if (registry.has<entity::component::celestial_body>(reference_entity))
radial_distance += registry.get<entity::component::celestial_body>(reference_entity).radius;
if (reference_body_eid != observer->reference_body_eid)
{
// Reference body changed
reference_body_eid = observer->reference_body_eid;
reference_body_modified();
reference_orbit_modified();
reference_atmosphere_modified();
}
if (reference_body_eid != entt::null)
{
// Get pointer to reference celestial body
const auto reference_body = registry.try_get<component::celestial_body>(reference_body_eid);
// Update BCBF to EUS transformation
if (reference_body)
update_bcbf_to_eus(*observer, *reference_body);
}
// Upload observer elevation to sky pass
if (sky_pass)
sky_pass->set_observer_elevation(static_cast<float>(observer->elevation));
}
}
void astronomy::reference_body_modified()
{
// Get pointer to reference celestial body
const auto reference_body = registry.try_get<component::celestial_body>(reference_body_eid);
if (reference_body)
{
// Get pointer to observer
const auto observer = registry.try_get<component::observer>(observer_eid);
// Update BCBF to EUS transformation
if (observer)
update_bcbf_to_eus(*observer, *reference_body);
}
// Construct reference frame which transforms coordinates from a BCBF frame to a horizontal frame
bcbf_to_enu = physics::orbit::frame::bcbf::to_enu
// Update reference celestial body-related sky pass parameters
if (sky_pass)
{
if (reference_body)
sky_pass->set_planet_radius(static_cast<float>(reference_body->radius));
else
sky_pass->set_planet_radius(0.0f);
}
}
void astronomy::reference_orbit_modified()
{
}
void astronomy::reference_atmosphere_modified()
{
}
void astronomy::update_bcbf_to_eus(const entity::component::observer& observer, const entity::component::celestial_body& body)
{
// Construct BCBF to EUS transformation
bcbf_to_eus = physics::orbit::frame::bcbf::to_enu
(
radial_distance,
observer_location[1],
observer_location[2]
body.radius + observer.elevation,
observer.latitude,
observer.longitude
) * enu_to_eus;
}
void astronomy::update_icrf_to_eus(const entity::component::celestial_body& body, const entity::component::orbit& orbit)
{
// Evaluate reference body orientation polynomials
const double body_pole_ra = math::polynomial::horner(body.pole_ra.begin(), body.pole_ra.end(), time_centuries);
const double body_pole_dec = math::polynomial::horner(body.pole_dec.begin(), body.pole_dec.end(), time_centuries);
const double body_prime_meridian = math::polynomial::horner(body.prime_meridian.begin(), body.prime_meridian.end(), time_days);
// Construct ICRF frame to BCBF transformation
math::transformation::se3<double> icrf_to_bcbf = physics::orbit::frame::bci::to_bcbf
(
body_pole_ra,
body_pole_dec,
body_prime_meridian
);
icrf_to_bcbf.t = icrf_to_bcbf.r * -orbit.position;
/// Construct ICRF to EUS transformation
icrf_to_eus = icrf_to_bcbf * bcbf_to_eus;
// Pass ICRF to EUS transformation to sky pass
if (sky_pass)
{
// Upload topocentric frame to sky pass
sky_pass->set_icrf_to_eus
(
math::transformation::se3<float>
{
math::type_cast<float>(icrf_to_eus.t),
math::type_cast<float>(icrf_to_eus.r)
}
);
}
}
double3 astronomy::integrate_transmittance(const entity::component::observer& observer, const entity::component::celestial_body& body, const entity::component::atmosphere& atmosphere, geom::ray<double> ray) const
{
double3 transmittance = {1, 1, 1};
// Make ray height relative to center of reference body
ray.origin.y += body.radius + observer.elevation;
// Construct sphere representing upper limit of the atmosphere
geom::sphere<double> atmosphere_sphere;
atmosphere_sphere.center = {0, 0, 0};
atmosphere_sphere.radius = body.radius + atmosphere.upper_limit;
// Check for intersection between the ray and atmosphere
auto intersection = geom::ray_sphere_intersection(ray, atmosphere_sphere);
if (std::get<0>(intersection))
{
// Get point of intersection
const double3 intersection_point = ray.extrapolate(std::get<2>(intersection));
// Integrate optical of Rayleigh, Mie, and ozone particles
const double optical_depth_r = physics::gas::atmosphere::optical_depth_exp(ray.origin, intersection_point, body.radius, atmosphere.rayleigh_scale_height, transmittance_samples);
const double optical_depth_m = physics::gas::atmosphere::optical_depth_exp(ray.origin, intersection_point, body.radius, atmosphere.mie_scale_height, transmittance_samples);
const double optical_depth_o = physics::gas::atmosphere::optical_depth_tri(ray.origin, intersection_point, body.radius, atmosphere.ozone_lower_limit, atmosphere.ozone_upper_limit, atmosphere.ozone_mode, transmittance_samples);
// Calculate transmittance factor due to scattering and absorption
const double3 extinction_r = atmosphere.rayleigh_scattering * optical_depth_r;
const double extinction_m = atmosphere.mie_extinction * optical_depth_m;
const double3 extinction_o = atmosphere.ozone_absorption * optical_depth_o;
transmittance = extinction_r + double3{extinction_m, extinction_m, extinction_m} + extinction_o;
transmittance.x = std::exp(-transmittance.x);
transmittance.y = std::exp(-transmittance.y);
transmittance.z = std::exp(-transmittance.z);
}
return transmittance;
}
} // namespace system

+ 72
- 29
src/entity/systems/astronomy.hpp View File

@ -24,19 +24,20 @@
#include "entity/id.hpp"
#include "scene/directional-light.hpp"
#include "scene/ambient-light.hpp"
#include "scene/camera.hpp"
#include "utility/fundamental-types.hpp"
#include "math/se3.hpp"
#include "render/passes/sky-pass.hpp"
#include "entity/components/observer.hpp"
#include "entity/components/atmosphere.hpp"
#include "entity/components/celestial-body.hpp"
#include "entity/components/orbit.hpp"
#include "geom/ray.hpp"
namespace entity {
namespace system {
/**
* Calculates apparent properties of celestial bodies relative to an observer.
* Calculates apparent properties of celestial bodies as seen by an observer.
*/
class astronomy:
public updatable
@ -46,7 +47,7 @@ public:
~astronomy();
/**
* Scales then adds the timestep `dt` to the current time, then recalculates the positions of celestial bodies.
* Adds the timestep `dt`, scaled by set time scale, to the current time, then calculates apparent properties of celestial bodies as seen by an observer.
*
* @param t Time, in seconds.
* @param dt Delta time, in seconds.
@ -56,9 +57,9 @@ public:
/**
* Sets the current time.
*
* @param time Time, in days.
* @param t Time since epoch, in days.
*/
void set_time(double time);
void set_time(double t);
/**
* Sets the factor by which the timestep `dt` will be scaled before being added to the current time.
@ -68,57 +69,99 @@ public:
void set_time_scale(double scale);
/**
* Sets the reference body entity, from which observations are taking place.
* Sets the observer entity.
*
* @param entity Entity of the reference body.
* @param eid Entity ID of the observer.
*/
void set_reference_body(entity::id entity_id);
void set_observer(entity::id eid);
/**
* Sets the location of the observer using spherical coordinates in BCBF space.
* Sets the number of samples to take when integrating atmospheric transmittance.
*
* @param location Spherical coordinates of the observer, in reference body BCBF space, in the ISO order of altitude (meters), latitude (radians), and longitude (radians).
* @param samples Number of integration samples.
*/
void set_observer_location(const double3& location);
void set_transmittance_samples(std::size_t samples);
void set_sun_light(scene::directional_light* light);
void set_sky_light(scene::ambient_light* light);
void set_moon_light(scene::directional_light* light);
void set_camera(scene::camera* camera);
void set_exposure_offset(float offset);
void set_bounce_light(scene::directional_light* light);
void set_bounce_albedo(const double3& albedo);
void set_starlight_illuminance(const double3& illuminance);
void set_sky_pass(::render::sky_pass* pass);
void set_starlight_illuminance(double illuminance);
private:
void on_observer_modified(entity::registry& registry, entity::id entity_id, entity::component::observer& component);
void on_observer_destroyed(entity::registry& registry, entity::id entity_id);
void on_celestial_body_modified(entity::registry& registry, entity::id entity_id, entity::component::celestial_body& component);
void on_celestial_body_destroyed(entity::registry& registry, entity::id entity_id);
void on_orbit_modified(entity::registry& registry, entity::id entity_id, entity::component::orbit& component);
void on_orbit_destroyed(entity::registry& registry, entity::id entity_id);
void on_atmosphere_modified(entity::registry& registry, entity::id entity_id, entity::component::atmosphere& component);
void on_atmosphere_destroyed(entity::registry& registry, entity::id entity_id);
inline float get_exposure_offset() const { return exposure_offset; };
/// Called each time the observer is modified.
void observer_modified();
void set_sky_pass(::render::sky_pass* pass);
/// Called each time the celestial body of the reference body is modified.
void reference_body_modified();
private:
void on_celestial_body_construct(entity::registry& registry, entity::id entity_id, entity::component::celestial_body& celestial_body);
void on_celestial_body_replace(entity::registry& registry, entity::id entity_id, entity::component::celestial_body& celestial_body);
/// Called each time the orbit of the reference body is modified.
void reference_orbit_modified();
void update_bcbf_to_enu();
/// Called each time the atmosphere of the reference body is modified.
void reference_atmosphere_modified();
double time;
/// Updates the BCBF to EUS transformation.
void update_bcbf_to_eus(const entity::component::observer& observer, const entity::component::celestial_body& body);
/// Updates the ICRF to EUS transformation.
void update_icrf_to_eus(const entity::component::celestial_body& body, const entity::component::orbit& orbit);
/**
* Integrates a transmittance factor due to atmospheric extinction along a ray.
*
* @param ray Ray to cast, in the EUS frame.
* @param samples Number of samples to integrate.
*
* @return Spectral transmittance factor.
*/
double3 integrate_transmittance(const entity::component::observer& observer, const entity::component::celestial_body& body, const entity::component::atmosphere& atmosphere, geom::ray<double> ray) const;
/// Time since epoch, in days.
double time_days;
/// Time since epoch, in centuries.
double time_centuries;
/// Time scale.
double time_scale;
entity::id reference_entity;
/// Number of transmittance integration samples.
std::size_t transmittance_samples;
/// Entity ID of the observer.
entity::id observer_eid;
double3 observer_location;
/// Entity ID of the reference body.
entity::id reference_body_eid;
math::transformation::se3<double> icrf_to_bcbf;
math::transformation::se3<double> bcbf_to_enu;
math::transformation::se3<double> icrf_to_enu;
/// ENU to EUS transformation.
math::transformation::se3<double> enu_to_eus;
/// BCBF to EUS transformation.
math::transformation::se3<double> bcbf_to_eus;
/// ICRF to EUS tranformation.
math::transformation::se3<double> icrf_to_eus;
scene::directional_light* sun_light;
scene::ambient_light* sky_light;
scene::directional_light* moon_light;
scene::camera* camera;
scene::directional_light* bounce_light;
double3 bounce_albedo;
::render::sky_pass* sky_pass;
float exposure_offset;
double starlight_illuminance;
double3 starlight_illuminance;
};
} // namespace system

+ 29
- 32
src/entity/systems/atmosphere.cpp View File

@ -21,7 +21,6 @@
#include "physics/gas/atmosphere.hpp"
#include "physics/gas/ozone.hpp"
#include "physics/number-density.hpp"
#include "color/srgb.hpp"
namespace entity {
namespace system {
@ -44,12 +43,15 @@ void atmosphere::update(double t, double dt)
void atmosphere::set_rgb_wavelengths(const double3& wavelengths)
{
rgb_wavelengths = wavelengths;
atmosphere_modified();
}
void atmosphere::set_rgb_ozone_cross_sections(const double3& cross_sections)
{
rgb_ozone_cross_sections = cross_sections;
// Update ozone cross sections
rgb_ozone_cross_sections =
{
physics::gas::ozone::cross_section_293k<double>(wavelengths.x * 1e9),
physics::gas::ozone::cross_section_293k<double>(wavelengths.y * 1e9),
physics::gas::ozone::cross_section_293k<double>(wavelengths.z * 1e9)
};
atmosphere_modified();
}
@ -67,37 +69,31 @@ void atmosphere::atmosphere_modified()
// Get atmosphere component of the entity
entity::component::atmosphere& component = *atmosphere_component;
// Calculate Rayleigh scattering coefficients for sRGB wavelengths
const double rayleigh_polarization = physics::gas::atmosphere::polarization(component.index_of_refraction, component.rayleigh_density);
const double3 rayleigh_scattering_srgb =
// Calculate Rayleigh scattering coefficients
const double rayleigh_density = physics::number_density(component.rayleigh_concentration);
const double rayleigh_polarization = physics::gas::atmosphere::polarization(component.index_of_refraction, rayleigh_density);
component.rayleigh_scattering =
{
physics::gas::atmosphere::scattering_rayleigh(rgb_wavelengths.x, component.rayleigh_density, rayleigh_polarization),
physics::gas::atmosphere::scattering_rayleigh(rgb_wavelengths.y, component.rayleigh_density, rayleigh_polarization),
physics::gas::atmosphere::scattering_rayleigh(rgb_wavelengths.z, component.rayleigh_density, rayleigh_polarization)
physics::gas::atmosphere::scattering(rayleigh_density, rayleigh_polarization, rgb_wavelengths.x),
physics::gas::atmosphere::scattering(rayleigh_density, rayleigh_polarization, rgb_wavelengths.y),
physics::gas::atmosphere::scattering(rayleigh_density, rayleigh_polarization, rgb_wavelengths.z)
};
// Transform Rayleigh scattering coefficients from sRGB to ACEScg
component.rayleigh_scattering = color::srgb::to_acescg(rayleigh_scattering_srgb);
// Calculate Mie scattering coefficient
const double mie_polarization = physics::gas::atmosphere::polarization(component.index_of_refraction, component.mie_density);
component.mie_scattering = physics::gas::atmosphere::scattering_mie(component.mie_density, mie_polarization);
// Calculate Mie scattering and extinction coefficients
const double mie_density = physics::number_density(component.mie_concentration);
const double mie_polarization = physics::gas::atmosphere::polarization(component.index_of_refraction, mie_density);
component.mie_scattering = physics::gas::atmosphere::scattering(mie_density, mie_polarization);
component.mie_extinction = physics::gas::atmosphere::extinction(component.mie_scattering, component.mie_albedo);
// Calculate Mie absorption coefficient
component.mie_absorption = physics::gas::atmosphere::absorption_mie(component.mie_scattering);
// Calculate ozone absorption coefficients for sRGB wavelengths
const double air_number_density = physics::number_density(component.air_concentration);
const double3 ozone_absorption_srgb =
// Calculate ozone absorption coefficients
const double ozone_density = physics::number_density(component.ozone_concentration);
component.ozone_absorption =
{
physics::gas::ozone::absorption(rgb_ozone_cross_sections.x, air_number_density, component.ozone_concentration),
physics::gas::ozone::absorption(rgb_ozone_cross_sections.y, air_number_density, component.ozone_concentration),
physics::gas::ozone::absorption(rgb_ozone_cross_sections.z, air_number_density, component.ozone_concentration)
physics::gas::ozone::absorption(rgb_ozone_cross_sections.x, ozone_density),
physics::gas::ozone::absorption(rgb_ozone_cross_sections.y, ozone_density),
physics::gas::ozone::absorption(rgb_ozone_cross_sections.z, ozone_density)
};
// Transform ozone absorption coefficients from sRGB to ACEScg
component.ozone_absorption = color::srgb::to_acescg(ozone_absorption_srgb);
// Pass atmosphere parameters to sky pass
update_sky_pass();
}
@ -111,8 +107,9 @@ void atmosphere::update_sky_pass()
sky_pass->set_atmosphere_upper_limit(static_cast<float>(component.upper_limit));
sky_pass->set_rayleigh_parameters(static_cast<float>(component.rayleigh_scale_height), math::type_cast<float>(component.rayleigh_scattering));
sky_pass->set_mie_parameters(static_cast<float>(component.mie_scale_height), static_cast<float>(component.mie_scattering), static_cast<float>(component.mie_absorption), static_cast<float>(component.mie_anisotropy));
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));
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));
sky_pass->set_airglow_illuminance(math::type_cast<float>(component.airglow_illuminance));
}
void atmosphere::on_atmosphere_construct(entity::registry& registry, entity::id entity_id, entity::component::atmosphere& component)

+ 0
- 7
src/entity/systems/atmosphere.hpp View File

@ -47,13 +47,6 @@ public:
*/
void set_rgb_wavelengths(const double3& wavelengths);
/**
* Sets ozone cross sections for red, green, and blue wavelengths.
*
* @param cross_sections Vector containing the ozone cross sections of red (x), green (y), and blue (z) light, in m-2/molecule.
*/
void set_rgb_ozone_cross_sections(const double3& cross_sections);
void set_sky_pass(::render::sky_pass* pass);
private:

+ 13
- 3
src/entity/systems/blackbody.cpp View File

@ -27,7 +27,8 @@ namespace entity {
namespace system {
blackbody::blackbody(entity::registry& registry):
updatable(registry)
updatable(registry),
illuminant(color::illuminant::deg2::d50<double>)
{
// Construct a range of sample wavelengths in the visible spectrum
visible_wavelengths_nm.resize(780 - 280);
@ -43,6 +44,11 @@ blackbody::blackbody(entity::registry& registry):
void blackbody::update(double t, double dt)
{}
void blackbody::set_illuminant(const math::vector2<double>& illuminant)
{
this->illuminant = illuminant;
}
void blackbody::update_luminance(entity::id entity_id)
{
// Abort if entity has no blackbody component
@ -62,8 +68,11 @@ void blackbody::update_luminance(entity::id entity_id)
// Get celestial body component of the entity
const component::celestial_body& celestial_body = registry.get<component::celestial_body>(entity_id);
// Construct chromatic adaptation transform
const double3x3 cat = color::cat::matrix(illuminant, color::aces::white_point<double>);
// Construct a lambda function which calculates the blackbody's RGB luminance of a given wavelength
auto rgb_luminance = [blackbody](double wavelength_nm) -> double3
auto rgb_luminance = [blackbody, cat](double wavelength_nm) -> double3
{
// Convert wavelength from nanometers to meters
const double wavelength_m = wavelength_nm * 1e-9;
@ -71,8 +80,9 @@ void blackbody::update_luminance(entity::id entity_id)
// Calculate the spectral intensity of the wavelength
const double spectral_radiance = physics::light::blackbody::spectral_radiance<double>(blackbody.temperature, wavelength_m);
// Calculate the ACEScg color of the wavelength using CIE color matching functions
double3 spectral_color = color::xyz::to_acescg(color::xyz::match(wavelength_nm));
double3 spectral_color = color::aces::ap1<double>.from_xyz * cat * color::xyz::match(wavelength_nm);
// Scale the spectral color by spectral intensity
return spectral_color * spectral_radiance * 1e-9 * physics::light::max_luminous_efficacy<double>;

+ 8
- 0
src/entity/systems/blackbody.hpp View File

@ -41,6 +41,13 @@ public:
virtual void update(double t, double dt);
/**
* Sets the blackbody illuminant.
*
* @param illuminant CIE chromaticity coordinates of an illuminant.
*/
void set_illuminant(const math::vector2<double>& illuminant);
private:
void update_luminance(entity::id entity_id);
@ -50,6 +57,7 @@ private:
void on_celestial_body_construct(entity::registry& registry, entity::id entity_id, entity::component::celestial_body& celestial_body);
void on_celestial_body_replace(entity::registry& registry, entity::id entity_id, entity::component::celestial_body& celestial_body);
math::vector2<double> illuminant;
std::vector<double> visible_wavelengths_nm;
};

+ 2
- 0
src/entity/systems/terrain.cpp View File

@ -72,6 +72,7 @@ terrain::~terrain()
void terrain::update(double t, double dt)
{
/*
// Refine the level of detail of each terrain quadsphere
registry.view<component::terrain, component::celestial_body>().each(
[&](entity::id terrain_eid, const auto& terrain_component, const auto& terrain_body)
@ -238,6 +239,7 @@ void terrain::update(double t, double dt)
}
}
});
*/
}
void terrain::set_patch_subdivisions(std::uint8_t n)

+ 147
- 0
src/game/ant/swarm.cpp View File

@ -0,0 +1,147 @@
/*
* Copyright (C) 2021 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include "game/ant/swarm.hpp"
#include "entity/components/transform.hpp"
#include "entity/components/steering.hpp"
#include "entity/components/model.hpp"
#include "resources/resource-manager.hpp"
#include "config.hpp"
#include <cmath>
#include <random>
namespace game {
namespace ant {
/**
* Generates a random point in a unit sphere.
*
* @see https://math.stackexchange.com/questions/87230/picking-random-points-in-the-volume-of-sphere-with-uniform-probability/87238#87238
*/
template <class T, class Generator>
static math::vector3<T> sphere_random(Generator& rng)
{
const std::uniform_real_distribution<T> distribution(T{-1}, T{1});
const T x = distribution(rng);
const T y = distribution(rng);
const T z = distribution(rng);
const T cbrt_u = std::cbrt(distribution(rng));
const T scale = (T{1} / std::sqrt(x * x + y * y + z * z)) * cbrt_u;
return {x * scale, y * scale, z * scale};
}
void create_swarm(game::context& ctx)
{
// Determine swarm properties
const float3 swarm_center = {0, 100, 0};
const float swarm_radius = 25.0f;
const std::size_t male_count = 50;
const std::size_t queen_count = 50;
const std::size_t alate_count = male_count + queen_count;
const float3 male_scale = {0.5, 0.5, 0.5};
const float3 queen_scale = {1, 1, 1};
// Init male model component
entity::component::model male_model;
male_model.render_model = ctx.resource_manager->load<render::model>("male-boid.mdl");
male_model.instance_count = 0;
male_model.layers = 1;
// Init queen model component
entity::component::model queen_model;
queen_model.render_model = ctx.resource_manager->load<render::model>("queen-boid.mdl");
queen_model.instance_count = 0;
queen_model.layers = 1;
// Init transform component
entity::component::transform transform;
transform.local = math::transform<float>::identity;
transform.world = transform.local;
transform.warp = true;
// Init steering component
entity::component::steering steering;
steering.agent.mass = 1.0f;
steering.agent.velocity = {0, 0, 0};
steering.agent.acceleration = {0, 0, 0};
steering.agent.max_force = 4.0f;
steering.agent.max_speed = 5.0f;
steering.agent.max_speed_squared = steering.agent.max_speed * steering.agent.max_speed;
steering.agent.orientation = math::quaternion<float>::identity;
steering.agent.forward = steering.agent.orientation * config::global_forward;
steering.agent.up = steering.agent.orientation * config::global_up;
steering.wander_weight = 1.0f;
steering.wander_noise = math::radians(2000.0f);
steering.wander_distance = 10.0f;
steering.wander_radius = 8.0f;
steering.wander_angle = 0.0f;
steering.wander_angle2 = 0.0f;
steering.seek_weight = 0.2f;
steering.seek_target = {0, 100, 0};
steering.flee_weight = 0.0f;
steering.sum_weights = steering.wander_weight + steering.seek_weight + steering.flee_weight;
// Construct and seed random number generator
std::random_device seed;
std::mt19937 rng(seed());
// Create alates
for (std::size_t i = 0; i < alate_count; ++i)
{
// Generate random position in swarm sphere
steering.agent.position = swarm_center + sphere_random<float>(rng) * swarm_radius;
transform.local.translation = steering.agent.position;
entity::id alate_eid = ctx.entity_registry->create();
ctx.entity_registry->assign<entity::component::steering>(alate_eid, steering);
if (i < male_count)
{
// Create male
ctx.entity_registry->assign<entity::component::model>(alate_eid, male_model);
transform.local.scale = male_scale;
transform.world = transform.local;
ctx.entity_registry->assign<entity::component::transform>(alate_eid, transform);
}
else
{
// Create queen
ctx.entity_registry->assign<entity::component::model>(alate_eid, queen_model);
transform.local.scale = queen_scale;
transform.world = transform.local;
ctx.entity_registry->assign<entity::component::transform>(alate_eid, transform);
}
}
}
void destroy_swarm(game::context& ctx)
{
auto view = ctx.entity_registry->view<entity::component::steering>();
ctx.entity_registry->destroy(view.begin(), view.end());
}
} // namespace ant
} // namespace game

+ 34
- 0
src/game/ant/swarm.hpp View File

@ -0,0 +1,34 @@
/*
* Copyright (C) 2021 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_GAME_ANT_SWARM_HPP
#define ANTKEEPER_GAME_ANT_SWARM_HPP
#include "game/context.hpp"
namespace game {
namespace ant {
void create_swarm(game::context& ctx);
void destroy_swarm(game::context& ctx);
} // namespace ant
} // namespace game
#endif // ANTKEEPER_GAME_ANT_SWARM_HPP

+ 1
- 3
src/game/context.hpp View File

@ -295,9 +295,7 @@ struct context
entity::system::orbit* orbit_system;
entity::system::proteome* proteome_system;
double elevation;
double latitude;
double longitude;
double3 rgb_wavelengths;
};
} // namespace game

+ 10
- 0
src/game/controls.cpp View File

@ -660,4 +660,14 @@ void apply_gamepad_calibration(input::gamepad& gamepad, const json& calibration)
}
}
void enable_orbit_controls(game::context& ctx)
{
}
void disable_orbit_controls(game::context& ctx)
{
}
} // namespace game

+ 3
- 0
src/game/controls.hpp View File

@ -87,6 +87,9 @@ bool save_gamepad_calibration(const game::context& ctx, const input::gamepad& ga
*/
void apply_gamepad_calibration(input::gamepad& gamepad, const json& calibration);
void enable_orbit_controls(game::context& ctx);
void disable_orbit_controls(game::context& ctx);
} // namespace game
#endif // ANTKEEPER_GAME_CONTROLS_HPP

+ 13
- 0
src/game/load.cpp View File

@ -86,6 +86,19 @@ void biome(game::context& ctx, const std::filesystem::path& path)
{
ctx.logger->warning("Biome terrain material undefined");
}
// Setup lighting
double3 terrain_albedo = {0, 0, 0};
if (terrain->contains("albedo"))
{
const auto& albedo_element = (*terrain)["albedo"];
terrain_albedo[0] = albedo_element[0].get<double>();
terrain_albedo[1]= albedo_element[1].get<double>();
terrain_albedo[2] = albedo_element[2].get<double>();
}
ctx.astronomy_system->set_bounce_albedo(terrain_albedo);
}
else
{

+ 6
- 17
src/game/state/boot.cpp View File

@ -93,7 +93,6 @@
#include "game/graphics.hpp"
#include "utility/timestamp.hpp"
#include "color/color.hpp"
#include "physics/gas/ozone.hpp"
#include <cxxopts.hpp>
#include <entt/entt.hpp>
#include <filesystem>
@ -834,20 +833,6 @@ void boot::setup_systems()
const auto& viewport_dimensions = ctx.app->get_viewport_dimensions();
float4 viewport = {0.0f, 0.0f, static_cast<float>(viewport_dimensions[0]), static_cast<float>(viewport_dimensions[1])};
// RGB wavelengths
const double3 rgb_wavelengths_nm = {680, 550, 440};
const double3 rgb_wavelengths_m = rgb_wavelengths_nm * 1e-9;
// Ozone cross sections
double3 rgb_ozone_cross_sections_293k =
{
physics::gas::ozone::cross_section_680nm_293k<double>,
physics::gas::ozone::cross_section_550nm_293k<double>,
physics::gas::ozone::cross_section_440nm_293k<double>
};
rgb_ozone_cross_sections_293k = rgb_ozone_cross_sections_293k;
// Setup terrain system
ctx.terrain_system = new entity::system::terrain(*ctx.entity_registry);
ctx.terrain_system->set_patch_subdivisions(30);
@ -904,15 +889,19 @@ void boot::setup_systems()
// Setup blackbody system
ctx.blackbody_system = new entity::system::blackbody(*ctx.entity_registry);
ctx.blackbody_system->set_illuminant(color::illuminant::deg2::d55<double>);
// RGB wavelengths for atmospheric scatteering
ctx.rgb_wavelengths = {645, 575, 440};
// Setup atmosphere system
ctx.atmosphere_system = new entity::system::atmosphere(*ctx.entity_registry);
ctx.atmosphere_system->set_rgb_wavelengths(rgb_wavelengths_m);
ctx.atmosphere_system->set_rgb_ozone_cross_sections(rgb_ozone_cross_sections_293k);
ctx.atmosphere_system->set_rgb_wavelengths(ctx.rgb_wavelengths * 1e-9);
ctx.atmosphere_system->set_sky_pass(ctx.sky_pass);
// Setup astronomy system
ctx.astronomy_system = new entity::system::astronomy(*ctx.entity_registry);
ctx.astronomy_system->set_transmittance_samples(16);
ctx.astronomy_system->set_sky_pass(ctx.sky_pass);
// Setup proteome system

+ 46
- 0
src/game/state/main-menu.cpp View File

@ -21,8 +21,13 @@
#include "game/state/options-menu.hpp"
#include "game/state/extras-menu.hpp"
#include "game/state/nuptial-flight.hpp"
#include "game/world.hpp"
#include "game/load.hpp"
#include "game/menu.hpp"
#include "game/ant/swarm.hpp"
#include "render/passes/clear-pass.hpp"
#include "render/passes/ground-pass.hpp"
#include "render/passes/sky-pass.hpp"
#include "resources/resource-manager.hpp"
#include "render/model.hpp"
#include "animation/animation.hpp"
@ -31,6 +36,10 @@
#include "animation/ease.hpp"
#include "application.hpp"
#include "config.hpp"
#include "physics/light/exposure.hpp"
#include "entity/components/model.hpp"
#include "entity/components/steering.hpp"
#include "entity/components/transform.hpp"
#include <limits>
namespace game {
@ -233,6 +242,40 @@ main_menu::main_menu(game::context& ctx, bool fade_in):
game::menu::fade_in(ctx, nullptr);
}
if (ctx.entities.find("earth") == ctx.entities.end())
{
game::world::cosmogenesis(ctx);
game::world::create_observer(ctx);
game::load::biome(ctx, "debug.bio");
}
// Set world time
game::world::set_time(ctx, 2022, 6, 21, 12, 0, 0.0);
// Set world time scale
game::world::set_time_scale(ctx, 0.0);
ctx.surface_camera->set_active(true);
const float ev100_sunny16 = physics::light::ev::from_settings(16.0f, 1.0f / 100.0f, 100.0f);
ctx.surface_camera->set_exposure(15.5f);
ctx.surface_camera->look_at({-55, 36, 10}, {0, 100, 0}, {0, 1, 0});
ctx.surface_camera->update_tweens();
// Setup and enable sky and ground passes
ctx.sky_pass->set_enabled(true);
ctx.ground_pass->set_enabled(true);
// Disable UI color clear
ctx.ui_clear_pass->set_cleared_buffers(false, true, false);
// Create mating swarm
game::ant::create_swarm(ctx);
if (!ctx.menu_bg_billboard->is_active())
game::menu::fade_in_bg(ctx);
ctx.logger->pop_task(EXIT_SUCCESS);
}
@ -253,6 +296,9 @@ main_menu::~main_menu()
// Destruct title text
ctx.ui_scene->remove_object(&title_text);
// Destroy swarm
game::ant::destroy_swarm(ctx);
ctx.logger->pop_task(EXIT_SUCCESS);
}

+ 90
- 89
src/game/state/nuptial-flight.cpp View File

@ -19,9 +19,11 @@
#include "game/state/nuptial-flight.hpp"
#include "game/state/pause-menu.hpp"
#include "game/ant/swarm.hpp"
#include "entity/archetype.hpp"
#include "entity/systems/camera.hpp"
#include "entity/systems/astronomy.hpp"
#include "entity/systems/atmosphere.hpp"
#include "entity/components/locomotion.hpp"
#include "entity/components/transform.hpp"
#include "entity/components/terrain.hpp"
@ -45,6 +47,8 @@
#include "game/ant/breed.hpp"
#include "game/ant/morphogenesis.hpp"
#include "math/interpolation.hpp"
#include "physics/light/exposure.hpp"
#include "color/color.hpp"
#include <iostream>
using namespace game::ant;
@ -92,61 +96,20 @@ nuptial_flight::nuptial_flight(game::context& ctx):
ctx.ui_clear_pass->set_cleared_buffers(false, true, false);
// Create world if not yet created
if (ctx.entities.find("planet") == ctx.entities.end())
if (ctx.entities.find("earth") == ctx.entities.end())
{
// Create cosmos
game::world::cosmogenesis(ctx);
// Create boids
for (int i = 0; i < 100; ++i)
{
entity::id boid_eid = ctx.entity_registry->create();
// Create transform component
entity::component::transform transform;
transform.local = math::transform<float>::identity;
transform.world = math::transform<float>::identity;
transform.warp = true;
ctx.entity_registry->assign<entity::component::transform>(boid_eid, transform);
// Create model component
entity::component::model model;
model.render_model = ctx.resource_manager->load<render::model>("boid.mdl");
model.instance_count = 0;
model.layers = 1;
ctx.entity_registry->assign<entity::component::model>(boid_eid, model);
// Create steering component
entity::component::steering steering;
steering.agent.mass = 1.0f;
steering.agent.position = {0, 100, 0};
steering.agent.velocity = {0, 0, 0};
steering.agent.acceleration = {0, 0, 0};
steering.agent.max_force = 4.0f;
steering.agent.max_speed = 5.0f;
steering.agent.max_speed_squared = steering.agent.max_speed * steering.agent.max_speed;
steering.agent.orientation = math::quaternion<float>::identity;
steering.agent.forward = steering.agent.orientation * config::global_forward;
steering.agent.up = steering.agent.orientation * config::global_up;
steering.wander_weight = 1.0f;
steering.wander_noise = math::radians(2000.0f);
steering.wander_distance = 10.0f;
steering.wander_radius = 8.0f;
steering.wander_angle = 0.0f;
steering.wander_angle2 = 0.0f;
steering.seek_weight = 0.2f;
steering.seek_target = {0, 100, 0};
steering.flee_weight = 0.0f;
steering.sum_weights = steering.wander_weight + steering.seek_weight + steering.flee_weight;
ctx.entity_registry->assign<entity::component::steering>(boid_eid, steering);
}
// Create observer
game::world::create_observer(ctx);
}
// Load biome
game::load::biome(ctx, "desert-scrub.bio");
// Set world time
game::world::set_time(ctx, 2022, 6, 21, 12, 0, 0.0);
game::world::set_time(ctx, 2022, 10, 9, 12, 0, 0.0);
// Set world time scale
game::world::set_time_scale(ctx, 60.0);
@ -162,6 +125,13 @@ nuptial_flight::nuptial_flight(game::context& ctx):
entity::command::warp_to(*ctx.entity_registry, color_checker_eid, {0, 0, -10});
}
// Create diffuse spheres
{
entity::archetype* diffuse_spheres_archetype = ctx.resource_manager->load<entity::archetype>("diffuse-spheres.ent");
auto diffuse_spheres_eid = diffuse_spheres_archetype->create(*ctx.entity_registry);
entity::command::warp_to(*ctx.entity_registry, diffuse_spheres_eid, {0, 0, -20});
}
// Create ruler
{
entity::archetype* ruler_10cm_archetype = ctx.resource_manager->load<entity::archetype>("ruler-10cm.ent");
@ -169,20 +139,6 @@ nuptial_flight::nuptial_flight(game::context& ctx):
entity::command::warp_to(*ctx.entity_registry, ruler_10cm_eid, {0, 0, 10});
}
// Create cocoon
{
entity::archetype* cocoon_archetype = ctx.resource_manager->load<entity::archetype>("cocoon.ent");
auto cocoon_eid = cocoon_archetype->create(*ctx.entity_registry);
entity::command::warp_to(*ctx.entity_registry, cocoon_eid, {-10, 0, 10});
}
// Create larva
{
entity::archetype* larva_archetype = ctx.resource_manager->load<entity::archetype>("long-neck-larva.ent");
auto larva_eid = larva_archetype->create(*ctx.entity_registry);
entity::command::warp_to(*ctx.entity_registry, larva_eid, {-13, 0, 10});
}
// Create keeper if not yet created
if (ctx.entities.find("keeper") == ctx.entities.end())
{
@ -190,33 +146,6 @@ nuptial_flight::nuptial_flight(game::context& ctx):
ctx.entities["keeper"] = keeper_eid;
}
// Create ant if not created
if (ctx.entities.find("ant") == ctx.entities.end())
{
auto boid_eid = ctx.entity_registry->create();
entity::component::model model;
model.render_model = worker_model;//ctx.resource_manager->load<render::model>("ant-test.mdl");
model.instance_count = 0;
model.layers = 1;
ctx.entity_registry->assign<entity::component::model>(boid_eid, model);
entity::component::transform transform;
transform.local = math::transform<float>::identity;
transform.world = math::transform<float>::identity;
transform.warp = true;
ctx.entity_registry->assign<entity::component::transform>(boid_eid, transform);
entity::component::locomotion locomotion;
locomotion.yaw = 0.0f;
ctx.entity_registry->assign<entity::component::locomotion>(boid_eid, locomotion);
entity::command::warp_to(*ctx.entity_registry, boid_eid, {0, 1, 0});
// Set target ant
ctx.entities["ant"] = boid_eid;
}
// Start as ant-keeper
is_keeper = true;
@ -322,10 +251,12 @@ void nuptial_flight::setup_camera()
constraint_stack.head = spring_constraint_eid;
ctx.entity_registry->assign<entity::component::constraint_stack>(camera_eid, constraint_stack);
}
ctx.surface_camera->set_exposure(15.5f);
ctx.astronomy_system->set_camera(ctx.surface_camera);
game::ant::create_swarm(ctx);
const float ev100_sunny16 = physics::light::ev::from_settings(16.0f, 1.0f / 100.0f, 100.0f);
const float ev100_looney11 = physics::light::ev::from_settings(11.0f, 1.0f / 100.0f, 100.0f);
ctx.surface_camera->set_exposure(ev100_sunny16);
}
void nuptial_flight::enable_keeper_controls()
@ -687,6 +618,76 @@ void nuptial_flight::enable_keeper_controls()
ctx.logger->log("EV100: " + std::to_string(ctx.surface_camera->get_exposure()));
}
);
const float wavelength_speed = 20.0 * (1.0 / 60.0);
ctx.controls["dec_red"]->set_active_callback
(
[&ctx = this->ctx, wavelength_speed](float)
{
ctx.rgb_wavelengths.x -= wavelength_speed;
ctx.atmosphere_system->set_rgb_wavelengths(ctx.rgb_wavelengths * 1e-9);
std::stringstream stream;
stream << ctx.rgb_wavelengths;
ctx.logger->log("wavelengths: " + stream.str());
}
);
ctx.controls["inc_red"]->set_active_callback
(
[&ctx = this->ctx, wavelength_speed](float)
{
ctx.rgb_wavelengths.x += wavelength_speed;
ctx.atmosphere_system->set_rgb_wavelengths(ctx.rgb_wavelengths * 1e-9);
std::stringstream stream;
stream << ctx.rgb_wavelengths;
ctx.logger->log("wavelengths: " + stream.str());
}
);
ctx.controls["dec_green"]->set_active_callback
(
[&ctx = this->ctx, wavelength_speed](float)
{
ctx.rgb_wavelengths.y -= wavelength_speed;
ctx.atmosphere_system->set_rgb_wavelengths(ctx.rgb_wavelengths * 1e-9);
std::stringstream stream;
stream << ctx.rgb_wavelengths;
ctx.logger->log("wavelengths: " + stream.str());
}
);
ctx.controls["inc_green"]->set_active_callback
(
[&ctx = this->ctx, wavelength_speed](float)
{
ctx.rgb_wavelengths.y += wavelength_speed;
ctx.atmosphere_system->set_rgb_wavelengths(ctx.rgb_wavelengths * 1e-9);
std::stringstream stream;
stream << ctx.rgb_wavelengths;
ctx.logger->log("wavelengths: " + stream.str());
}
);
ctx.controls["dec_blue"]->set_active_callback
(
[&ctx = this->ctx, wavelength_speed](float)
{
ctx.rgb_wavelengths.z -= wavelength_speed;
ctx.atmosphere_system->set_rgb_wavelengths(ctx.rgb_wavelengths * 1e-9);
std::stringstream stream;
stream << ctx.rgb_wavelengths;
ctx.logger->log("wavelengths: " + stream.str());
}
);
ctx.controls["inc_blue"]->set_active_callback
(
[&ctx = this->ctx, wavelength_speed](float)
{
ctx.rgb_wavelengths.z += wavelength_speed;
ctx.atmosphere_system->set_rgb_wavelengths(ctx.rgb_wavelengths * 1e-9);
std::stringstream stream;
stream << ctx.rgb_wavelengths;
ctx.logger->log("wavelengths: " + stream.str());
}
);
}
void nuptial_flight::disable_keeper_controls()

+ 2
- 2
src/game/tools.cpp View File

@ -90,8 +90,8 @@ entity::id build_time_tool(game::context& ctx)
// Setup tool active calback
tool.active = [&ctx]()
{
auto [mouse_x, mouse_y] = ctx.app->get_mouse()->get_current_position();
auto [window_w, window_h] = ctx.app->get_viewport_dimensions();
//auto mouse = ctx.app->get_mouse()->get_current_position();
//auto window = ctx.app->get_viewport_dimensions();
entity::id planet_eid = ctx.entities["planet"];
entity::component::celestial_body body = ctx.entity_registry->get<entity::component::celestial_body>(planet_eid);

+ 114
- 35
src/game/world.cpp View File

@ -27,6 +27,7 @@
#include "entity/components/orbit.hpp"
#include "entity/components/terrain.hpp"
#include "entity/components/transform.hpp"
#include "entity/components/observer.hpp"
#include "entity/systems/astronomy.hpp"
#include "entity/systems/orbit.hpp"
#include "entity/commands.hpp"
@ -52,6 +53,7 @@
#include "gl/texture-wrapping.hpp"
#include "gl/texture-filter.hpp"
#include "render/material-flags.hpp"
#include "geom/solid-angle.hpp"
#include "config.hpp"
#include <iostream>
@ -88,15 +90,79 @@ void cosmogenesis(game::context& ctx)
ctx.logger->pop_task(EXIT_SUCCESS);
}
void set_location(game::context& ctx, double elevation, double latitude, double longitude)
void create_observer(game::context& ctx)
{
// Update context location
ctx.elevation = elevation;
ctx.latitude = latitude;
ctx.longitude = longitude;
ctx.logger->push_task("Creating observer");
// Pass location to astronomy system
ctx.astronomy_system->set_observer_location({elevation, latitude, longitude});
try
{
// Create observer entity
entity::id observer_eid = ctx.entity_registry->create();
ctx.entities["observer"] = observer_eid;
// Construct observer component
entity::component::observer observer;
// Set observer reference body
if (auto it = ctx.entities.find("earth"); it != ctx.entities.end())
observer.reference_body_eid = it->second;
else
observer.reference_body_eid = entt::null;
// Set observer location
observer.elevation = 0.0;
observer.latitude = 0.0;
observer.longitude = 0.0;
// Assign observer component to observer entity
ctx.entity_registry->assign<entity::component::observer>(observer_eid, observer);
// Set astronomy system observer
ctx.astronomy_system->set_observer(observer_eid);
}
catch (const std::exception&)
{
ctx.logger->pop_task(EXIT_FAILURE);
return;
}
ctx.logger->pop_task(EXIT_SUCCESS);
}
void set_location(game::context& ctx, double elevation, double latitude, double longitude)
{
if (auto it = ctx.entities.find("observer"); it != ctx.entities.end())
{
entity::id observer_eid = it->second;
if (observer_eid != entt::null)
{
// Get pointer to observer component
const auto observer = ctx.entity_registry->try_get<entity::component::observer>(observer_eid);
// Set observer location
if (observer)
{
observer->elevation = elevation;
observer->latitude = latitude;
observer->longitude = longitude;
ctx.entity_registry->replace<entity::component::observer>(observer_eid, *observer);
}
/*
ctx.entity_registry->patch<entity::component::observer>
(
observer_eid,
[&](auto& component)
{
component.elevation = elevation;
component.latitude = latitude;
component.longitude = longitude;
}
);
*/
}
}
}
void set_time(game::context& ctx, double t)
@ -117,28 +183,36 @@ void set_time(game::context& ctx, double t)
void set_time(game::context& ctx, int year, int month, int day, int hour, int minute, double second)
{
const double utc_offset = physics::time::utc::offset<double>(ctx.longitude);
double longitude = 0.0;
// Get longitude of observer
if (auto it = ctx.entities.find("observer"); it != ctx.entities.end())
{
entity::id observer_eid = it->second;
if (observer_eid != entt::null)
{
const auto observer = ctx.entity_registry->try_get<entity::component::observer>(observer_eid);
if (observer)
longitude = observer->longitude;
}
}
// Calculate UTC offset at longitude
const double utc_offset = physics::time::utc::offset<double>(longitude);
// Convert time from Gregorian to UT1
const double t = physics::time::gregorian::to_ut1<double>(year, month, day, hour, minute, second, utc_offset);
set_time(ctx, t);
}
void set_time_scale(game::context& ctx, double scale)
{
ctx.logger->push_task("Setting time scale to " + std::to_string(scale));
try
{
// Convert time scale from seconds to days
const double astronomical_scale = scale / physics::time::seconds_per_day<double>;
ctx.orbit_system->set_time_scale(astronomical_scale);
ctx.astronomy_system->set_time_scale(astronomical_scale);
}
catch (const std::exception&)
{
ctx.logger->pop_task(EXIT_FAILURE);
return;
}
ctx.logger->pop_task(EXIT_SUCCESS);
// Convert time scale from seconds to days
const double astronomical_scale = scale / physics::time::seconds_per_day<double>;
ctx.orbit_system->set_time_scale(astronomical_scale);
ctx.astronomy_system->set_time_scale(astronomical_scale);
}
void load_ephemeris(game::context& ctx)
@ -208,7 +282,7 @@ void create_stars(game::context& ctx)
float* star_vertex = star_vertex_data;
// Init starlight illuminance
double starlight_illuminance = 0.0;
double3 starlight_illuminance = {0, 0, 0};
// Build star catalog vertex data
for (std::size_t i = 1; i < star_catalog->size(); ++i)
@ -239,9 +313,6 @@ void create_stars(game::context& ctx)
// Convert ICRF coordinates from spherical to Cartesian
double3 position = physics::orbit::frame::bci::cartesian(double3{1.0, dec, ra});
// Convert apparent magnitude to brightness factor relative to a 0th magnitude star
double brightness = physics::light::vmag::to_brightness(vmag);
// Convert color index to color temperature
double cct = color::index::bv_to_cct(bv);
@ -249,10 +320,10 @@ void create_stars(game::context& ctx)
double3 color_xyz = color::cct::to_xyz(cct);
// Transform XYZ color to ACEScg colorspace
double3 color_acescg = color::xyz::to_acescg(color_xyz);
double3 color_acescg = color::aces::ap1<double>.from_xyz * color_xyz;
// Scale color by relative brightness
color_acescg *= brightness;
// Convert apparent magnitude to brightness factor relative to a 0th magnitude star
double brightness = physics::light::vmag::to_brightness(vmag);
// Build vertex
*(star_vertex++) = static_cast<float>(position.x);
@ -263,8 +334,11 @@ void create_stars(game::context& ctx)
*(star_vertex++) = static_cast<float>(color_acescg.z);
*(star_vertex++) = static_cast<float>(brightness);
// Convert apparent magnitude to illuminance and add to total starlight
starlight_illuminance += physics::light::vmag::to_illuminance(vmag);
// Calculate spectral illuminance
double3 illuminance = color_acescg * physics::light::vmag::to_illuminance(vmag);
// Add spectral illuminance to total starlight illuminance
starlight_illuminance += illuminance;
}
// Unload star catalog
@ -347,14 +421,22 @@ void create_sun(game::context& ctx)
sky_light->set_color({0, 0, 0});
sky_light->update_tweens();
// Create bounce directional light scene object
scene::directional_light* bounce_light = new scene::directional_light();
bounce_light->set_color({0, 0, 0});
bounce_light->look_at({0, 0, 0}, {0, 1, 0}, {1, 0, 0});
bounce_light->update_tweens();
// Add sun light scene objects to surface scene
ctx.surface_scene->add_object(sun_light);
ctx.surface_scene->add_object(sky_light);
ctx.surface_scene->add_object(bounce_light);
// Pass direct sun light scene object to shadow map pass and astronomy system
ctx.surface_shadow_map_pass->set_light(sun_light);
ctx.astronomy_system->set_sun_light(sun_light);
ctx.astronomy_system->set_sky_light(sky_light);
ctx.astronomy_system->set_bounce_light(bounce_light);
}
catch (const std::exception&)
{
@ -415,9 +497,6 @@ void create_earth(game::context& ctx)
terrain.max_lod = 0;
terrain.patch_material = nullptr;
//ctx.entity_registry->assign<entity::component::terrain>(earth_eid, terrain);
// Pass earth to astronomy system as reference body
ctx.astronomy_system->set_reference_body(earth_eid);
}
catch (const std::exception&)
{

+ 3
- 0
src/game/world.hpp View File

@ -30,6 +30,9 @@ namespace world {
/// Creates the cosmos.
void cosmogenesis(game::context& ctx);
/// Creates the observer.
void create_observer(game::context& ctx);
/**
* Sets the location of the observer.
*

+ 2
- 3
src/geom/sphere.hpp View File

@ -69,7 +69,7 @@ template
bool sphere<T>::intersects(const sphere<T>& sphere) const
{
vector_type d = center - sphere.center;
float r = radius + sphere.radius;
T r = radius + sphere.radius;
return (math::dot(d, d) <= r * r);
}
@ -82,7 +82,7 @@ bool sphere::intersects(const aabb& aabb) const
template <class T>
bool sphere<T>::contains(const sphere<T>& sphere) const
{
float containment_radius = radius - sphere.radius;
T containment_radius = radius - sphere.radius;
if (containment_radius < T(0))
return false;
@ -115,4 +115,3 @@ bool sphere::contains(const vector_type& point) const
} // namespace geom
#endif // ANTKEEPER_GEOM_SPHERE_HPP

+ 5
- 0
src/gl/texture-2d.cpp View File

@ -33,6 +33,11 @@ void texture_2d::resize(std::uint16_t width, std::uint16_t height, gl::pixel_typ
texture::resize(width, height, type, format, color_space, data);
}
void texture_2d::resize(std::uint16_t width, std::uint16_t height, const void* data)
{
texture::resize(width, height, get_pixel_type(), get_pixel_format(), get_color_space(), data);
}
void texture_2d::set_wrapping(gl::texture_wrapping wrap_s, texture_wrapping wrap_t)
{
texture::set_wrapping(wrap_s, wrap_t);

+ 9
- 0
src/gl/texture-2d.hpp View File

@ -39,6 +39,15 @@ public:
/// @copydoc texture::resize(std::uint16_t, std::uint16_t, gl::pixel_type, gl::pixel_format, gl::color_space, const void*)
virtual void resize(std::uint16_t width, std::uint16_t height, gl::pixel_type type, gl::pixel_format format, gl::color_space color_space, const void* data);
/**
* Resizes the texture.
*
* @param width Texture width, in pixels.
* @param height Texture height, in pixels.
* @param data Pointer to pixel data.
*/
void resize(std::uint16_t width, std::uint16_t height, const void* data);
/// @copydoc texture::set_wrapping(gl::texture_wrapping, gl::texture_wrapping)
virtual void set_wrapping(gl::texture_wrapping wrap_s, texture_wrapping wrap_t);
};

+ 74
- 74
src/math/matrix-functions.hpp View File

@ -35,15 +35,15 @@ namespace math {
* @return Sum of the two matrices.
*/
template <class T>
matrix<T, 2, 2> add(const matrix<T, 2, 2>& x, const matrix<T, 2, 2>& y);
constexpr matrix<T, 2, 2> add(const matrix<T, 2, 2>& x, const matrix<T, 2, 2>& y);
/// @copydoc add(const matrix<T, 2, 2>&, const matrix<T, 2, 2>&)
template <class T>
matrix<T, 3, 3> add(const matrix<T, 3, 3>& x, const matrix<T, 3, 3>& y);
constexpr matrix<T, 3, 3> add(const matrix<T, 3, 3>& x, const matrix<T, 3, 3>& y);
/// @copydoc add(const matrix<T, 2, 2>&, const matrix<T, 2, 2>&)
template <class T>
matrix<T, 4, 4> add(const matrix<T, 4, 4>& x, const matrix<T, 4, 4>& y);
constexpr matrix<T, 4, 4> add(const matrix<T, 4, 4>& x, const matrix<T, 4, 4>& y);
/**
* Reinterprets data as an `NxM` matrix of type `T`.
@ -54,7 +54,7 @@ matrix add(const matrix& x, const matrix& y);
* @param data Data to reinterpret.
*/
template <std::size_t N, std::size_t M, typename T>
matrix<T, N, M>& as_matrix(T& data);
constexpr matrix<T, N, M>& as_matrix(T& data);
/**
* Calculates the determinant of a matrix.
@ -62,15 +62,15 @@ matrix& as_matrix(T& data);
* @param m Matrix of which to take the determinant.
*/
template <class T>
T determinant(const matrix<T, 2, 2>& m);
constexpr T determinant(const matrix<T, 2, 2>& m);
/// @copydoc determinant(const matrix<T, 2, 2>&)
template <class T>
T determinant(const matrix<T, 3, 3>& m);
constexpr T determinant(const matrix<T, 3, 3>& m);
/// @copydoc determinant(const matrix<T, 2, 2>&)
template <class T>
T determinant(const matrix<T, 4, 4>& m);
constexpr T determinant(const matrix<T, 4, 4>& m);
/**
* Calculates the inverse of a matrix.
@ -78,15 +78,15 @@ T determinant(const matrix& m);
* @param m Matrix of which to take the inverse.
*/
template <class T>
matrix<T, 2, 2> inverse(const matrix<T, 2, 2>& m);
constexpr matrix<T, 2, 2> inverse(const matrix<T, 2, 2>& m);
/// @copydoc inverse(const matrix<T, 2, 2>&)
template <class T>
matrix<T, 3, 3> inverse(const matrix<T, 3, 3>& m);
constexpr matrix<T, 3, 3> inverse(const matrix<T, 3, 3>& m);
/// @copydoc inverse(const matrix<T, 2, 2>&)
template <class T>
matrix<T, 4, 4> inverse(const matrix<T, 4, 4>& m);
constexpr matrix<T, 4, 4> inverse(const matrix<T, 4, 4>& m);
/**
* Performs a component-wise multiplication of two matrices.
@ -95,15 +95,15 @@ matrix inverse(const matrix& m);
* @param y Second matrix multiplicand.
*/
template <class T>
matrix<T, 2, 2> componentwise_mul(const matrix<T, 2, 2>& x, const matrix<T, 2, 2>& y);
constexpr matrix<T, 2, 2> componentwise_mul(const matrix<T, 2, 2>& x, const matrix<T, 2, 2>& y);
/// @copydoc componentwise_mul(const matrix<T, 2, 2>&, const matrix<T, 2, 2>&)
template <class T>
matrix<T, 3, 3> componentwise_mul(const matrix<T, 3, 3>& x, const matrix<T, 3, 3>& y);
constexpr matrix<T, 3, 3> componentwise_mul(const matrix<T, 3, 3>& x, const matrix<T, 3, 3>& y);
/// @copydoc componentwise_mul(const matrix<T, 2, 2>&, const matrix<T, 2, 2>&)
template <class T>
matrix<T, 4, 4> componentwise_mul(const matrix<T, 4, 4>& x, const matrix<T, 4, 4>& y);
constexpr matrix<T, 4, 4> componentwise_mul(const matrix<T, 4, 4>& x, const matrix<T, 4, 4>& y);
/**
* Creates a viewing transformation matrix.
@ -114,7 +114,7 @@ matrix componentwise_mul(const matrix& x, const matrix
* @return Viewing transformation matrix.
*/
template <class T>
matrix<T, 4, 4> look_at(const vector<T, 3>& position, const vector<T, 3>& target, vector<T, 3> up);
constexpr matrix<T, 4, 4> look_at(const vector<T, 3>& position, const vector<T, 3>& target, vector<T, 3> up);
/**
* Multiplies two matrices.
@ -124,15 +124,15 @@ matrix look_at(const vector& position, const vector& target
* @return Product of the two matrices.
*/
template <class T>
matrix<T, 2, 2> mul(const matrix<T, 2, 2>& x, const matrix<T, 2, 2>& y);
constexpr matrix<T, 2, 2> mul(const matrix<T, 2, 2>& x, const matrix<T, 2, 2>& y);
/// @copydoc mul(const matrix<T, 2, 2>&, const matrix<T, 2, 2>&);
template <class T>
matrix<T, 3, 3> mul(const matrix<T, 3, 3>& x, const matrix<T, 3, 3>& y);
constexpr matrix<T, 3, 3> mul(const matrix<T, 3, 3>& x, const matrix<T, 3, 3>& y);
/// @copydoc mul(const matrix<T, 2, 2>&, const matrix<T, 2, 2>&);
template <class T>
matrix<T, 4, 4> mul(const matrix<T, 4, 4>& x, const matrix<T, 4, 4>& y);
constexpr matrix<T, 4, 4> mul(const matrix<T, 4, 4>& x, const matrix<T, 4, 4>& y);
/**
* Multiplies a matrix by a scalar.
@ -142,7 +142,7 @@ matrix mul(const matrix& x, const matrix& y);
* @return Product of the matrix and the scalar..
*/
template <class T, std::size_t N, std::size_t M>
matrix<T, N, M> mul(const matrix<T, N, M>& m, T s);
constexpr matrix<T, N, M> mul(const matrix<T, N, M>& m, T s);
/**
* Transforms a vector by a matrix.
@ -152,15 +152,15 @@ matrix mul(const matrix& m, T s);
* @return Transformed vector.
*/
template <class T>
vector<T, 2> mul(const matrix<T, 2, 2>& m, const vector<T, 2>& v);
constexpr vector<T, 2> mul(const matrix<T, 2, 2>& m, const vector<T, 2>& v);
/// @copydoc mul(const matrix<T, 2, 2>&, const vector<T, 2>&)
template <class T>
vector<T, 3> mul(const matrix<T, 3, 3>& m, const vector<T, 3>& v);
constexpr vector<T, 3> mul(const matrix<T, 3, 3>& m, const vector<T, 3>& v);
/// @copydoc mul(const matrix<T, 2, 2>&, const vector<T, 2>&)
template <class T>
vector<T, 4> mul(const matrix<T, 4, 4>& m, const vector<T, 4>& v);
constexpr vector<T, 4> mul(const matrix<T, 4, 4>& m, const vector<T, 4>& v);
/**
* Creates an orthographic projection matrix which will transform the near and far clipping planes to `[-1, 1]`, respectively.
@ -174,7 +174,7 @@ vector mul(const matrix& m, const vector& v);
* @return Orthographic projection matrix.
*/
template <class T>
matrix<T, 4, 4> ortho(T left, T right, T bottom, T top, T z_near, T z_far);
constexpr matrix<T, 4, 4> ortho(T left, T right, T bottom, T top, T z_near, T z_far);
/**
* Creates an orthographic projection matrix which will transform the near and far clipping planes to `[0, 1]`, respectively.
@ -188,7 +188,7 @@ matrix ortho(T left, T right, T bottom, T top, T z_near, T z_far);
* @return Orthographic projection matrix.
*/
template <class T>
matrix<T, 4, 4> ortho_half_z(T left, T right, T bottom, T top, T z_near, T z_far);
constexpr matrix<T, 4, 4> ortho_half_z(T left, T right, T bottom, T top, T z_near, T z_far);
/**
* Calculates the outer product of a pair of vectors.
@ -197,15 +197,15 @@ matrix ortho_half_z(T left, T right, T bottom, T top, T z_near, T z_far
* @param r Parameter to be treated as a row vector.
*/
template <class T>
matrix<T, 2, 2> outer_product(const vector<T, 2>& c, const vector<T, 2>& r);
constexpr matrix<T, 2, 2> outer_product(const vector<T, 2>& c, const vector<T, 2>& r);
/// @copydoc outer_product(const vector<T, 2>&, const vector<T, 2>&)
template <class T>
matrix<T, 3, 3> outer_product(const vector<T, 3>& c, const vector<T, 3>& r);
constexpr matrix<T, 3, 3> outer_product(const vector<T, 3>& c, const vector<T, 3>& r);
/// @copydoc outer_product(const vector<T, 2>&, const vector<T, 2>&)
template <class T>
matrix<T, 4, 4> outer_product(const vector<T, 4>& c, const vector<T, 4> r);
constexpr matrix<T, 4, 4> outer_product(const vector<T, 4>& c, const vector<T, 4> r);
/**
* Creates a perspective projection matrix which will transform the near and far clipping planes to `[-1, 1]`, respectively.
@ -238,7 +238,7 @@ matrix perspective_half_z(T vertical_fov, T aspect_ratio, T z_near, T z
* @return Resized matrix.
*/
template <std::size_t N1, std::size_t M1, class T, std::size_t N0, std::size_t M0>
matrix<T, N1, M1> resize(const matrix<T, N0, M0>& m);
constexpr matrix<T, N1, M1> resize(const matrix<T, N0, M0>& m);
/**
* Constructs a rotation matrix.
@ -285,7 +285,7 @@ matrix3 rotate_z(T angle);
* @return Scaled matrix.
*/
template <class T>
matrix<T, 4, 4> scale(const matrix<T, 4, 4>& m, const vector<T, 3>& v);
constexpr matrix<T, 4, 4> scale(const matrix<T, 4, 4>& m, const vector<T, 3>& v);
/**
* Subtracts a matrix from another matrix.
@ -295,15 +295,15 @@ matrix scale(const matrix& m, const vector& v);
* @return Difference between the two matrices.
*/
template <class T>
matrix<T, 2, 2> sub(const matrix<T, 2, 2>& x, const matrix<T, 2, 2>& y);
constexpr matrix<T, 2, 2> sub(const matrix<T, 2, 2>& x, const matrix<T, 2, 2>& y);
/// @copydoc sub(const matrix<T, 2, 2>&, const matrix<T, 2, 2>&)
template <class T>
matrix<T, 3, 3> sub(const matrix<T, 3, 3>& x, const matrix<T, 3, 3>& y);
constexpr matrix<T, 3, 3> sub(const matrix<T, 3, 3>& x, const matrix<T, 3, 3>& y);
/// @copydoc sub(const matrix<T, 2, 2>&, const matrix<T, 2, 2>&)
template <class T>
matrix<T, 4, 4> sub(const matrix<T, 4, 4>& x, const matrix<T, 4, 4>& y);
constexpr matrix<T, 4, 4> sub(const matrix<T, 4, 4>& x, const matrix<T, 4, 4>& y);
/**
* Translates a matrix.
@ -313,7 +313,7 @@ matrix sub(const matrix& x, const matrix& y);
* @return Translated matrix.
*/
template <class T>
matrix<T, 4, 4> translate(const matrix<T, 4, 4>& m, const vector<T, 3>& v);
constexpr matrix<T, 4, 4> translate(const matrix<T, 4, 4>& m, const vector<T, 3>& v);
/**
* Calculates the transpose of a matrix.
@ -321,15 +321,15 @@ matrix translate(const matrix& m, const vector& v);
* @param m Matrix of which to take the transpose.
*/
template <class T>
matrix<T, 2, 2> transpose(const matrix<T, 2, 2>& m);
constexpr matrix<T, 2, 2> transpose(const matrix<T, 2, 2>& m);
/// @copydoc transpose(const matrix<T, 2, 2>&)
template <class T>
matrix<T, 3, 3> transpose(const matrix<T, 3, 3>& m);
constexpr matrix<T, 3, 3> transpose(const matrix<T, 3, 3>& m);
/// @copydoc transpose(const matrix<T, 2, 2>&)
template <class T>
matrix<T, 4, 4> transpose(const matrix<T, 4, 4>& m);
constexpr matrix<T, 4, 4> transpose(const matrix<T, 4, 4>& m);
/**
* Types casts each matrix element and returns a matrix of the casted type.
@ -342,10 +342,10 @@ matrix transpose(const matrix& m);
* @return Type-casted matrix.
*/
template <class T2, class T1, std::size_t N, std::size_t M>
matrix<T2, N, M> type_cast(const matrix<T1, N, M>& m);
constexpr matrix<T2, N, M> type_cast(const matrix<T1, N, M>& m);
template <class T>
matrix<T, 2, 2> add(const matrix<T, 2, 2>& x, const matrix<T, 2, 2>& y)
constexpr matrix<T, 2, 2> add(const matrix<T, 2, 2>& x, const matrix<T, 2, 2>& y)
{
return
{{
@ -355,7 +355,7 @@ matrix add(const matrix& x, const matrix& y)
}
template <class T>
matrix<T, 3, 3> add(const matrix<T, 3, 3>& x, const matrix<T, 3, 3>& y)
constexpr matrix<T, 3, 3> add(const matrix<T, 3, 3>& x, const matrix<T, 3, 3>& y)
{
return
{{
@ -366,7 +366,7 @@ matrix add(const matrix& x, const matrix& y)
}
template <class T>
matrix<T, 4, 4> add(const matrix<T, 4, 4>& x, const matrix<T, 4, 4>& y)
constexpr matrix<T, 4, 4> add(const matrix<T, 4, 4>& x, const matrix<T, 4, 4>& y)
{
return
{{
@ -378,20 +378,20 @@ matrix add(const matrix& x, const matrix& y)
}
template <std::size_t N, std::size_t M, typename T>
inline matrix<T, N, M>& as_matrix(T& data)
constexpr inline matrix<T, N, M>& as_matrix(T& data)
{
static_assert(std::is_pod<matrix<T, N, M>>::value);
return reinterpret_cast<matrix<T, N, M>&>(data);
}
template <class T>
T determinant(const matrix<T, 2, 2>& m)
constexpr T determinant(const matrix<T, 2, 2>& m)
{
return m[0][0] * m[1][1] - m[0][1] * m[1][0];
}
template <class T>
T determinant(const matrix<T, 3, 3>& m)
constexpr T determinant(const matrix<T, 3, 3>& m)
{
return m[0][0] * m [1][1] * m[2][2] +
m[0][1] * m[1][2] * m[2][0] +
@ -402,7 +402,7 @@ T determinant(const matrix& m)
}
template <class T>
T determinant(const matrix<T, 4, 4>& m)
constexpr T determinant(const matrix<T, 4, 4>& m)
{
return m[0][3] * m[1][2] * m[2][1] * m[3][0] - m[0][2] * m[1][3] * m[2][1] * m[3][0] -
m[0][3] * m[1][1] * m[2][2] * m[3][0] + m[0][1] * m[1][3] * m[2][2] * m[3][0] +
@ -419,7 +419,7 @@ T determinant(const matrix& m)
}
template <class T>
matrix<T, 2, 2> inverse(const matrix<T, 2, 2>& m)
constexpr matrix<T, 2, 2> inverse(const matrix<T, 2, 2>& m)
{
static_assert(std::is_floating_point<T>::value);
@ -432,7 +432,7 @@ matrix inverse(const matrix& m)
}
template <class T>
matrix<T, 3, 3> inverse(const matrix<T, 3, 3>& m)
constexpr matrix<T, 3, 3> inverse(const matrix<T, 3, 3>& m)
{
static_assert(std::is_floating_point<T>::value);
@ -461,7 +461,7 @@ matrix inverse(const matrix& m)
}
template <class T>
matrix<T, 4, 4> inverse(const matrix<T, 4, 4>& m)
constexpr matrix<T, 4, 4> inverse(const matrix<T, 4, 4>& m)
{
static_assert(std::is_floating_point<T>::value);
@ -500,7 +500,7 @@ matrix inverse(const matrix& m)
}
template <class T>
matrix<T, 2, 2> componentwise_mul(const matrix<T, 2, 2>& x, const matrix<T, 2, 2>& y)
constexpr matrix<T, 2, 2> componentwise_mul(const matrix<T, 2, 2>& x, const matrix<T, 2, 2>& y)
{
return
{{
@ -510,7 +510,7 @@ matrix componentwise_mul(const matrix& x, const matrix
}
template <class T>
matrix<T, 3, 3> componentwise_mul(const matrix<T, 3, 3>& x, const matrix<T, 3, 3>& y)
constexpr matrix<T, 3, 3> componentwise_mul(const matrix<T, 3, 3>& x, const matrix<T, 3, 3>& y)
{
return
{{
@ -521,7 +521,7 @@ matrix componentwise_mul(const matrix& x, const matrix
}
template <class T>
matrix<T, 4, 4> componentwise_mul(const matrix<T, 4, 4>& x, const matrix<T, 4, 4>& y)
constexpr matrix<T, 4, 4> componentwise_mul(const matrix<T, 4, 4>& x, const matrix<T, 4, 4>& y)
{
return
{{
@ -533,7 +533,7 @@ matrix componentwise_mul(const matrix& x, const matrix
}
template <class T>
matrix<T, 4, 4> look_at(const vector<T, 3>& position, const vector<T, 3>& target, vector<T, 3> up)
constexpr matrix<T, 4, 4> look_at(const vector<T, 3>& position, const vector<T, 3>& target, vector<T, 3> up)
{
vector<T, 3> forward = normalize(sub(target, position));
vector<T, 3> right = normalize(cross(forward, up));
@ -551,7 +551,7 @@ matrix look_at(const vector& position, const vector& target
}
template <class T>
matrix<T, 2, 2> mul(const matrix<T, 2, 2>& x, const matrix<T, 2, 2>& y)
constexpr matrix<T, 2, 2> mul(const matrix<T, 2, 2>& x, const matrix<T, 2, 2>& y)
{
return
{{
@ -561,7 +561,7 @@ matrix mul(const matrix& x, const matrix& y)
}
template <class T>
matrix<T, 3, 3> mul(const matrix<T, 3, 3>& x, const matrix<T, 3, 3>& y)
constexpr matrix<T, 3, 3> mul(const matrix<T, 3, 3>& x, const matrix<T, 3, 3>& y)
{
return
{{
@ -572,7 +572,7 @@ matrix mul(const matrix& x, const matrix& y)
}
template <class T>
matrix<T, 4, 4> mul(const matrix<T, 4, 4>& x, const matrix<T, 4, 4>& y)
constexpr matrix<T, 4, 4> mul(const matrix<T, 4, 4>& x, const matrix<T, 4, 4>& y)
{
return
{{
@ -585,19 +585,19 @@ matrix mul(const matrix& x, const matrix& y)
/// @private
template <class T, std::size_t N, std::size_t M, std::size_t... I>
inline matrix<T, N, M> mul(const matrix<T, N, M>& m, T s, std::index_sequence<I...>)
constexpr inline matrix<T, N, M> mul(const matrix<T, N, M>& m, T s, std::index_sequence<I...>)
{
return {{(m[I] * s)...}};
}
template <class T, std::size_t N, std::size_t M>
inline matrix<T, N, M> mul(const matrix<T, N, M>& m, T s)
constexpr inline matrix<T, N, M> mul(const matrix<T, N, M>& m, T s)
{
return mul(m, s, std::make_index_sequence<N>{});
}
template <class T>
vector<T, 2> mul(const matrix<T, 2, 2>& m, const vector<T, 2>& v)
constexpr vector<T, 2> mul(const matrix<T, 2, 2>& m, const vector<T, 2>& v)
{
return
{
@ -607,7 +607,7 @@ vector mul(const matrix& m, const vector& v)
}
template <class T>
vector<T, 3> mul(const matrix<T, 3, 3>& m, const vector<T, 3>& v)
constexpr vector<T, 3> mul(const matrix<T, 3, 3>& m, const vector<T, 3>& v)
{
return
{
@ -618,7 +618,7 @@ vector mul(const matrix& m, const vector& v)
}
template <class T>
vector<T, 4> mul(const matrix<T, 4, 4>& m, const vector<T, 4>& v)
constexpr vector<T, 4> mul(const matrix<T, 4, 4>& m, const vector<T, 4>& v)
{
return
{
@ -630,7 +630,7 @@ vector mul(const matrix& m, const vector& v)
}
template <class T>
matrix<T, 4, 4> ortho(T left, T right, T bottom, T top, T z_near, T z_far)
constexpr matrix<T, 4, 4> ortho(T left, T right, T bottom, T top, T z_near, T z_far)
{
return
{{
@ -642,7 +642,7 @@ matrix ortho(T left, T right, T bottom, T top, T z_near, T z_far)
}
template <class T>
matrix<T, 4, 4> ortho_half_z(T left, T right, T bottom, T top, T z_near, T z_far)
constexpr matrix<T, 4, 4> ortho_half_z(T left, T right, T bottom, T top, T z_near, T z_far)
{
return
{{
@ -654,7 +654,7 @@ matrix ortho_half_z(T left, T right, T bottom, T top, T z_near, T z_far
}
template <class T>
matrix<T, 2, 2> outer_product(const vector<T, 2>& c, const vector<T, 2>& r)
constexpr matrix<T, 2, 2> outer_product(const vector<T, 2>& c, const vector<T, 2>& r)
{
return
{{
@ -664,7 +664,7 @@ matrix outer_product(const vector& c, const vector& r)
}
template <class T>
matrix<T, 3, 3> outer_product(const vector<T, 3>& c, const vector<T, 3>& r)
constexpr matrix<T, 3, 3> outer_product(const vector<T, 3>& c, const vector<T, 3>& r)
{
return
{{
@ -675,7 +675,7 @@ matrix outer_product(const vector& c, const vector& r)
}
template <class T>
matrix<T, 4, 4> outer_product(const vector<T, 4>& c, const vector<T, 4> r)
constexpr matrix<T, 4, 4> outer_product(const vector<T, 4>& c, const vector<T, 4> r)
{
return
{{
@ -717,7 +717,7 @@ matrix perspective_half_z(T vertical_fov, T aspect_ratio, T z_near, T z
}
template <std::size_t N1, std::size_t M1, class T, std::size_t N0, std::size_t M0>
matrix<T, N1, M1> resize(const matrix<T, N0, M0>& m)
constexpr matrix<T, N1, M1> resize(const matrix<T, N0, M0>& m)
{
matrix<T, N1, M1> resized;
@ -796,7 +796,7 @@ matrix3 rotate_z(T angle)
}
template <class T>
matrix<T, 4, 4> scale(const matrix<T, 4, 4>& m, const vector<T, 3>& v)
constexpr matrix<T, 4, 4> scale(const matrix<T, 4, 4>& m, const vector<T, 3>& v)
{
return mul(m, matrix<T, 4, 4>
{{
@ -808,7 +808,7 @@ matrix scale(const matrix& m, const vector& v)
}
template <class T>
matrix<T, 2, 2> sub(const matrix<T, 2, 2>& x, const matrix<T, 2, 2>& y)
constexpr matrix<T, 2, 2> sub(const matrix<T, 2, 2>& x, const matrix<T, 2, 2>& y)
{
return
{{
@ -818,7 +818,7 @@ matrix sub(const matrix& x, const matrix& y)
}
template <class T>
matrix<T, 3, 3> sub(const matrix<T, 3, 3>& x, const matrix<T, 3, 3>& y)
constexpr matrix<T, 3, 3> sub(const matrix<T, 3, 3>& x, const matrix<T, 3, 3>& y)
{
return
{{
@ -829,7 +829,7 @@ matrix sub(const matrix& x, const matrix& y)
}
template <class T>
matrix<T, 4, 4> sub(const matrix<T, 4, 4>& x, const matrix<T, 4, 4>& y)
constexpr matrix<T, 4, 4> sub(const matrix<T, 4, 4>& x, const matrix<T, 4, 4>& y)
{
return
{{
@ -841,7 +841,7 @@ matrix sub(const matrix& x, const matrix& y)
}
template <class T>
matrix<T, 4, 4> translate(const matrix<T, 4, 4>& m, const vector<T, 3>& v)
constexpr matrix<T, 4, 4> translate(const matrix<T, 4, 4>& m, const vector<T, 3>& v)
{
return mul(m, matrix<T, 4, 4>
{{
@ -853,7 +853,7 @@ matrix translate(const matrix& m, const vector& v)
}
template <class T>
matrix<T, 2, 2> transpose(const matrix<T, 2, 2>& m)
constexpr matrix<T, 2, 2> transpose(const matrix<T, 2, 2>& m)
{
return
@ -869,7 +869,7 @@ matrix transpose(const matrix& m)
}
template <class T>
matrix<T, 3, 3> transpose(const matrix<T, 3, 3>& m)
constexpr matrix<T, 3, 3> transpose(const matrix<T, 3, 3>& m)
{
return
@ -889,7 +889,7 @@ matrix transpose(const matrix& m)
}
template <class T>
matrix<T, 4, 4> transpose(const matrix<T, 4, 4>& m)
constexpr matrix<T, 4, 4> transpose(const matrix<T, 4, 4>& m)
{
return
@ -914,13 +914,13 @@ matrix transpose(const matrix& m)
/// @private
template <class T2, class T1, std::size_t N, std::size_t M, std::size_t... I>
inline matrix<T2, N, M> type_cast(const matrix<T1, N, M>& m, std::index_sequence<I...>)
constexpr inline matrix<T2, N, M> type_cast(const matrix<T1, N, M>& m, std::index_sequence<I...>)
{
return {type_cast<T2>(m[I])...};
}
template <class T2, class T1, std::size_t N, std::size_t M>
matrix<T2, N, M> type_cast(const matrix<T1, N, M>& m)
constexpr matrix<T2, N, M> type_cast(const matrix<T1, N, M>& m)
{
return type_cast<T2>(m, std::make_index_sequence<N>{});
}

+ 12
- 12
src/math/matrix-operators.hpp View File

@ -25,60 +25,60 @@
/// @copydoc math::add(const math::matrix<T, 2, 2>&, const math::matrix<T, 2, 2>&)
template <class T, std::size_t N, std::size_t M>
math::matrix<T, N, M> operator+(const math::matrix<T, N, M>& x, const math::matrix<T, N, M>& y);
constexpr math::matrix<T, N, M> operator+(const math::matrix<T, N, M>& x, const math::matrix<T, N, M>& y);
/// @copydoc math::mul(const math::matrix<T, 2, 2>&, const math::matrix<T, 2, 2>&)
template <class T, std::size_t N, std::size_t M>
math::matrix<T, N, M> operator*(const math::matrix<T, N, M>& x, const math::matrix<T, N, M>& y);
constexpr math::matrix<T, N, M> operator*(const math::matrix<T, N, M>& x, const math::matrix<T, N, M>& y);
/// @copydoc math::mul(const math::matrix<T, N, M>&, T)
template <class T, std::size_t N, std::size_t M>
math::matrix<T, N, M> operator*(const math::matrix<T, N, M>& m, T s);
constexpr math::matrix<T, N, M> operator*(const math::matrix<T, N, M>& m, T s);
/// @copydoc math::mul(const math::matrix<T, N, M>&, T)
template <class T, std::size_t N, std::size_t M>
math::matrix<T, N, M> operator*(T s, const math::matrix<T, N, M>& m);
constexpr math::matrix<T, N, M> operator*(T s, const math::matrix<T, N, M>& m);
/// @copydoc math::mul(const math::matrix<T, 2, 2>&, const math::vector<T, 2>&)
template <class T, std::size_t N>
math::vector<T, N> operator*(const math::matrix<T, N, N>& m, const math::vector<T, N>& v);
constexpr math::vector<T, N> operator*(const math::matrix<T, N, N>& m, const math::vector<T, N>& v);
/// @copydoc math::sub(const math::matrix<T, 2, 2>&, const math::matrix<T, 2, 2>&)
template <class T, std::size_t N, std::size_t M>
math::matrix<T, N, M> operator-(const math::matrix<T, N, M>& x, const math::matrix<T, N, M>& y);
constexpr math::matrix<T, N, M> operator-(const math::matrix<T, N, M>& x, const math::matrix<T, N, M>& y);
template <class T, std::size_t N, std::size_t M>
inline math::matrix<T, N, M> operator+(const math::matrix<T, N, M>& x, const math::matrix<T, N, M>& y)
constexpr inline math::matrix<T, N, M> operator+(const math::matrix<T, N, M>& x, const math::matrix<T, N, M>& y)
{
return add(x, y);
}
template <class T, std::size_t N, std::size_t M>
inline math::matrix<T, N, M> operator*(const math::matrix<T, N, M>& x, const math::matrix<T, N, M>& y)
constexpr inline math::matrix<T, N, M> operator*(const math::matrix<T, N, M>& x, const math::matrix<T, N, M>& y)
{
return mul(x, y);
}
template <class T, std::size_t N, std::size_t M>
inline math::matrix<T, N, M> operator*(const math::matrix<T, N, M>& m, T s)
constexpr inline math::matrix<T, N, M> operator*(const math::matrix<T, N, M>& m, T s)
{
return mul(m, s);
}
template <class T, std::size_t N, std::size_t M>
inline math::matrix<T, N, M> operator*(T s, const math::matrix<T, N, M>& m)
constexpr inline math::matrix<T, N, M> operator*(T s, const math::matrix<T, N, M>& m)
{
return mul(m, s);
}
template <class T, std::size_t N>
inline math::vector<T, N> operator*(const math::matrix<T, N, N>& m, const math::vector<T, N>& v)
constexpr inline math::vector<T, N> operator*(const math::matrix<T, N, N>& m, const math::vector<T, N>& v)
{
return mul(m, v);
}
template <class T, std::size_t N, std::size_t M>
inline math::matrix<T, N, M> operator-(const math::matrix<T, N, M>& x, const math::matrix<T, N, M>& y)
constexpr inline math::matrix<T, N, M> operator-(const math::matrix<T, N, M>& x, const math::matrix<T, N, M>& y)
{
return sub(x, y);
}

+ 12
- 0
src/math/matrix-type.hpp View File

@ -66,14 +66,26 @@ constexpr matrix matrix::identity = identity_matrix(std::ma
template <typename T>
using matrix2 = matrix<T, 2, 2>;
/// 2x2 matrix.
template <typename T>
using matrix2x2 = matrix<T, 2, 2>;
/// 3x3 matrix.
template <typename T>
using matrix3 = matrix<T, 3, 3>;
/// 3x3 matrix.
template <typename T>
using matrix3x3 = matrix<T, 3, 3>;
/// 4x4 matrix.
template <typename T>
using matrix4 = matrix<T, 4, 4>;
/// 4x4 matrix.
template <typename T>
using matrix4x4 = matrix<T, 4, 4>;
} // namespace math
#endif // ANTKEEPER_MATH_MATRIX_TYPE_HPP

+ 69
- 71
src/math/vector-functions.hpp View File

@ -36,7 +36,7 @@ namespace math {
* @return Sum of the two vectors.
*/
template <class T, std::size_t N>
vector<T, N> add(const vector<T, N>& x, const vector<T, N>& y);
constexpr vector<T, N> add(const vector<T, N>& x, const vector<T, N>& y);
/**
* Checks if all elements of a boolean vector are `true`.
@ -45,7 +45,7 @@ vector add(const vector& x, const vector& y);
* @return `true` if all elements are `true`, `false` otherwise.
*/
template <std::size_t N>
bool all(const vector<bool, N>& x);
constexpr bool all(const vector<bool, N>& x);
/**
* Checks if any elements of a boolean vector are `true`.
@ -54,7 +54,7 @@ bool all(const vector& x);
* @return `true` if any elements are `true`, `false` otherwise.
*/
template <std::size_t N>
bool any(const vector<bool, N>& x);
constexpr bool any(const vector<bool, N>& x);
/**
* Reinterprets data as an `N`-dimensional vector of type `T`.
@ -64,7 +64,7 @@ bool any(const vector& x);
* @param data Data to reinterpret.
*/
template <std::size_t N, typename T>
vector<T, N>& as_vector(T& data);
constexpr vector<T, N>& as_vector(T& data);
/**
* Clamps the values of a vector's elements.
@ -75,7 +75,7 @@ vector& as_vector(T& data);
* @return Clamped vector.
*/
template <class T, std::size_t N>
vector<T, N> clamp(const vector<T, N>& x, T min_value, T max_value);
constexpr vector<T, N> clamp(const vector<T, N>& x, T min_value, T max_value);
/**
* Clamps the length of a vector.
@ -95,7 +95,7 @@ vector clamp_length(const vector& x, T max_length);
* @return Cross product of the two vectors.
*/
template <class T>
vector<T, 3> cross(const vector<T, 3>& x, const vector<T, 3>& y);
constexpr vector<T, 3> cross(const vector<T, 3>& x, const vector<T, 3>& y);
/**
* Calculates the distance between two points.
@ -115,7 +115,7 @@ vector distance(const vector& p0, const vector& p1);
* @return Squared distance between the two points.
*/
template <class T, std::size_t N>
vector<T, N> distance_squared(const vector<T, N>& p0, const vector<T, N>& p1);
constexpr vector<T, N> distance_squared(const vector<T, N>& p0, const vector<T, N>& p1);
/**
* Divides a vector by another vector.
@ -125,7 +125,7 @@ vector distance_squared(const vector& p0, const vector& p1);
* @return Result of the division.
*/
template <class T, std::size_t N>
vector<T, N> div(const vector<T, N>& x, const vector<T, N>& y);
constexpr vector<T, N> div(const vector<T, N>& x, const vector<T, N>& y);
/**
* Divides a vector by a scalar.
@ -135,7 +135,7 @@ vector div(const vector& x, const vector& y);
* @return Result of the division.
*/
template <class T, std::size_t N>
vector<T, N> div(const vector<T, N>& v, T s);
constexpr vector<T, N> div(const vector<T, N>& v, T s);
/**
* Calculates the dot product of two vectors.
@ -145,7 +145,7 @@ vector div(const vector& v, T s);
* @return Dot product of the two vectors.
*/
template <class T, std::size_t N>
T dot(const vector<T, N>& x, const vector<T, N>& y);
constexpr T dot(const vector<T, N>& x, const vector<T, N>& y);
/**
* Compares two vectors for equality
@ -155,7 +155,7 @@ T dot(const vector& x, const vector& y);
* @return Boolean vector containing the result of the element comparisons.
*/
template <class T, std::size_t N>
vector<bool, N> equal(const vector<T, N>& x, const vector<T, N>& y);
constexpr vector<bool, N> equal(const vector<T, N>& x, const vector<T, N>& y);
/**
* Performs a component-wise greater-than comparison of two vectors.
@ -165,7 +165,7 @@ vector equal(const vector& x, const vector& y);
* @return Boolean vector containing the result of the element comparisons.
*/
template <class T, std::size_t N>
vector<bool, N> greater_than(const vector<T, N>& x, const vector<T, N>& y);
constexpr vector<bool, N> greater_than(const vector<T, N>& x, const vector<T, N>& y);
/**
* Performs a component-wise greater-than or equal-to comparison of two vectors.
@ -175,7 +175,7 @@ vector greater_than(const vector& x, const vector& y);
* @return Boolean vector containing the result of the element comparisons.
*/
template <class T, std::size_t N>
vector<bool, N> greater_than_equal(const vector<T, N>& x, const vector<T, N>& y);
constexpr vector<bool, N> greater_than_equal(const vector<T, N>& x, const vector<T, N>& y);
/**
* Calculates the length of a vector.
@ -193,7 +193,7 @@ T length(const vector& x);
* @return Squared length of the vector.
*/
template <class T, std::size_t N>
T length_squared(const vector<T, N>& x);
constexpr T length_squared(const vector<T, N>& x);
/**
* Performs a component-wise less-than comparison of two vectors.
@ -203,7 +203,7 @@ T length_squared(const vector& x);
* @return Boolean vector containing the result of the element comparisons.
*/
template <class T, std::size_t N>
vector<bool, N> less_than(const vector<T, N>& x, const vector<T, N>& y);
constexpr vector<bool, N> less_than(const vector<T, N>& x, const vector<T, N>& y);
/**
* Performs a component-wise less-than or equal-to comparison of two vectors.
@ -213,7 +213,7 @@ vector less_than(const vector& x, const vector& y);
* @return Boolean vector containing the result of the element comparisons.
*/
template <class T, std::size_t N>
vector<bool, N> less_than_equal(const vector<T, N>& x, const vector<T, N>& y);
constexpr vector<bool, N> less_than_equal(const vector<T, N>& x, const vector<T, N>& y);
/**
* Multiplies two vectors.
@ -223,7 +223,7 @@ vector less_than_equal(const vector& x, const vector& y);
* @return Product of the two vectors.
*/
template <class T, std::size_t N>
vector<T, N> mul(const vector<T, N>& x, const vector<T, N>& y);
constexpr vector<T, N> mul(const vector<T, N>& x, const vector<T, N>& y);
/**
* Multiplies a vector by a scalar.
@ -233,7 +233,7 @@ vector mul(const vector& x, const vector& y);
* @return Product of the vector and scalar.
*/
template <class T, std::size_t N>
vector<T, N> mul(const vector<T, N>& v, T s);
constexpr vector<T, N> mul(const vector<T, N>& v, T s);
/**
* Negates a vector.
@ -242,7 +242,7 @@ vector mul(const vector& v, T s);
* @return Negated vector.
*/
template <class T, std::size_t N>
vector<T, N> negate(const vector<T, N>& x);
constexpr vector<T, N> negate(const vector<T, N>& x);
/**
* Calculates the unit vector in the same direction as the original vector.
@ -260,7 +260,7 @@ vector normalize(const vector& x);
* @return Logically inverted vector.
*/
template <class T, std::size_t N>
vector<bool, N> not(const vector<T, N>& x);
constexpr vector<bool, N> not(const vector<T, N>& x);
/**
* Compares two vectors for inequality
@ -270,7 +270,7 @@ vector not(const vector& x);
* @return Boolean vector containing the result of the element comparisons.
*/
template <class T, std::size_t N>
vector<bool, N> not_equal(const vector<T, N>& x, const vector<T, N>& y);
constexpr vector<bool, N> not_equal(const vector<T, N>& x, const vector<T, N>& y);
/**
* Resizes a vector. Any new elements will be set to `0`.
@ -279,7 +279,7 @@ vector not_equal(const vector& x, const vector& y);
* @return Resized vector.
*/
template <std::size_t N1, class T, std::size_t N0>
vector<T, N1> resize(const vector<T, N0>& v);
constexpr vector<T, N1> resize(const vector<T, N0>& v);
/**
* Subtracts a vector from another vector.
@ -289,7 +289,7 @@ vector resize(const vector& v);
* @return Difference between the two vectors.
*/
template <class T, std::size_t N>
vector<T, N> sub(const vector<T, N>& x, const vector<T, N>& y);
constexpr vector<T, N> sub(const vector<T, N>& x, const vector<T, N>& y);
/**
* Makes an m-dimensional vector by rearranging and/or duplicating elements of an n-dimensional vector.
@ -300,7 +300,7 @@ vector sub(const vector& x, const vector& y);
* @return Vector containing elements from vector `v` in the order specified by `Indices`. The size of the returned vector is equivalent to the number of indices in `Indices`.
*/
template <std::size_t... Indices, class T, std::size_t N>
vector<T, sizeof...(Indices)> swizzle(const vector<T, N>& v);
constexpr vector<T, sizeof...(Indices)> swizzle(const vector<T, N>& v);
/**
* Types casts each vector component and returns a vector of the casted type.
@ -312,49 +312,49 @@ vector swizzle(const vector& v);
* @return Type-casted vector.
*/
template <class T2, class T1, std::size_t N>
vector<T2, N> type_cast(const vector<T1, N>& v);
constexpr vector<T2, N> type_cast(const vector<T1, N>& v);
/// @private
template <class T, std::size_t N, std::size_t... I>
inline vector<T, N> add(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
constexpr inline vector<T, N> add(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
{
return {(x[I] + y[I])...};
}
template <class T, std::size_t N>
inline vector<T, N> add(const vector<T, N>& x, const vector<T, N>& y)
constexpr inline vector<T, N> add(const vector<T, N>& x, const vector<T, N>& y)
{
return add(x, y, std::make_index_sequence<N>{});
}
/// @private
template <std::size_t N, std::size_t... I>
inline bool all(const vector<bool, N>& x, std::index_sequence<I...>)
constexpr inline bool all(const vector<bool, N>& x, std::index_sequence<I...>)
{
return (x[I] && ...);
}
template <std::size_t N>
inline bool all(const vector<bool, N>& x)
constexpr inline bool all(const vector<bool, N>& x)
{
return all(x, std::make_index_sequence<N>{});
}
/// @private
template <std::size_t N, std::size_t... I>
inline bool any(const vector<bool, N>& x, std::index_sequence<I...>)
constexpr inline bool any(const vector<bool, N>& x, std::index_sequence<I...>)
{
return (x[I] || ...);
}
template <std::size_t N>
inline bool any(const vector<bool, N>& x)
constexpr inline bool any(const vector<bool, N>& x)
{
return any(x, std::make_index_sequence<N>{});
}
template <std::size_t N, typename T>
inline vector<T, N>& as_vector(T& data)
constexpr inline vector<T, N>& as_vector(T& data)
{
static_assert(std::is_pod<vector<T, N>>::value);
return reinterpret_cast<vector<T, N>&>(data);
@ -362,13 +362,13 @@ inline vector& as_vector(T& data)
/// @private
template <class T, std::size_t N, std::size_t... I>
inline vector<T, N> clamp(const vector<T, N>& x, T min_value, T max_value, std::index_sequence<I...>)
constexpr inline vector<T, N> clamp(const vector<T, N>& x, T min_value, T max_value, std::index_sequence<I...>)
{
return {std::min<T>(max_value, std::max<T>(min_value, x[I]))...};
}
template <class T, std::size_t N>
inline vector<T, N> clamp(const vector<T, N>& x, T min_value, T max_value)
constexpr inline vector<T, N> clamp(const vector<T, N>& x, T min_value, T max_value)
{
return clamp(x, min_value, max_value, std::make_index_sequence<N>{});
}
@ -381,7 +381,7 @@ vector clamp_length(const vector& x, T max_length)
}
template <class T>
inline vector<T, 3> cross(const vector<T, 3>& x, const vector<T, 3>& y)
constexpr inline vector<T, 3> cross(const vector<T, 3>& x, const vector<T, 3>& y)
{
return
{
@ -399,7 +399,7 @@ inline vector distance(const vector& p0, const vector& p1)
}
template <class T, std::size_t N>
inline vector<T, N> distance_squared(const vector<T, N>& p0, const vector<T, N>& p1)
constexpr inline vector<T, N> distance_squared(const vector<T, N>& p0, const vector<T, N>& p1)
{
static_assert(std::is_floating_point<T>::value);
return length_squared(sub(p0, p1));
@ -407,78 +407,78 @@ inline vector distance_squared(const vector& p0, const vector&
/// @private
template <class T, std::size_t N, std::size_t... I>
inline vector<T, N> div(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
constexpr inline vector<T, N> div(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
{
return {(x[I] / y[I])...};
}
template <class T, std::size_t N>
inline vector<T, N> div(const vector<T, N>& x, const vector<T, N>& y)
constexpr inline vector<T, N> div(const vector<T, N>& x, const vector<T, N>& y)
{
return div(x, y, std::make_index_sequence<N>{});
}
/// @private
template <class T, std::size_t N, std::size_t... I>
inline vector<T, N> div(const vector<T, N>& v, T s, std::index_sequence<I...>)
constexpr inline vector<T, N> div(const vector<T, N>& v, T s, std::index_sequence<I...>)
{
return {(v[I] / s)...};
}
template <class T, std::size_t N>
inline vector<T, N> div(const vector<T, N>& v, T s)
constexpr inline vector<T, N> div(const vector<T, N>& v, T s)
{
return div(v, s, std::make_index_sequence<N>{});
}
/// @private
template <class T, std::size_t N, std::size_t... I>
inline T dot(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
constexpr inline T dot(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
{
return ((x[I] * y[I]) + ...);
}
template <class T, std::size_t N>
inline T dot(const vector<T, N>& x, const vector<T, N>& y)
constexpr inline T dot(const vector<T, N>& x, const vector<T, N>& y)
{
return dot(x, y, std::make_index_sequence<N>{});
}
/// @private
template <class T, std::size_t N, std::size_t... I>
inline vector<bool, N> equal(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
constexpr inline vector<bool, N> equal(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
{
return {(x[I] == y[I])...};
}
template <class T, std::size_t N>
inline vector<bool, N> equal(const vector<T, N>& x, const vector<T, N>& y)
constexpr inline vector<bool, N> equal(const vector<T, N>& x, const vector<T, N>& y)
{
return equal(x, y, std::make_index_sequence<N>{});
}
/// @private
template <class T, std::size_t N, std::size_t... I>
inline vector<bool, N> greater_than(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
constexpr inline vector<bool, N> greater_than(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
{
return {(x[I] > y[I])...};
}
template <class T, std::size_t N>
inline vector<bool, N> greater_than(const vector<T, N>& x, const vector<T, N>& y)
constexpr inline vector<bool, N> greater_than(const vector<T, N>& x, const vector<T, N>& y)
{
return greater_than(x, y, std::make_index_sequence<N>{});
}
/// @private
template <class T, std::size_t N, std::size_t... I>
inline vector<bool, N> greater_than_equal(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
constexpr inline vector<bool, N> greater_than_equal(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
{
return {(x[I] >= y[I])...};
}
template <class T, std::size_t N>
inline vector<bool, N> greater_than_equal(const vector<T, N>& x, const vector<T, N>& y)
constexpr inline vector<bool, N> greater_than_equal(const vector<T, N>& x, const vector<T, N>& y)
{
return greater_than_equal(x, y, std::make_index_sequence<N>{});
}
@ -491,73 +491,72 @@ inline T length(const vector& x)
}
template <class T, std::size_t N>
inline T length_squared(const vector<T, N>& x)
constexpr inline T length_squared(const vector<T, N>& x)
{
static_assert(std::is_floating_point<T>::value);
return dot(x, x);
}
/// @private
template <class T, std::size_t N, std::size_t... I>
inline vector<bool, N> less_than(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
constexpr inline vector<bool, N> less_than(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
{
return {(x[I] < y[I])...};
}
template <class T, std::size_t N>
inline vector<bool, N> less_than(const vector<T, N>& x, const vector<T, N>& y)
constexpr inline vector<bool, N> less_than(const vector<T, N>& x, const vector<T, N>& y)
{
return less_than(x, y, std::make_index_sequence<N>{});
}
/// @private
template <class T, std::size_t N, std::size_t... I>
inline vector<bool, N> less_than_equal(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
constexpr inline vector<bool, N> less_than_equal(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
{
return {(x[I] <= y[I])...};
}
template <class T, std::size_t N>
inline vector<bool, N> less_than_equal(const vector<T, N>& x, const vector<T, N>& y)
constexpr inline vector<bool, N> less_than_equal(const vector<T, N>& x, const vector<T, N>& y)
{
return less_than_equal(x, y, std::make_index_sequence<N>{});
}
/// @private
template <class T, std::size_t N, std::size_t... I>
inline vector<T, N> mul(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
constexpr inline vector<T, N> mul(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
{
return {(x[I] * y[I])...};
}
template <class T, std::size_t N>
inline vector<T, N> mul(const vector<T, N>& x, const vector<T, N>& y)
constexpr inline vector<T, N> mul(const vector<T, N>& x, const vector<T, N>& y)
{
return mul(x, y, std::make_index_sequence<N>{});
}
/// @private
template <class T, std::size_t N, std::size_t... I>
inline vector<T, N> mul(const vector<T, N>& v, T s, std::index_sequence<I...>)
constexpr inline vector<T, N> mul(const vector<T, N>& v, T s, std::index_sequence<I...>)
{
return {(v[I] * s)...};
}
template <class T, std::size_t N>
inline vector<T, N> mul(const vector<T, N>& v, T s)
constexpr inline vector<T, N> mul(const vector<T, N>& v, T s)
{
return mul(v, s, std::make_index_sequence<N>{});
}
/// @private
template <class T, std::size_t N, std::size_t... I>
inline vector<T, N> negate(const vector<T, N>& x, std::index_sequence<I...>)
constexpr inline vector<T, N> negate(const vector<T, N>& x, std::index_sequence<I...>)
{
return {(-x[I])...};
}
template <class T, std::size_t N>
inline vector<T, N> negate(const vector<T, N>& x)
constexpr inline vector<T, N> negate(const vector<T, N>& x)
{
return negate(x, std::make_index_sequence<N>{});
}
@ -571,32 +570,32 @@ inline vector normalize(const vector& x)
/// @private
template <class T, std::size_t N, std::size_t... I>
inline vector<bool, N> not(const vector<T, N>& x, std::index_sequence<I...>)
constexpr inline vector<bool, N> not(const vector<T, N>& x, std::index_sequence<I...>)
{
return {!x[I]...};
}
template <class T, std::size_t N>
inline vector<bool, N> not(const vector<T, N>& x)
constexpr inline vector<bool, N> not(const vector<T, N>& x)
{
return not(x, std::make_index_sequence<N>{});
}
/// @private
template <class T, std::size_t N, std::size_t... I>
inline vector<bool, N> not_equal(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
constexpr inline vector<bool, N> not_equal(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
{
return {(x[I] != y[I])...};
}
template <class T, std::size_t N>
inline vector<bool, N> not_equal(const vector<T, N>& x, const vector<T, N>& y)
constexpr inline vector<bool, N> not_equal(const vector<T, N>& x, const vector<T, N>& y)
{
return not_equal(x, y, std::make_index_sequence<N>{});
}
template <std::size_t N1, class T, std::size_t N0>
vector<T, N1> resize(const vector<T, N0>& v)
constexpr vector<T, N1> resize(const vector<T, N0>& v)
{
vector<T, N1> resized;
@ -611,32 +610,32 @@ vector resize(const vector& v)
/// @private
template <class T, std::size_t N, std::size_t... I>
inline vector<T, N> sub(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
constexpr inline vector<T, N> sub(const vector<T, N>& x, const vector<T, N>& y, std::index_sequence<I...>)
{
return {(x[I] - y[I])...};
}
template <class T, std::size_t N>
inline vector<T, N> sub(const vector<T, N>& x, const vector<T, N>& y)
constexpr inline vector<T, N> sub(const vector<T, N>& x, const vector<T, N>& y)
{
return sub(x, y, std::make_index_sequence<N>{});
}
template <std::size_t... Indices, class T, std::size_t N>
inline vector<T, sizeof...(Indices)> swizzle(const vector<T, N>& v)
constexpr inline vector<T, sizeof...(Indices)> swizzle(const vector<T, N>& v)
{
return { v[Indices]... };
}
/// @private
template <class T2, class T1, std::size_t N, std::size_t... I>
inline vector<T2, N> type_cast(const vector<T1, N>& v, std::index_sequence<I...>)
constexpr inline vector<T2, N> type_cast(const vector<T1, N>& v, std::index_sequence<I...>)
{
return {static_cast<T2>(v[I])...};
}
template <class T2, class T1, std::size_t N>
inline vector<T2, N> type_cast(const vector<T1, N>& v)
constexpr inline vector<T2, N> type_cast(const vector<T1, N>& v)
{
return type_cast<T2>(v, std::make_index_sequence<N>{});
}
@ -644,4 +643,3 @@ inline vector type_cast(const vector& v)
} // namespace math
#endif // ANTKEEPER_MATH_VECTOR_FUNCTIONS_HPP

+ 28
- 29
src/math/vector-operators.hpp View File

@ -25,35 +25,35 @@
/// @copydoc math::add(const math::vector<T, N>&, const math::vector<T, N>&)
template <class T, std::size_t N>
math::vector<T, N> operator+(const math::vector<T, N>& x, const math::vector<T, N>& y);
constexpr math::vector<T, N> operator+(const math::vector<T, N>& x, const math::vector<T, N>& y);
/// @copydoc math::div(const math::vector<T, N>&, const math::vector<T, N>&)
template <class T, std::size_t N>
math::vector<T, N> operator/(const math::vector<T, N>& x, const math::vector<T, N>& y);
constexpr math::vector<T, N> operator/(const math::vector<T, N>& x, const math::vector<T, N>& y);
/// @copydoc math::div(const math::vector<T, N>&, T)
template <class T, std::size_t N>
math::vector<T, N> operator/(const math::vector<T, N>& v, T s);
constexpr math::vector<T, N> operator/(const math::vector<T, N>& v, T s);
/// @copydoc math::mul(const math::vector<T, N>&, const math::vector<T, N>&)
template <class T, std::size_t N>
math::vector<T, N> operator*(const math::vector<T, N>& x, const math::vector<T, N>& y);
constexpr math::vector<T, N> operator*(const math::vector<T, N>& x, const math::vector<T, N>& y);
/// @copydoc math::mul(const math::vector<T, N>&, T)
template <class T, std::size_t N>
math::vector<T, N> operator*(const math::vector<T, N>& v, T s);
constexpr math::vector<T, N> operator*(const math::vector<T, N>& v, T s);
/// @copydoc math::mul(const math::vector<T, N>&, T)
template <class T, std::size_t N>
math::vector<T, N> operator*(T s, const math::vector<T, N>& v);
constexpr math::vector<T, N> operator*(T s, const math::vector<T, N>& v);
/// @copydoc math::negate(const math::vector<T, N>&)
template <class T, std::size_t N>
math::vector<T, N> operator-(const math::vector<T, N>& x);
constexpr math::vector<T, N> operator-(const math::vector<T, N>& x);
/// @copydoc math::sub(const math::vector<T, N>&, const math::vector<T, N>&)
template <class T, std::size_t N>
math::vector<T, N> operator-(const math::vector<T, N>& x, const math::vector<T, N>& y);
constexpr math::vector<T, N> operator-(const math::vector<T, N>& x, const math::vector<T, N>& y);
/**
* Adds two vectors and stores the result in the first vector.
@ -63,7 +63,7 @@ math::vector operator-(const math::vector& x, const math::vector
* @return Reference to the first vector.
*/
template <class T, std::size_t N>
math::vector<T, N>& operator+=(math::vector<T, N>& x, const math::vector<T, N>& y);
constexpr math::vector<T, N>& operator+=(math::vector<T, N>& x, const math::vector<T, N>& y);
/**
* Subtracts two vectors and stores the result in the first vector.
@ -73,7 +73,7 @@ math::vector& operator+=(math::vector& x, const math::vector&
* @return Reference to the first vector.
*/
template <class T, std::size_t N>
math::vector<T, N>& operator-=(math::vector<T, N>& x, const math::vector<T, N>& y);
constexpr math::vector<T, N>& operator-=(math::vector<T, N>& x, const math::vector<T, N>& y);
/**
* Multiplies two vectors and stores the result in the first vector.
@ -83,7 +83,7 @@ math::vector& operator-=(math::vector& x, const math::vector&
* @return Reference to the first vector.
*/
template <class T, std::size_t N>
math::vector<T, N>& operator*=(math::vector<T, N>& x, const math::vector<T, N>& y);
constexpr math::vector<T, N>& operator*=(math::vector<T, N>& x, const math::vector<T, N>& y);
/**
* Multiplies a vector and a scalar and stores the result in the vector.
@ -93,7 +93,7 @@ math::vector& operator*=(math::vector& x, const math::vector&
* @return Reference to the vector.
*/
template <class T, std::size_t N>
math::vector<T, N>& operator*=(math::vector<T, N>& v, T s);
constexpr math::vector<T, N>& operator*=(math::vector<T, N>& v, T s);
/**
* Divides the first vector by the second vector the result in the first vector.
@ -103,7 +103,7 @@ math::vector& operator*=(math::vector& v, T s);
* @return Reference to the first vector.
*/
template <class T, std::size_t N>
math::vector<T, N>& operator/=(math::vector<T, N>& x, const math::vector<T, N>& y);
constexpr math::vector<T, N>& operator/=(math::vector<T, N>& x, const math::vector<T, N>& y);
/**
* Divides a vector by a scalar and stores the result in the vector.
@ -113,91 +113,90 @@ math::vector& operator/=(math::vector& x, const math::vector&
* @return Reference to the vector.
*/
template <class T, std::size_t N>
math::vector<T, N>& operator/=(math::vector<T, N>& v, T s);
constexpr math::vector<T, N>& operator/=(math::vector<T, N>& v, T s);
template <class T, std::size_t N>
inline math::vector<T, N> operator+(const math::vector<T, N>& x, const math::vector<T, N>& y)
constexpr inline math::vector<T, N> operator+(const math::vector<T, N>& x, const math::vector<T, N>& y)
{
return add(x, y);
}
template <class T, std::size_t N>
inline math::vector<T, N> operator-(const math::vector<T, N>& x)
constexpr inline math::vector<T, N> operator-(const math::vector<T, N>& x)
{
return negate(x);
}
template <class T, std::size_t N>
inline math::vector<T, N> operator-(const math::vector<T, N>& x, const math::vector<T, N>& y)
constexpr inline math::vector<T, N> operator-(const math::vector<T, N>& x, const math::vector<T, N>& y)
{
return sub(x, y);
}
template <class T, std::size_t N>
inline math::vector<T, N> operator*(const math::vector<T, N>& x, const math::vector<T, N>& y)
constexpr inline math::vector<T, N> operator*(const math::vector<T, N>& x, const math::vector<T, N>& y)
{
return mul(x, y);
}
template <class T, std::size_t N>
inline math::vector<T, N> operator*(const math::vector<T, N>& v, T s)
constexpr inline math::vector<T, N> operator*(const math::vector<T, N>& v, T s)
{
return mul(v, s);
}
template <class T, std::size_t N>
inline math::vector<T, N> operator*(T s, const math::vector<T, N>& v)
constexpr inline math::vector<T, N> operator*(T s, const math::vector<T, N>& v)
{
return mul(v, s);
}
template <class T, std::size_t N>
inline math::vector<T, N> operator/(const math::vector<T, N>& x, const math::vector<T, N>& y)
constexpr inline math::vector<T, N> operator/(const math::vector<T, N>& x, const math::vector<T, N>& y)
{
return div(x, y);
}
template <class T, std::size_t N>
inline math::vector<T, N> operator/(const math::vector<T, N>& v, T s)
constexpr inline math::vector<T, N> operator/(const math::vector<T, N>& v, T s)
{
return div(v, s);
}
template <class T, std::size_t N>
inline math::vector<T, N>& operator+=(math::vector<T, N>& x, const math::vector<T, N>& y)
constexpr inline math::vector<T, N>& operator+=(math::vector<T, N>& x, const math::vector<T, N>& y)
{
return (x = x + y);
}
template <class T, std::size_t N>
inline math::vector<T, N>& operator-=(math::vector<T, N>& x, const math::vector<T, N>& y)
constexpr inline math::vector<T, N>& operator-=(math::vector<T, N>& x, const math::vector<T, N>& y)
{
return (x = x - y);
}
template <class T, std::size_t N>
inline math::vector<T, N>& operator*=(math::vector<T, N>& x, const math::vector<T, N>& y)
constexpr inline math::vector<T, N>& operator*=(math::vector<T, N>& x, const math::vector<T, N>& y)
{
return (x = x * y);
}
template <class T, std::size_t N>
inline math::vector<T, N>& operator*=(math::vector<T, N>& v, T s)
constexpr inline math::vector<T, N>& operator*=(math::vector<T, N>& v, T s)
{
return (v = v * s);
}
template <class T, std::size_t N>
inline math::vector<T, N>& operator/=(math::vector<T, N>& x, const math::vector<T, N>& y)
constexpr inline math::vector<T, N>& operator/=(math::vector<T, N>& x, const math::vector<T, N>& y)
{
return (x = x * y);
}
template <class T, std::size_t N>
inline math::vector<T, N>& operator/=(math::vector<T, N>& v, T s)
constexpr inline math::vector<T, N>& operator/=(math::vector<T, N>& v, T s)
{
return (v = v / s);
}
#endif // ANTKEEPER_MATH_VECTOR_OPERATORS_HPP

+ 77
- 59
src/math/vector-type.hpp View File

@ -20,7 +20,6 @@
#ifndef ANTKEEPER_MATH_VECTOR_TYPE_HPP
#define ANTKEEPER_MATH_VECTOR_TYPE_HPP
#include <array>
#include <cstddef>
namespace math {
@ -34,87 +33,107 @@ namespace math {
template <typename T, std::size_t N>
struct vector
{
typedef T scalar_type;
typedef std::array<T, N> array_type;
scalar_type components[N];
inline constexpr scalar_type& operator[](std::size_t i) noexcept { return components[i]; }
inline constexpr const scalar_type& operator[](std::size_t i) const noexcept { return components[i]; }
inline constexpr operator array_type&() noexcept { return reinterpret_cast<array_type&>(components[0]); }
inline constexpr operator const array_type&() const noexcept { return reinterpret_cast<const array_type&>(components[0]); }
inline constexpr const scalar_type* data() const noexcept { return components; };
inline constexpr scalar_type* data() noexcept { return components; };
typedef T element_type;
element_type elements[N];
inline constexpr element_type& operator[](std::size_t i) noexcept { return elements[i]; }
inline constexpr const element_type& operator[](std::size_t i) const noexcept { return elements[i]; }
inline constexpr const element_type* data() const noexcept { return elements; };
inline constexpr element_type* data() noexcept { return elements; };
inline constexpr std::size_t size() const noexcept { return N; };
};
template <typename T>
struct vector<T, 1>
{
typedef T scalar_type;
typedef std::array<T, 1> array_type;
scalar_type x;
inline constexpr scalar_type& operator[](std::size_t i) noexcept { return *((&x) + i); }
inline constexpr const scalar_type& operator[](std::size_t i) const noexcept { return *((&x) + i); }
inline constexpr operator array_type&() noexcept { return reinterpret_cast<array_type&>(x); }
inline constexpr operator const array_type&() const noexcept { return reinterpret_cast<const array_type&>(x); }
inline constexpr const scalar_type* data() const noexcept { return &x; };
inline constexpr scalar_type* data() noexcept { return &x; };
typedef T element_type;
union
{
element_type elements[1];
struct
{
element_type x;
};
};
inline constexpr element_type& operator[](std::size_t i) noexcept { return elements[i]; }
inline constexpr const element_type& operator[](std::size_t i) const noexcept { return elements[i]; }
inline constexpr const element_type* data() const noexcept { return elements; };
inline constexpr element_type* data() noexcept { return elements; };
inline constexpr std::size_t size() const noexcept { return 1; };
};
template <typename T>
struct vector<T, 2>
{
typedef T scalar_type;
typedef std::array<T, 2> array_type;
scalar_type x;
scalar_type y;
inline constexpr scalar_type& operator[](std::size_t i) noexcept { return *((&x) + i); }
inline constexpr const scalar_type& operator[](std::size_t i) const noexcept { return *((&x) + i); }
inline constexpr operator array_type&() noexcept { return reinterpret_cast<array_type&>(x); }
inline constexpr operator const array_type&() const noexcept { return reinterpret_cast<const array_type&>(x); }
inline constexpr const scalar_type* data() const noexcept { return &x; };
inline constexpr scalar_type* data() noexcept { return &x; };
typedef T element_type;
union
{
element_type elements[2];
struct
{
element_type x;
element_type y;
};
};
inline constexpr element_type& operator[](std::size_t i) noexcept { return elements[i]; }
inline constexpr const element_type& operator[](std::size_t i) const noexcept { return elements[i]; }
inline constexpr const element_type* data() const noexcept { return elements; };
inline constexpr element_type* data() noexcept { return elements; };
inline constexpr std::size_t size() const noexcept { return 2; };
};
template <typename T>
struct vector<T, 3>
{
typedef T scalar_type;
typedef std::array<T, 3> array_type;
scalar_type x;
scalar_type y;
scalar_type z;
inline constexpr scalar_type& operator[](std::size_t i) noexcept { return *((&x) + i); }
inline constexpr const scalar_type& operator[](std::size_t i) const noexcept { return *((&x) + i); }
inline constexpr operator array_type&() noexcept { return reinterpret_cast<array_type&>(x); }
inline constexpr operator const array_type&() const noexcept { return reinterpret_cast<const array_type&>(x); }
inline constexpr const scalar_type* data() const noexcept { return &x; };
inline constexpr scalar_type* data() noexcept { return &x; };
typedef T element_type;
union
{
element_type elements[3];
struct
{
element_type x;
element_type y;
element_type z;
};
};
inline constexpr element_type& operator[](std::size_t i) noexcept { return elements[i]; }
inline constexpr const element_type& operator[](std::size_t i) const noexcept { return elements[i]; }
inline constexpr const element_type* data() const noexcept { return elements; };
inline constexpr element_type* data() noexcept { return elements; };
inline constexpr std::size_t size() const noexcept { return 3; };
};
template <typename T>
struct vector<T, 4>
{
typedef T scalar_type;
typedef std::array<T, 4> array_type;
scalar_type x;
scalar_type y;
scalar_type z;
scalar_type w;
inline constexpr scalar_type& operator[](std::size_t i) noexcept { return *((&x) + i); }
inline constexpr const scalar_type& operator[](std::size_t i) const noexcept { return *((&x) + i); }
inline constexpr operator array_type&() noexcept { return reinterpret_cast<array_type&>(x); }
inline constexpr operator const array_type&() const noexcept { return reinterpret_cast<const array_type&>(x); }
inline constexpr const scalar_type* data() const noexcept { return &x; };
inline constexpr scalar_type* data() noexcept { return &x; };
typedef T element_type;
union
{
element_type elements[4];
struct
{
element_type x;
element_type y;
element_type z;
element_type w;
};
};
inline constexpr element_type& operator[](std::size_t i) noexcept { return elements[i]; }
inline constexpr const element_type& operator[](std::size_t i) const noexcept { return elements[i]; }
inline constexpr const element_type* data() const noexcept { return elements; };
inline constexpr element_type* data() noexcept { return elements; };
inline constexpr std::size_t size() const noexcept { return 4; };
};
@ -133,4 +152,3 @@ using vector4 = vector;
} // namespace math
#endif // ANTKEEPER_MATH_VECTOR_TYPE_HPP

+ 36
- 42
src/physics/gas/atmosphere.hpp View File

@ -32,101 +32,95 @@ namespace gas {
namespace atmosphere {
/**
* Calculates a particle polarizability factor used in computing scattering coefficients.
* Calculates a particle polarizability factor.
*
* @param ior Atmospheric index of refraction.
* @param density Molecular density.
* @return Polarization factor.
* @param density Molecular number density, in mol/m-3.
* @return Polarizability factor.
*
* @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
* @see Elek, Oskar. (2009). Rendering Parametrizable Planetary Atmospheres with Multiple Scattering in Real-Time.
* @see Real-Time Spectral Scattering in Large-Scale Natural Participating Media.
*/
template <class T>
T polarization(T ior, T density)
{
const T ior2m1 = ior * ior - T(1.0);
const T num = T(2) * math::pi<T> * math::pi<T> * ior2m1 * ior2m1;
constexpr T k = T(2) * math::pi<T> * math::pi<T>;
const T ior2m1 = ior * ior - T(1);
const T num = k * ior2m1 * ior2m1;
const T den = T(3) * density * density;
return num / den;
}
/**
* Calculates a Rayleigh scattering coefficient (wavelength-dependent).
* Calculates a wavelength-dependent scattering coefficient.
*
* @param density Molecular number density of the particles, in mol/m-3.
* @param polarization Particle polarizability factor.
* @param wavelength Wavelength of light, in meters.
* @param density Molecular density of Rayleigh particles.
* @param polarization Rayleigh particle polarization factor.
*
* @return Scattering coefficient.
*
* @see atmosphere::polarization
*
* @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
* @see Elek, Oskar. (2009). Rendering Parametrizable Planetary Atmospheres with Multiple Scattering in Real-Time.
* @see Real-Time Spectral Scattering in Large-Scale Natural Participating Media.
*/
template <class T>
T scattering_rayleigh(T wavelength, T density, T polarization)
T scattering(T density, T polarization, T wavelength)
{
const T wavelength2 = wavelength * wavelength;
return math::four_pi<T> * density / (wavelength2 * wavelength2) * polarization;
return math::four_pi<T> * (density / (wavelength2 * wavelength2)) * polarization;
}
/**
* Calculates a Mie scattering coefficient (wavelength-independent).
* Calculates a wavelength-independent scattering coefficient.
*
* @param density Molecular density of Mie particles.
* @param polarization Mie particle polarization factor.
* @param density Molecular number density of the particles, in mol/m-3.
* @param polarization Particle polarizability factor.
*
* @return Mie scattering coefficient.
* @return Scattering coefficient.
*
* @see atmosphere::polarization
*
* @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
* @see Elek, Oskar. (2009). Rendering Parametrizable Planetary Atmospheres with Multiple Scattering in Real-Time.
* @see Real-Time Spectral Scattering in Large-Scale Natural Participating Media.
*/
template <class T>
T scattering_mie(T density, T polarization)
T scattering(T density, T polarization)
{
return math::four_pi<T> * density * polarization;
}
/**
* Calculates a Mie absorption coefficient (wavelength-independent).
* Calculates an absorption coefficient.
*
* @param scattering Mie scattering coefficient.
* @param scattering Scattering coefficient.
* @param albedo Single-scattering albedo.
*
* @return Mie absorption coefficient.
* @return Absorption coefficient.
*
* @see Bruneton, E. and Neyret, F. (2008), Precomputed Atmospheric Scattering. Computer Graphics Forum, 27: 1079-1086. https://doi.org/10.1111/j.1467-8659.2008.01245.x
* @see https://en.wikipedia.org/wiki/Single-scattering_albedo
*/
template <class T>
T absorption_mie(T scattering)
T absorption(T scattering, T albedo)
{
return scattering / T(9);
return scattering * (T(1) / albedo - T(1));
}
/**
* Calculates attenuation due to extinction (absorption + out-scattering).
* Calculates an extinction coefficient.
*
* @param ec Extinction coefficient (absorption coefficient + scattering coefficient).
* @param s Scale factor.
* @return Attenuation factor.
*/
template <class T>
T extinction(T ec, T s)
{
return std::exp(-(ec * s));
}
/**
* Calculates the single-scattering albedo (SSA) given a scattering coefficient and an extinction coefficient.
* @param scattering Scattering coefficient.
* @param albedo Single-scattering albedo.
*
* @return Extinction coefficient.
*
* @param s Scattering coefficient.
* @param e Extinction coefficient.
* @return Single-scattering albedo.
* @see https://en.wikipedia.org/wiki/Single-scattering_albedo
*/
template <class T>
T albedo(T s, T e)
T extinction(T scattering, T albedo)
{
return s / e;
return scattering / albedo;
}
/**

+ 527
- 19
src/physics/gas/ozone.hpp View File

@ -20,51 +20,559 @@
#ifndef ANTKEEPER_PHYSICS_GAS_OZONE_HPP
#define ANTKEEPER_PHYSICS_GAS_OZONE_HPP
#include "math/interpolation.hpp"
namespace physics {
namespace gas {
/// Ozone-related constants and functions.
namespace ozone {
/**
* Cross section of ozone at wavelength 680nm and temperature 293K, in m-2/molecule.
*
* @see https://www.iup.uni-bremen.de/gruppen/molspec/databases/referencespectra/o3spectra2011/index.html
*/
template <class T>
constexpr T cross_section_680nm_293k = T(1.36820899679147e-25);
/**
* Cross section of ozone at wavelength 550nm and temperature 293K, in m-2/molecule.
* Cross sections of ozone from wavelength 280nm to 780nm, in increments of 1nm, at a temperature of 293K, in m-2/molecule.
*
* @see https://www.iup.uni-bremen.de/gruppen/molspec/databases/referencespectra/o3spectra2011/index.html
*/
template <class T>
constexpr T cross_section_550nm_293k = T(3.31405330400124e-25);
constexpr double cross_sections_280nm_780nm_293k[781 - 280] =
{
4.08020162329358e-22,
3.71300005805609e-22,
3.33329613050011e-22,
3.08830771169272e-22,
2.7952452827933e-22,
2.54507006594824e-22,
2.31059906830132e-22,
2.06098663896454e-22,
1.77641837487505e-22,
1.60649162987982e-22,
1.43573256268989e-22,
1.28028940869356e-22,
1.11222715354512e-22,
1.00812840644175e-22,
8.62757275283743e-23,
7.74492225274189e-23,
6.74998572150431e-23,
5.92584261096169e-23,
5.09573191001311e-23,
4.58263122360992e-23,
3.90608822487099e-23,
3.4712884682176e-23,
3.05004947986011e-23,
2.61948471583207e-23,
2.35950204633063e-23,
2.01696279467763e-23,
1.77716671613151e-23,
1.57884103804348e-23,
1.35332466460157e-23,
1.23148992566335e-23,
1.00674476685553e-23,
9.14966132477946e-24,
8.0373280016411e-24,
6.82346538467894e-24,
6.42747947320284e-24,
5.12300259416845e-24,
4.77060350699273e-24,
4.0011431423959e-24,
3.72184265884461e-24,
2.71828160861414e-24,
3.14980819763314e-24,
2.01180905161078e-24,
2.23741500460792e-24,
2.04586872483057e-24,
1.14774957440809e-24,
1.7873766001915e-24,
1.14326155695545e-24,
7.61393733215954e-25,
1.30841854222986e-24,
6.50013011248201e-25,
4.47253301018733e-25,
7.22254319278391e-25,
4.42923420258652e-25,
3.22168537281097e-25,
5.60700006481047e-25,
2.51991724359347e-25,
1.64975530971913e-25,
2.69863618345909e-25,
2.2962216595934e-25,
1.2768604186372e-25,
1.6428080690911e-25,
1.15252741016694e-25,
6.88123014503947e-26,
9.01478526179051e-26,
1.38671804168295e-25,
7.28648586727799e-26,
6.3468766437083e-26,
4.1705109317344e-26,
3.22298756116943e-26,
2.52476541455397e-26,
2.96595291121762e-26,
2.10981495904366e-26,
3.0696184107227e-26,
2.38627682184272e-26,
1.35645160962203e-26,
1.14737436955784e-26,
1.00293019429341e-26,
1.42699666872085e-26,
1.03892014298915e-26,
7.46029500400895e-27,
7.86729405487508e-27,
6.49493671023213e-27,
3.90586420068501e-27,
3.3969327080211e-27,
2.69156849765275e-27,
4.89998022220222e-27,
4.18363151355665e-27,
2.41505691668684e-27,
1.52926807176976e-27,
1.74010836686791e-27,
1.43997701486263e-27,
1.61611242687813e-27,
1.09444991940235e-27,
8.68337506495441e-28,
1.28660044051837e-27,
1.07534571825705e-27,
7.59223090396554e-28,
6.75850905941831e-28,
6.05594086115429e-28,
7.40387066310015e-28,
6.04999720618854e-28,
5.17923583652293e-28,
4.0858846895433e-28,
6.47448369216067e-28,
5.29992493931534e-28,
5.63128808710364e-28,
4.17695119955099e-28,
5.15330384762416e-28,
5.25185850011986e-28,
6.17618171380047e-28,
6.37119303086457e-28,
6.8496876006444e-28,
5.9229625229341e-28,
5.99998795876176e-28,
7.06136396740756e-28,
9.93040926727483e-28,
1.03668944015898e-27,
9.60158757124091e-28,
9.00247643555494e-28,
1.01801330597124e-27,
1.0893103182854e-27,
1.30096252080506e-27,
1.42018105948242e-27,
1.53477820553937e-27,
1.60452920542724e-27,
1.45613806382105e-27,
1.63671034304492e-27,
1.88680147053984e-27,
2.26659932677371e-27,
2.57113808884621e-27,
2.73584069155576e-27,
2.84524835939992e-27,
2.65294565386989e-27,
2.52007318042733e-27,
2.56347774832346e-27,
2.73272493525925e-27,
3.21972108535573e-27,
3.64879308272645e-27,
3.86875166703077e-27,
3.77657059174972e-27,
3.67917967079418e-27,
3.84603321414093e-27,
4.47110813921024e-27,
5.19879478264214e-27,
6.13707395634462e-27,
6.88229484256763e-27,
7.11935416561536e-27,
7.15812015493665e-27,
6.67142397990209e-27,
6.35218112458219e-27,
6.34510826220203e-27,
6.90321809802859e-27,
7.82871587803871e-27,
8.52938477234511e-27,
8.74335964163491e-27,
8.6718822639457e-27,
8.59495406258221e-27,
8.90719500501358e-27,
9.90176156668504e-27,
1.14857395824068e-26,
1.36017282525383e-26,
1.53232356175871e-26,
1.75024000506424e-26,
1.8179765858316e-26,
1.80631911188605e-26,
1.70102948254892e-26,
1.56536231218255e-26,
1.51141962474665e-26,
1.57847025841346e-26,
1.72161452840856e-26,
1.90909798194127e-26,
1.96774621921165e-26,
1.99812678813396e-26,
1.96900102296014e-26,
1.95126617395258e-26,
2.06408915381352e-26,
2.28866836725858e-26,
2.57662977048169e-26,
2.96637551360212e-26,
3.34197426701549e-26,
3.73735792971477e-26,
4.03453827718193e-26,
4.1291323324037e-26,
4.07643587970195e-26,
3.84067732691303e-26,
3.6271000065179e-26,
3.50502931147362e-26,
3.48851626868318e-26,
3.73778737646723e-26,
3.97091132121154e-26,
4.21773978585713e-26,
4.21620738550362e-26,
4.22087900183437e-26,
4.27973060694892e-26,
4.36010682588909e-26,
4.60584575680881e-26,
4.91428506793045e-26,
5.4918846417406e-26,
6.10573296817762e-26,
6.83025566941932e-26,
7.51469261186479e-26,
8.08197962688924e-26,
8.44082645474868e-26,
8.4843465766735e-26,
8.4126775729461e-26,
8.14411830190209e-26,
7.83636723569755e-26,
7.60974711104334e-26,
7.57877917471603e-26,
7.77887132347866e-26,
8.07522339055262e-26,
8.32310316258138e-26,
8.59015818152486e-26,
8.67834106505007e-26,
8.72244226406716e-26,
8.84734167611993e-26,
9.0711580597939e-26,
9.51778147590566e-26,
1.01490385328969e-25,
1.09448341447976e-25,
1.18257044868557e-25,
1.28105938778111e-25,
1.37732704252934e-25,
1.47491161151436e-25,
1.55090701035304e-25,
1.60575752538508e-25,
1.62886093543744e-25,
1.62802718439262e-25,
1.60288510229631e-25,
1.57216917046401e-25,
1.54475957021763e-25,
1.534341089264e-25,
1.5409967492982e-25,
1.56495784865383e-25,
1.60012763627009e-25,
1.63952588489707e-25,
1.67232066912218e-25,
1.70167894480834e-25,
1.7335194060265e-25,
1.7602731663686e-25,
1.79953556347172e-25,
1.84084607422109e-25,
1.89999243847493e-25,
1.97490644310087e-25,
2.05279021301286e-25,
2.14427839223598e-25,
2.24098369182092e-25,
2.34362490982003e-25,
2.44138366650567e-25,
2.53826212075759e-25,
2.62577562731292e-25,
2.70621837640467e-25,
2.76622780914432e-25,
2.80661519633223e-25,
2.82737499370866e-25,
2.82968166962191e-25,
2.82659484597549e-25,
2.81717325255129e-25,
2.82197485088881e-25,
2.84600833360439e-25,
2.88048754046166e-25,
2.92686210579676e-25,
2.98551267943544e-25,
3.04464034622896e-25,
3.09724266051229e-25,
3.14551726028915e-25,
3.18670379817661e-25,
3.22330249380314e-25,
3.25463784914917e-25,
3.2854797958699e-25,
3.31405330400124e-25,
3.34398013095565e-25,
3.38005272562664e-25,
3.41218557614901e-25,
3.45555599852459e-25,
3.5043277615423e-25,
3.55984911371566e-25,
3.6264721972979e-25,
3.70647322984569e-25,
3.79188179306458e-25,
3.88981479760571e-25,
3.98973596432023e-25,
4.08527421216539e-25,
4.17464990288797e-25,
4.25462181228461e-25,
4.32317712812093e-25,
4.38401384845366e-25,
4.44216978945654e-25,
4.49508440820886e-25,
4.5516564927479e-25,
4.60931329475278e-25,
4.66173637960526e-25,
4.70665064920011e-25,
4.74051362440113e-25,
4.75812011867871e-25,
4.7570031038151e-25,
4.73747927545327e-25,
4.71027119364443e-25,
4.66860282624977e-25,
4.6288533265784e-25,
4.57997871538082e-25,
4.53548773884213e-25,
4.49607272653461e-25,
4.4568818824566e-25,
4.42881930827398e-25,
4.40157474149992e-25,
4.38677564524713e-25,
4.37182142194489e-25,
4.37104565551326e-25,
4.37919711899623e-25,
4.39683352146027e-25,
4.42484514000691e-25,
4.47212673326828e-25,
4.53157968174371e-25,
4.60815452736499e-25,
4.69376508835705e-25,
4.78054316070552e-25,
4.87030272266768e-25,
4.95220907227656e-25,
5.02898332230558e-25,
5.09027352924287e-25,
5.13210890748271e-25,
5.15374454317407e-25,
5.15075653533686e-25,
5.13171378996911e-25,
5.09303097809138e-25,
5.03697164998998e-25,
4.97218676726656e-25,
4.89461758141549e-25,
4.80937594526597e-25,
4.72371968798565e-25,
4.63859449875443e-25,
4.55132403268817e-25,
4.46787830232533e-25,
4.38816245012175e-25,
4.31406743009557e-25,
4.24483372714822e-25,
4.17474755876221e-25,
4.11305082072427e-25,
4.05554427636835e-25,
4.0030863998631e-25,
3.95393149188544e-25,
3.90576318741963e-25,
3.86085282288514e-25,
3.81425489414328e-25,
3.76584427585746e-25,
3.71837025816073e-25,
3.66911165810168e-25,
3.61941817240908e-25,
3.56533744970388e-25,
3.51159798289664e-25,
3.46140984744989e-25,
3.41173597486151e-25,
3.36073006491665e-25,
3.30753716054224e-25,
3.25252799457143e-25,
3.19530424634748e-25,
3.13651908668849e-25,
3.07841534489121e-25,
3.01880275032991e-25,
2.95965464815758e-25,
2.90194743931008e-25,
2.84696394478385e-25,
2.79488978476361e-25,
2.74800171431914e-25,
2.70053589638645e-25,
2.65588371839819e-25,
2.6091795190684e-25,
2.56708069403319e-25,
2.52375403058723e-25,
2.48382556862202e-25,
2.44458617524673e-25,
2.40594587498642e-25,
2.36627105488787e-25,
2.32528309566254e-25,
2.28436716651676e-25,
2.24424313328781e-25,
2.20515093141858e-25,
2.16647251017334e-25,
2.12914125517962e-25,
2.09073684368918e-25,
2.05335637747553e-25,
2.01912040845123e-25,
1.98301051757051e-25,
1.94465669006103e-25,
1.9057000954812e-25,
1.86388414183128e-25,
1.82241187234978e-25,
1.78160123951627e-25,
1.74179167768809e-25,
1.70080577609513e-25,
1.6615348247565e-25,
1.62305192083274e-25,
1.58738563014106e-25,
1.55171430112041e-25,
1.51949383874537e-25,
1.48607225456117e-25,
1.45360366466218e-25,
1.42252183610792e-25,
1.39462753606039e-25,
1.36820899679147e-25,
1.34377836247288e-25,
1.3233906891166e-25,
1.30492894377563e-25,
1.28681831161393e-25,
1.2663174075999e-25,
1.2420229295933e-25,
1.21412305909061e-25,
1.18502869999655e-25,
1.15382448376731e-25,
1.12540171803974e-25,
1.09558453899584e-25,
1.06672010609186e-25,
1.03896476876362e-25,
1.01172047316729e-25,
9.84602582159865e-26,
9.58059205575365e-26,
9.33099533469407e-26,
9.08936155224937e-26,
8.8491955813636e-26,
8.64349280941688e-26,
8.44550335501804e-26,
8.25653238461191e-26,
8.08238949115334e-26,
7.94009406468206e-26,
7.80797137891831e-26,
7.67364989571709e-26,
7.54965718671858e-26,
7.43779079827743e-26,
7.31964666857758e-26,
7.2232944312979e-26,
7.12771524608971e-26,
7.0510155861502e-26,
6.99911412369698e-26,
6.96383131319201e-26,
6.92914966812787e-26,
6.85928437919081e-26,
6.74428511228458e-26,
6.59224480420957e-26,
6.38840433633278e-26,
6.15855599572905e-26,
5.95772659493798e-26,
5.76494205198861e-26,
5.60397496087846e-26,
5.46017309852595e-26,
5.32285644696103e-26,
5.22365816180628e-26,
5.07899578121548e-26,
4.93592723237266e-26,
4.79667132541204e-26,
4.68132550170927e-26,
4.56404612656666e-26,
4.48276475068268e-26,
4.40173864033052e-26,
4.35417448301629e-26,
4.30681941574933e-26,
4.28871372503407e-26,
4.24230311436515e-26,
4.22301315090103e-26,
4.19685390394596e-26,
4.18917236558952e-26,
4.17687017488352e-26,
4.22019512128238e-26,
4.2557462015274e-26,
4.31172890769302e-26,
4.36741466155527e-26,
4.41740590419353e-26,
4.44874945269751e-26,
4.42029497925774e-26,
4.34317624813875e-26,
4.21853858585038e-26,
4.01907542789597e-26,
3.80281792816081e-26,
3.60902775684479e-26,
3.41921953398109e-26,
3.25291539681547e-26,
3.10743399295997e-26,
2.99157340432027e-26,
2.89660087626517e-26,
2.82185391364051e-26,
2.76872520775773e-26,
2.72983807771732e-26,
2.65963957090044e-26,
2.62737083974039e-26,
2.56625477748644e-26,
2.53980768456023e-26,
2.49759827680602e-26,
2.47017705195044e-26,
2.47697548770545e-26,
2.46973660414457e-26,
2.47714280793403e-26,
2.50190654239581e-26,
2.56196471101148e-26,
2.64525680175745e-26,
2.72275203692747e-26,
2.826728922873e-26,
2.94507453632992e-26,
3.05247618840877e-26,
3.1005889405393e-26,
3.1508637563266e-26,
3.13148927506362e-26
};
/**
* Cross section of ozone at wavelength 550nm and temperature 293K, in m-2/molecule.
* Returns the cross section of ozone at temperature 293k and a given wavelength in the visible spectrum.
*
* @see https://www.iup.uni-bremen.de/gruppen/molspec/databases/referencespectra/o3spectra2011/index.html
* @param wavelength Wavelength, in nanometers, on `[280, 780)`.
* @return Ozone cross section at temperature 293k and the given wavelength, in m-2/molecule.
*/
template <class T>
constexpr T cross_section_440nm_293k = T(1.36017282525383e-26);
constexpr T cross_section_293k(T wavelength)
{
int i = static_cast<int>(wavelength);
int j = static_cast<int>(wavelength + T(1));
if (i < 280 || j > 780)
return T(0);
const T x = static_cast<T>(cross_sections_280nm_780nm_293k[i - 280]);
const T y = static_cast<T>(cross_sections_280nm_780nm_293k[j - 280]);
return math::lerp<T>(x, y, wavelength - static_cast<T>(i));
}
/**
* Calculates an ozone absorption coefficient (wavelength-dependent).
*
* @param cross_section Ozone cross section of a wavelength, in m-2/molecule.
* @param n Molecular number density of standard air, in molecules/m-3.
* @param c Concentration of ozone in the atmosphere, unitless.
* @param density Molecular number density of ozone, in mol/m-3.
*
* @return Ozone absorption coefficient.
*
* @see https://skyrenderer.blogspot.com/2012/10/ozone-absorption.html
*/
template <class T>
T absorption(T cross_section, T n, T c)
T absorption(T cross_section, T density)
{
return cross_section * n * c;
return cross_section * density;
}
} // namespace ozone

+ 3
- 3
src/physics/light/exposure.hpp View File

@ -93,16 +93,16 @@ T to_luminance(T ev, T s, T k)
}
/**
* Exposure value to luminance.
* Exposure value to illuminance.
*
* @param ev Exposure value.
* @param s ISO arithmetic speed. A value of `100` corresponds to ISO 100.
* @param k Incident-light meter calibration constant. A common value is `250`.
* @param c Incident-light meter calibration constant. A common value is `250`.
*
* @return Illuminance, in lux.
*/
template <class T>
T to_luminance(T ev, T s, T c)
T to_illuminance(T ev, T s, T c)
{
return (c * std::exp2(ev)) / s;
}

+ 8
- 0
src/physics/time/jd.hpp View File

@ -26,6 +26,14 @@ namespace time {
/// Julian day (JD).
namespace jd {
/// Number of Julian days per Julian century.
template <class T>
constexpr T days_per_century = T{36525};
/// Number of Julian centuries per Julian day.
template <class T>
constexpr T centuries_per_day = T{1} / T{36525};
/**
* Converts JD to UT1.
*

+ 10
- 1
src/render/context.hpp View File

@ -53,9 +53,18 @@ struct context
/// Camera culling volume.
const geom::bounding_volume<float>* camera_culling_volume;
/// Near clipping plane of the camera
/// Near clipping plane of the camera.
geom::plane<float> clip_near;
/// Camera view matrix.
float4x4 view;
/// Camera projection matrix.
float4x4 projection;
/// Camera view projection matrix.
float4x4 view_projection;
/// Camera exposure normalization factor.
float exposure;

+ 3
- 3
src/render/passes/ground-pass.cpp View File

@ -86,10 +86,10 @@ void ground_pass::render(const render::context& ctx, render::queue& queue) const
float clip_far = camera.get_clip_far_tween().interpolate(ctx.alpha);
float3 model_scale = float3{1.0f, 1.0f, 1.0f} * (clip_near + clip_far) * 0.5f;
float4x4 model = math::scale(math::matrix4<float>::identity, model_scale);
float4x4 view = math::resize<4, 4>(math::resize<3, 3>(camera.get_view_tween().interpolate(ctx.alpha)));
float4x4 view = math::resize<4, 4>(math::resize<3, 3>(ctx.view));
float4x4 model_view = view * model;
float4x4 projection = camera.get_projection_tween().interpolate(ctx.alpha);
float4x4 view_projection = camera.get_view_projection_tween().interpolate(ctx.alpha);
const float4x4& projection = ctx.projection;
const float4x4& view_projection = ctx.view_projection;
float4x4 model_view_projection = projection * model_view;

+ 3
- 3
src/render/passes/material-pass.cpp View File

@ -120,9 +120,9 @@ void material_pass::render(const render::context& ctx, render::queue& queue) con
float2 resolution = {static_cast<float>(std::get<0>(viewport)), static_cast<float>(std::get<1>(viewport))};
const float3& camera_position = ctx.camera_transform.translation;
float4x4 view = ctx.camera->get_view_tween().interpolate(ctx.alpha);
float4x4 projection = ctx.camera->get_projection_tween().interpolate(ctx.alpha);
float4x4 view_projection = projection * view;
const float4x4& view = ctx.view;
const float4x4& projection = ctx.projection;
const float4x4& view_projection = ctx.view_projection;
float4x4 model_view_projection;
float4x4 model;
float4x4 model_view;

+ 154
- 129
src/render/passes/sky-pass.cpp View File

@ -46,6 +46,7 @@
#include <cmath>
#include <stdexcept>
#include <glad/glad.h>
#include <iostream>
namespace render {
@ -64,10 +65,6 @@ sky_pass::sky_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffe
stars_model_vao(nullptr),
star_material(nullptr),
star_shader_program(nullptr),
clouds_model(nullptr),
clouds_model_vao(nullptr),
cloud_material(nullptr),
cloud_shader_program(nullptr),
observer_position_tween({0, 0, 0}, math::lerp<float3, float>),
sun_position_tween(float3{1.0f, 0.0f, 0.0f}, math::lerp<float3, float>),
sun_luminance_tween(float3{0.0f, 0.0f, 0.0f}, math::lerp<float3, float>),
@ -81,6 +78,8 @@ sky_pass::sky_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffe
moon_sunlight_illuminance_tween(float3{0, 0, 0}, math::lerp<float3, float>),
moon_planetlight_direction_tween(float3{0, 0, 0}, math::lerp<float3, float>),
moon_planetlight_illuminance_tween(float3{0, 0, 0}, math::lerp<float3, float>),
moon_illuminance_tween(float3{0.0f, 0.0f, 0.0f}, math::lerp<float3, float>),
render_transmittance_lut(false),
magnification(1.0f)
{
// Build quad VBO and VAO
@ -107,15 +106,13 @@ sky_pass::sky_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffe
quad_vao->bind(render::vertex_attribute::position, quad_position_attribute);
// Create transmittance LUT texture and framebuffer (32F color, no depth)
int transmittance_width = 256;
int transmittance_height = 64;
transmittance_inverse_lut_resolution = {1.0f / static_cast<float>(transmittance_width), 1.0f / static_cast<float>(transmittance_height)};
transmittance_texture = new gl::texture_2d(transmittance_width, transmittance_height, gl::pixel_type::float_32, gl::pixel_format::rgb);
transmittance_texture->set_wrapping(gl::texture_wrapping::extend, gl::texture_wrapping::extend);
transmittance_texture->set_filters(gl::texture_min_filter::linear, gl::texture_mag_filter::linear);
transmittance_texture->set_max_anisotropy(0.0f);
transmittance_framebuffer = new gl::framebuffer(transmittance_width, transmittance_height);
transmittance_framebuffer->attach(gl::framebuffer_attachment_type::color, transmittance_texture);
transmittance_lut_texture = new gl::texture_2d(256, 64, gl::pixel_type::float_32, gl::pixel_format::rgb);
transmittance_lut_texture->set_wrapping(gl::texture_wrapping::extend, gl::texture_wrapping::extend);
transmittance_lut_texture->set_filters(gl::texture_min_filter::linear, gl::texture_mag_filter::linear);
transmittance_lut_texture->set_max_anisotropy(0.0f);
transmittance_lut_framebuffer = new gl::framebuffer({transmittance_lut_texture->get_width(), transmittance_lut_texture->get_height()});
transmittance_lut_framebuffer->attach(gl::framebuffer_attachment_type::color, transmittance_lut_texture);
transmittance_lut_resolution = {static_cast<float>(transmittance_lut_texture->get_width()), static_cast<float>(transmittance_lut_texture->get_height())};
// Load transmittance LUT shader
transmittance_shader_program = resource_manager->load<gl::shader_program>("transmittance-lut.glsl");
@ -124,13 +121,41 @@ sky_pass::sky_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffe
transmittance_mie_parameters_input = transmittance_shader_program->get_input("mie_parameters");
transmittance_ozone_distribution_input = transmittance_shader_program->get_input("ozone_distribution");
transmittance_ozone_absorption_input = transmittance_shader_program->get_input("ozone_absorption");
transmittance_inverse_lut_resolution_input = transmittance_shader_program->get_input("inverse_lut_resolution");
transmittance_resolution_input = transmittance_shader_program->get_input("resolution");
// Create sky LUT texture and framebuffer (32F color, no depth)
int sky_lut_width = 200;
int sky_lut_height = 100;
sky_lut_resolution = {static_cast<float>(sky_lut_width), static_cast<float>(sky_lut_height)};
sky_lut_texture = new gl::texture_2d(sky_lut_width, sky_lut_height, gl::pixel_type::float_32, gl::pixel_format::rgb);
sky_lut_texture->set_wrapping(gl::texture_wrapping::extend, gl::texture_wrapping::extend);
sky_lut_texture->set_filters(gl::texture_min_filter::linear, gl::texture_mag_filter::linear);
sky_lut_texture->set_max_anisotropy(0.0f);
sky_lut_framebuffer = new gl::framebuffer(sky_lut_width, sky_lut_height);
sky_lut_framebuffer->attach(gl::framebuffer_attachment_type::color, sky_lut_texture);
// Load sky LUT shader
sky_lut_shader_program = resource_manager->load<gl::shader_program>("sky-illuminance-lut.glsl");
sky_lut_light_direction_input = sky_lut_shader_program->get_input("light_direction");
sky_lut_light_illuminance_input = sky_lut_shader_program->get_input("light_illuminance");
sky_lut_atmosphere_radii_input = sky_lut_shader_program->get_input("atmosphere_radii");
sky_lut_observer_position_input = sky_lut_shader_program->get_input("observer_position");
sky_lut_rayleigh_parameters_input = sky_lut_shader_program->get_input("rayleigh_parameters");
sky_lut_mie_parameters_input = sky_lut_shader_program->get_input("mie_parameters");
sky_lut_ozone_distribution_input = sky_lut_shader_program->get_input("ozone_distribution");
sky_lut_ozone_absorption_input = sky_lut_shader_program->get_input("ozone_absorption");
sky_lut_airglow_illuminance_input = sky_lut_shader_program->get_input("airglow_illuminance");
sky_lut_resolution_input = sky_lut_shader_program->get_input("resolution");
sky_lut_transmittance_lut_input = sky_lut_shader_program->get_input("transmittance_lut");
sky_lut_transmittance_lut_resolution_input = sky_lut_shader_program->get_input("transmittance_lut_resolution");
}
sky_pass::~sky_pass()
{
delete transmittance_framebuffer;
delete transmittance_texture;
delete sky_lut_framebuffer;
delete sky_lut_texture;
delete transmittance_lut_framebuffer;
delete transmittance_lut_texture;
delete quad_vao;
delete quad_vbo;
}
@ -143,33 +168,35 @@ void sky_pass::render(const render::context& ctx, render::queue& queue) const
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
// Render transmittance LUT
auto transmittance_viewport = transmittance_framebuffer->get_dimensions();
rasterizer->set_viewport(0, 0, std::get<0>(transmittance_viewport), std::get<1>(transmittance_viewport));
rasterizer->use_framebuffer(*transmittance_framebuffer);
rasterizer->use_program(*transmittance_shader_program);
transmittance_atmosphere_radii_input->upload(atmosphere_radii);
transmittance_rayleigh_parameters_input->upload(rayleigh_parameters);
transmittance_mie_parameters_input->upload(mie_parameters);
transmittance_ozone_distribution_input->upload(ozone_distribution);
transmittance_ozone_absorption_input->upload(ozone_absorption);
if (transmittance_inverse_lut_resolution_input)
transmittance_inverse_lut_resolution_input->upload(transmittance_inverse_lut_resolution);
rasterizer->draw_arrays(*quad_vao, gl::drawing_mode::triangles, 0, 6);
rasterizer->use_framebuffer(*framebuffer);
auto viewport = framebuffer->get_dimensions();
rasterizer->set_viewport(0, 0, std::get<0>(viewport), std::get<1>(viewport));
float2 resolution = {static_cast<float>(std::get<0>(viewport)), static_cast<float>(std::get<1>(viewport))};
// Render transmittance LUT if transmittance parameters have been altered.
if (render_transmittance_lut)
{
// Render transmittance LUT
rasterizer->set_viewport(0, 0, transmittance_lut_texture->get_width(), transmittance_lut_texture->get_height());
rasterizer->use_framebuffer(*transmittance_lut_framebuffer);
rasterizer->use_program(*transmittance_shader_program);
transmittance_atmosphere_radii_input->upload(atmosphere_radii);
transmittance_rayleigh_parameters_input->upload(rayleigh_parameters);
transmittance_mie_parameters_input->upload(mie_parameters);
transmittance_ozone_distribution_input->upload(ozone_distribution);
transmittance_ozone_absorption_input->upload(ozone_absorption);
if (transmittance_resolution_input)
transmittance_resolution_input->upload(transmittance_lut_resolution);
rasterizer->draw_arrays(*quad_vao, gl::drawing_mode::triangles, 0, 6);
// Don't render transmittance LUT next frame unless parameters have changed.
render_transmittance_lut = false;
}
// Construct matrices
const scene::camera& camera = *ctx.camera;
float clip_near = camera.get_clip_near_tween().interpolate(ctx.alpha);
float clip_far = camera.get_clip_far_tween().interpolate(ctx.alpha);
float3 model_scale = float3{1.0f, 1.0f, 1.0f} * (clip_near + clip_far) * 0.5f;
float4x4 model = math::scale(math::matrix4<float>::identity, model_scale);
float4x4 view = math::resize<4, 4>(math::resize<3, 3>(camera.get_view_tween().interpolate(ctx.alpha)));
float4x4 view = math::resize<4, 4>(math::resize<3, 3>(ctx.view));
float4x4 model_view = view * model;
float4x4 projection = camera.get_projection_tween().interpolate(ctx.alpha);
const float4x4& projection = ctx.projection;
float4x4 view_projection = projection * view;
float4x4 model_view_projection = projection * model_view;
@ -191,6 +218,47 @@ void sky_pass::render(const render::context& ctx, render::queue& queue) const
float3 sun_luminance = sun_luminance_tween.interpolate(ctx.alpha) * ctx.exposure;
float3 sun_illuminance = sun_illuminance_tween.interpolate(ctx.alpha) * ctx.exposure;
float3 moon_position = moon_position_tween.interpolate(ctx.alpha);
float3 moon_direction = math::normalize(moon_position);
float3 moon_illuminance = moon_illuminance_tween.interpolate(ctx.alpha) * ctx.exposure;
float moon_angular_radius = moon_angular_radius_tween.interpolate(ctx.alpha) * magnification;
float sun_y = color::aces::ap1<float>.luminance(sun_transmitted_illuminance);
float moon_y = color::aces::ap1<float>.luminance(moon_transmitted_illuminance);
float3 dominant_light_direction = (sun_y > moon_y) ? sun_direction : moon_direction;
float3 dominant_light_illuminance = (sun_y > moon_y) ? sun_illuminance : moon_illuminance;
if (moon_y > sun_y)
sun_luminance *= 0.0f;
// Render sky illuminance LUT
auto sky_lut_viewport = sky_lut_framebuffer->get_dimensions();
rasterizer->set_viewport(0, 0, std::get<0>(sky_lut_viewport), std::get<1>(sky_lut_viewport));
rasterizer->use_framebuffer(*sky_lut_framebuffer);
rasterizer->use_program(*sky_lut_shader_program);
sky_lut_light_direction_input->upload(dominant_light_direction);
sky_lut_light_illuminance_input->upload(dominant_light_illuminance);
sky_lut_atmosphere_radii_input->upload(atmosphere_radii);
sky_lut_observer_position_input->upload(observer_position);
sky_lut_rayleigh_parameters_input->upload(rayleigh_parameters);
sky_lut_mie_parameters_input->upload(mie_parameters);
sky_lut_ozone_distribution_input->upload(ozone_distribution);
sky_lut_ozone_absorption_input->upload(ozone_absorption);
sky_lut_airglow_illuminance_input->upload(airglow_illuminance * ctx.exposure);
if (sky_lut_resolution_input)
sky_lut_resolution_input->upload(sky_lut_resolution);
sky_lut_transmittance_lut_input->upload(transmittance_lut_texture);
if (sky_lut_transmittance_lut_resolution_input)
sky_lut_transmittance_lut_resolution_input->upload(transmittance_lut_resolution);
rasterizer->draw_arrays(*quad_vao, gl::drawing_mode::triangles, 0, 6);
rasterizer->use_framebuffer(*framebuffer);
auto viewport = framebuffer->get_dimensions();
rasterizer->set_viewport(0, 0, std::get<0>(viewport), std::get<1>(viewport));
float2 resolution = {static_cast<float>(std::get<0>(viewport)), static_cast<float>(std::get<1>(viewport))};
// Draw atmosphere
if (sky_model)
{
@ -203,61 +271,26 @@ void sky_pass::render(const render::context& ctx, render::queue& queue) const
mouse_input->upload(mouse_position);
if (resolution_input)
resolution_input->upload(resolution);
if (time_input)
time_input->upload(ctx.t);
if (exposure_input)
exposure_input->upload(ctx.exposure);
if (sun_direction_input)
sun_direction_input->upload(sun_direction);
if (light_direction_input)
light_direction_input->upload(dominant_light_direction);
if (sun_luminance_input)
sun_luminance_input->upload(sun_luminance);
if (sun_illuminance_input)
sun_illuminance_input->upload(sun_illuminance);
if (sun_angular_radius_input)
sun_angular_radius_input->upload(sun_angular_radius * magnification);
if (atmosphere_radii_input)
atmosphere_radii_input->upload(atmosphere_radii);
if (observer_position_input)
observer_position_input->upload(observer_position);
if (rayleigh_parameters_input)
rayleigh_parameters_input->upload(rayleigh_parameters);
if (mie_parameters_input)
mie_parameters_input->upload(mie_parameters);
if (ozone_distribution_input)
ozone_distribution_input->upload(ozone_distribution);
if (ozone_absorption_input)
ozone_absorption_input->upload(ozone_absorption);
if (transmittance_lut_input)
transmittance_lut_input->upload(transmittance_texture);
if (inverse_transmittance_lut_resolution_input)
inverse_transmittance_lut_resolution_input->upload(transmittance_inverse_lut_resolution);
if (sky_illuminance_lut_input)
sky_illuminance_lut_input->upload(sky_lut_texture);
if (sky_illuminance_lut_resolution_input)
sky_illuminance_lut_resolution_input->upload(sky_lut_resolution);
sky_material->upload(ctx.alpha);
rasterizer->draw_arrays(*sky_model_vao, sky_model_drawing_mode, sky_model_start_index, sky_model_index_count);
}
// Draw clouds
if (clouds_model)
{
rasterizer->use_program(*cloud_shader_program);
if (cloud_model_view_projection_input)
cloud_model_view_projection_input->upload(model_view_projection);
if (cloud_sun_direction_input)
cloud_sun_direction_input->upload(sun_direction);
if (cloud_sun_illuminance_input)
cloud_sun_illuminance_input->upload(sun_illuminance);
if (cloud_camera_position_input)
cloud_camera_position_input->upload(ctx.camera_transform.translation);
if (cloud_camera_exposure_input)
cloud_camera_exposure_input->upload(ctx.exposure);
cloud_material->upload(ctx.alpha);
rasterizer->draw_arrays(*clouds_model_vao, clouds_model_drawing_mode, clouds_model_start_index, clouds_model_index_count);
}
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
//glBlendFunc(GL_ONE, GL_ONE);
@ -288,8 +321,6 @@ void sky_pass::render(const render::context& ctx, render::queue& queue) const
}
// Draw moon model
float3 moon_position = moon_position_tween.interpolate(ctx.alpha);
float moon_angular_radius = moon_angular_radius_tween.interpolate(ctx.alpha) * magnification;
//if (moon_position.y >= -moon_angular_radius)
{
float moon_distance = (clip_near + clip_far) * 0.5f;
@ -352,20 +383,13 @@ void sky_pass::set_sky_model(const model* model)
model_view_projection_input = sky_shader_program->get_input("model_view_projection");
mouse_input = sky_shader_program->get_input("mouse");
resolution_input = sky_shader_program->get_input("resolution");
time_input = sky_shader_program->get_input("time");
exposure_input = sky_shader_program->get_input("camera.exposure");
sun_direction_input = sky_shader_program->get_input("sun_direction");
light_direction_input = sky_shader_program->get_input("light_direction");
sun_luminance_input = sky_shader_program->get_input("sun_luminance");
sun_illuminance_input = sky_shader_program->get_input("sun_illuminance");
sun_angular_radius_input = sky_shader_program->get_input("sun_angular_radius");
atmosphere_radii_input = sky_shader_program->get_input("atmosphere_radii");
observer_position_input = sky_shader_program->get_input("observer_position");
rayleigh_parameters_input = sky_shader_program->get_input("rayleigh_parameters");
mie_parameters_input = sky_shader_program->get_input("mie_parameters");
ozone_distribution_input = sky_shader_program->get_input("ozone_distribution");
ozone_absorption_input = sky_shader_program->get_input("ozone_absorption");
transmittance_lut_input = sky_shader_program->get_input("transmittance_lut");
inverse_transmittance_lut_resolution_input = sky_shader_program->get_input("inverse_transmittance_lut_resolution");
sky_illuminance_lut_input = sky_shader_program->get_input("sky_illuminance_lut");
sky_illuminance_lut_resolution_input = sky_shader_program->get_input("sky_illuminance_lut_resolution");
}
}
}
@ -451,43 +475,6 @@ void sky_pass::set_stars_model(const model* model)
}
}
void sky_pass::set_clouds_model(const model* model)
{
clouds_model = model;
if (clouds_model)
{
clouds_model_vao = model->get_vertex_array();
const std::vector<model_group*>& groups = *model->get_groups();
for (model_group* group: groups)
{
cloud_material = group->get_material();
clouds_model_drawing_mode = group->get_drawing_mode();
clouds_model_start_index = group->get_start_index();
clouds_model_index_count = group->get_index_count();
}
if (cloud_material)
{
cloud_shader_program = cloud_material->get_shader_program();
if (cloud_shader_program)
{
cloud_model_view_projection_input = cloud_shader_program->get_input("model_view_projection");
cloud_sun_direction_input = cloud_shader_program->get_input("sun_direction");
cloud_sun_illuminance_input = cloud_shader_program->get_input("sun_illuminance");
cloud_camera_position_input = cloud_shader_program->get_input("camera.position");
cloud_camera_exposure_input = cloud_shader_program->get_input("camera.exposure");
}
}
}
else
{
clouds_model = nullptr;
}
}
void sky_pass::update_tweens()
{
observer_position_tween.update();
@ -504,6 +491,7 @@ void sky_pass::update_tweens()
moon_sunlight_illuminance_tween.update();
moon_planetlight_direction_tween.update();
moon_planetlight_illuminance_tween.update();
moon_illuminance_tween.update();
}
void sky_pass::set_magnification(float magnification)
@ -522,9 +510,10 @@ void sky_pass::set_sun_position(const float3& position)
sun_position_tween[1] = position;
}
void sky_pass::set_sun_illuminance(const float3& illuminance)
void sky_pass::set_sun_illuminance(const float3& illuminance, const float3& transmitted_illuminance)
{
sun_illuminance_tween[1] = illuminance;
sun_transmitted_illuminance = transmitted_illuminance;
}
void sky_pass::set_sun_luminance(const float3& luminance)
@ -543,6 +532,9 @@ void sky_pass::set_planet_radius(float radius)
atmosphere_radii.y = atmosphere_radii.x + atmosphere_upper_limit;
atmosphere_radii.z = atmosphere_radii.y * atmosphere_radii.y;
observer_position_tween[1] = {0.0f, atmosphere_radii.x + observer_elevation, 0.0f};
// Trigger transmittance LUT render
render_transmittance_lut = true;
}
void sky_pass::set_atmosphere_upper_limit(float limit)
@ -550,6 +542,9 @@ void sky_pass::set_atmosphere_upper_limit(float limit)
atmosphere_upper_limit = limit;
atmosphere_radii.y = atmosphere_radii.x + atmosphere_upper_limit;
atmosphere_radii.z = atmosphere_radii.y * atmosphere_radii.y;
// Trigger transmittance LUT render
render_transmittance_lut = true;
}
void sky_pass::set_observer_elevation(float elevation)
@ -567,17 +562,23 @@ void sky_pass::set_rayleigh_parameters(float scale_height, const float3& scatter
scattering.y,
scattering.z
};
// Trigger transmittance LUT render
render_transmittance_lut = true;
}
void sky_pass::set_mie_parameters(float scale_height, float scattering, float absorption, float anisotropy)
void sky_pass::set_mie_parameters(float scale_height, float scattering, float extinction, float anisotropy)
{
mie_parameters =
{
-1.0f / scale_height,
scattering,
absorption,
extinction,
anisotropy
};
// Trigger transmittance LUT render
render_transmittance_lut = true;
}
void sky_pass::set_ozone_parameters(float lower_limit, float upper_limit, float mode, const float3& absorption)
@ -589,6 +590,14 @@ void sky_pass::set_ozone_parameters(float lower_limit, float upper_limit, float
mode
};
ozone_absorption = absorption;
// Trigger transmittance LUT render
render_transmittance_lut = true;
}
void sky_pass::set_airglow_illuminance(const float3& illuminance)
{
airglow_illuminance = illuminance;
}
void sky_pass::set_moon_position(const float3& position)
@ -626,6 +635,22 @@ void sky_pass::set_moon_planetlight_illuminance(const float3& illuminance)
moon_planetlight_illuminance_tween[1] = illuminance;
}
void sky_pass::set_moon_illuminance(const float3& illuminance, const float3& transmitted_illuminance)
{
moon_illuminance_tween[1] = illuminance;
moon_transmitted_illuminance = transmitted_illuminance;
}
void sky_pass::set_transmittance_lut_resolution(std::uint16_t width, std::uint16_t height)
{
transmittance_lut_texture->resize(width, height, nullptr);
transmittance_lut_framebuffer->resize({transmittance_lut_texture->get_width(), transmittance_lut_texture->get_height()});
transmittance_lut_resolution = {static_cast<float>(width), static_cast<float>(height)};
// Trigger transmittance LUT render
render_transmittance_lut = true;
}
void sky_pass::handle_event(const mouse_moved_event& event)
{
mouse_position = {static_cast<float>(event.x), static_cast<float>(event.y)};

+ 42
- 27
src/render/passes/sky-pass.hpp View File

@ -60,20 +60,20 @@ public:
void set_sky_model(const model* model);
void set_moon_model(const model* model);
void set_stars_model(const model* model);
void set_clouds_model(const model* model);
void set_icrf_to_eus(const math::transformation::se3<float>& transformation);
void set_sun_position(const float3& position);
void set_sun_luminance(const float3& luminance);
void set_sun_illuminance(const float3& illuminance);
void set_sun_illuminance(const float3& illuminance, const float3& transmitted_illuminance);
void set_sun_angular_radius(float radius);
void set_planet_radius(float radius);
void set_atmosphere_upper_limit(float limit);
void set_observer_elevation(float elevation);
void set_rayleigh_parameters(float scale_height, const float3& scattering);
void set_mie_parameters(float scale_height, float scattering, float absorption, float anisotropy);
void set_mie_parameters(float scale_height, float scattering, float extinction, float anisotropy);
void set_ozone_parameters(float lower_limit, float upper_limit, float mode, const float3& absorption);
void set_airglow_illuminance(const float3& illuminance);
void set_moon_position(const float3& position);
void set_moon_rotation(const math::quaternion<float>& rotation);
@ -82,42 +82,62 @@ public:
void set_moon_sunlight_illuminance(const float3& illuminance);
void set_moon_planetlight_direction(const float3& direction);
void set_moon_planetlight_illuminance(const float3& illuminance);
void set_moon_illuminance(const float3& illuminance, const float3& transmitted_illuminance);
/**
* Sets the resolution of transmittance LUT.
*
* @param width Transmittance LUT width, in pixels.
* @param height Transmittance LUT height, in pixels.
*/
void set_transmittance_lut_resolution(std::uint16_t width, std::uint16_t height);
private:
virtual void handle_event(const mouse_moved_event& event);
gl::vertex_buffer* quad_vbo;
gl::vertex_array* quad_vao;
gl::texture_2d* transmittance_texture;
gl::framebuffer* transmittance_framebuffer;
float2 transmittance_inverse_lut_resolution;
gl::texture_2d* transmittance_lut_texture;
gl::framebuffer* transmittance_lut_framebuffer;
float2 transmittance_lut_resolution;
gl::shader_program* transmittance_shader_program;
const gl::shader_input* transmittance_atmosphere_radii_input;
const gl::shader_input* transmittance_rayleigh_parameters_input;
const gl::shader_input* transmittance_mie_parameters_input;
const gl::shader_input* transmittance_ozone_distribution_input;
const gl::shader_input* transmittance_ozone_absorption_input;
const gl::shader_input* transmittance_inverse_lut_resolution_input;
const gl::shader_input* transmittance_resolution_input;
mutable bool render_transmittance_lut;
gl::texture_2d* sky_lut_texture;
gl::framebuffer* sky_lut_framebuffer;
gl::shader_program* sky_lut_shader_program;
float2 sky_lut_resolution;
const gl::shader_input* sky_lut_light_direction_input;
const gl::shader_input* sky_lut_light_illuminance_input;
const gl::shader_input* sky_lut_atmosphere_radii_input;
const gl::shader_input* sky_lut_observer_position_input;
const gl::shader_input* sky_lut_rayleigh_parameters_input;
const gl::shader_input* sky_lut_mie_parameters_input;
const gl::shader_input* sky_lut_ozone_distribution_input;
const gl::shader_input* sky_lut_ozone_absorption_input;
const gl::shader_input* sky_lut_airglow_illuminance_input;
const gl::shader_input* sky_lut_resolution_input;
const gl::shader_input* sky_lut_transmittance_lut_input;
const gl::shader_input* sky_lut_transmittance_lut_resolution_input;
gl::shader_program* sky_shader_program;
const gl::shader_input* model_view_projection_input;
const gl::shader_input* mouse_input;
const gl::shader_input* resolution_input;
const gl::shader_input* time_input;
const gl::shader_input* exposure_input;
const gl::shader_input* sun_direction_input;
const gl::shader_input* light_direction_input;
const gl::shader_input* sun_luminance_input;
const gl::shader_input* sun_illuminance_input;
const gl::shader_input* sun_angular_radius_input;
const gl::shader_input* atmosphere_radii_input;
const gl::shader_input* observer_position_input;
const gl::shader_input* rayleigh_parameters_input;
const gl::shader_input* mie_parameters_input;
const gl::shader_input* ozone_distribution_input;
const gl::shader_input* ozone_absorption_input;
const gl::shader_input* transmittance_lut_input;
const gl::shader_input* inverse_transmittance_lut_resolution_input;
const gl::shader_input* sky_illuminance_lut_input;
const gl::shader_input* sky_illuminance_lut_resolution_input;
gl::shader_program* moon_shader_program;
const gl::shader_input* moon_model_input;
@ -155,13 +175,6 @@ private:
const gl::shader_input* star_exposure_input;
const gl::shader_input* star_distance_input;
const model* clouds_model;
const material* cloud_material;
const gl::vertex_array* clouds_model_vao;
gl::drawing_mode clouds_model_drawing_mode;
std::size_t clouds_model_start_index;
std::size_t clouds_model_index_count;
gl::shader_program* cloud_shader_program;
const gl::shader_input* cloud_model_view_projection_input;
const gl::shader_input* cloud_sun_direction_input;
@ -169,14 +182,12 @@ private:
const gl::shader_input* cloud_camera_position_input;
const gl::shader_input* cloud_camera_exposure_input;
const gl::texture_2d* blue_noise_map;
const gl::texture_2d* sky_gradient;
const gl::texture_2d* sky_gradient2;
float2 mouse_position;
tween<float3> sun_position_tween;
tween<float3> sun_luminance_tween;
tween<float3> sun_illuminance_tween;
float3 sun_transmitted_illuminance;
tween<float3> icrf_to_eus_translation;
tween<math::quaternion<float>> icrf_to_eus_rotation;
@ -187,6 +198,9 @@ private:
tween<float3> moon_sunlight_illuminance_tween;
tween<float3> moon_planetlight_direction_tween;
tween<float3> moon_planetlight_illuminance_tween;
tween<float3> moon_illuminance_tween;
float3 moon_transmitted_illuminance;
float sun_angular_radius;
float atmosphere_upper_limit;
@ -197,6 +211,7 @@ private:
float4 mie_parameters;
float3 ozone_distribution;
float3 ozone_absorption;
float3 airglow_illuminance;
float magnification;
};

+ 3
- 0
src/render/renderer.cpp View File

@ -107,6 +107,9 @@ void renderer::render(float t, float dt, float alpha, const scene::collection& c
ctx.camera_forward = ctx.camera_transform.rotation * config::global_forward;
ctx.camera_up = ctx.camera_transform.rotation * config::global_up;
ctx.clip_near = camera->get_view_frustum().get_near(); ///< @TODO: tween this
ctx.view = camera->get_view_tween().interpolate(alpha);
ctx.projection = camera->get_projection_tween().interpolate(alpha);
ctx.view_projection = ctx.projection * ctx.view;
ctx.exposure = std::exp2(-camera->get_exposure_tween().interpolate(alpha));
// Create render queue

+ 15
- 10
src/resources/entity-archetype-loader.cpp View File

@ -44,32 +44,37 @@ static bool load_component_atmosphere(entity::archetype& archetype, const json&
component.upper_limit = element["upper_limit"].get<double>();
if (element.contains("index_of_refraction"))
component.index_of_refraction = element["index_of_refraction"].get<double>();
if (element.contains("air_concentration"))
component.air_concentration = element["air_concentration"].get<double>();
if (element.contains("rayleigh_concentration"))
component.rayleigh_concentration = element["rayleigh_concentration"].get<double>();
if (element.contains("rayleigh_scale_height"))
component.rayleigh_scale_height = element["rayleigh_scale_height"].get<double>();
if (element.contains("rayleigh_density"))
component.rayleigh_density = element["rayleigh_density"].get<double>();
if (element.contains("mie_concentration"))
component.mie_concentration = element["mie_concentration"].get<double>();
if (element.contains("mie_scale_height"))
component.mie_scale_height = element["mie_scale_height"].get<double>();
if (element.contains("mie_density"))
component.mie_density = element["mie_density"].get<double>();
if (element.contains("mie_anisotropy"))
component.mie_anisotropy = element["mie_anisotropy"].get<double>();
if (element.contains("mie_albedo"))
component.mie_albedo = element["mie_albedo"].get<double>();
if (element.contains("ozone_concentration"))
component.ozone_concentration = element["ozone_concentration"].get<double>();
if (element.contains("ozone_lower_limit"))
component.ozone_lower_limit = element["ozone_lower_limit"].get<double>();
if (element.contains("ozone_upper_limit"))
component.ozone_upper_limit = element["ozone_upper_limit"].get<double>();
if (element.contains("ozone_mode"))
component.ozone_mode = element["ozone_mode"].get<double>();
if (element.contains("ozone_concentration"))
component.ozone_concentration = element["ozone_concentration"].get<double>();
if (element.contains("airglow"))
component.airglow = element["airglow"].get<double>();
if (element.contains("airglow_illuminance"))
{
const auto& airglow_illuminance = element["airglow_illuminance"];
component.airglow_illuminance.x = airglow_illuminance[0].get<double>();
component.airglow_illuminance.y = airglow_illuminance[1].get<double>();
component.airglow_illuminance.z = airglow_illuminance[2].get<double>();
}
archetype.set<entity::component::atmosphere>(component);

+ 2
- 2
src/resources/material-loader.cpp View File

@ -161,7 +161,7 @@ static bool load_vector_property(render::material* material, const std::string&
T value;
std::size_t j = 0;
for (const auto& value_element: vector_element)
value[j++] = value_element.get<typename T::scalar_type>();
value[j++] = value_element.get<typename T::element_type>();
// Set property values
property->set_value(i++, value);
@ -176,7 +176,7 @@ static bool load_vector_property(render::material* material, const std::string&
T value;
std::size_t i = 0;
for (const auto& value_element: json)
value[i++] = value_element.get<typename T::scalar_type>();
value[i++] = value_element.get<typename T::element_type>();
// Set property values
property->set_value(value);

Loading…
Cancel
Save