Browse Source

Improve sky pass. Add light probes.

master
C. J. Howard 10 months ago
parent
commit
74e8d126fc
52 changed files with 1967 additions and 732 deletions
  1. +0
    -1
      CMakeLists.txt
  2. +1
    -1
      src/engine/color/aces.hpp
  3. +1
    -1
      src/engine/color/cat.hpp
  4. +1
    -1
      src/engine/color/cct.hpp
  5. +1
    -1
      src/engine/color/index.hpp
  6. +17
    -23
      src/engine/color/rgb.hpp
  7. +16
    -22
      src/engine/color/srgb.hpp
  8. +1
    -1
      src/engine/color/ucs.hpp
  9. +3
    -3
      src/engine/color/xyy.hpp
  10. +20
    -20
      src/engine/color/xyz.hpp
  11. +8
    -19
      src/engine/geom/intersection.hpp
  12. +13
    -13
      src/engine/gl/framebuffer.cpp
  13. +48
    -49
      src/engine/gl/framebuffer.hpp
  14. +6
    -4
      src/engine/gl/rasterizer.cpp
  15. +64
    -2
      src/engine/gl/texture.cpp
  16. +62
    -1
      src/engine/gl/texture.hpp
  17. +1
    -1
      src/engine/physics/gas/atmosphere.hpp
  18. +7
    -0
      src/engine/render/passes/final-pass.cpp
  19. +1
    -0
      src/engine/render/passes/final-pass.hpp
  20. +0
    -13
      src/engine/render/passes/ground-pass.cpp
  21. +0
    -1
      src/engine/render/passes/ground-pass.hpp
  22. +56
    -27
      src/engine/render/passes/material-pass.cpp
  23. +7
    -3
      src/engine/render/passes/material-pass.hpp
  24. +620
    -176
      src/engine/render/passes/sky-pass.cpp
  25. +193
    -28
      src/engine/render/passes/sky-pass.hpp
  26. +19
    -14
      src/engine/render/renderer.cpp
  27. +11
    -5
      src/engine/render/renderer.hpp
  28. +153
    -0
      src/engine/render/stages/light-probe-stage.cpp
  29. +91
    -0
      src/engine/render/stages/light-probe-stage.hpp
  30. +0
    -34
      src/engine/scene/ambient-light.cpp
  31. +0
    -90
      src/engine/scene/ambient-light.hpp
  32. +25
    -4
      src/engine/scene/camera.cpp
  33. +14
    -7
      src/engine/scene/camera.hpp
  34. +70
    -0
      src/engine/scene/light-probe.cpp
  35. +139
    -0
      src/engine/scene/light-probe.hpp
  36. +1
    -7
      src/engine/scene/light-type.hpp
  37. +3
    -3
      src/engine/scene/light.hpp
  38. +0
    -25
      src/engine/scene/sky-light.cpp
  39. +0
    -47
      src/engine/scene/sky-light.hpp
  40. +2
    -2
      src/game/components/atmosphere-component.hpp
  41. +18
    -0
      src/game/controls.cpp
  42. +6
    -4
      src/game/game.cpp
  43. +3
    -3
      src/game/game.hpp
  44. +5
    -5
      src/game/loaders/entity-archetype-loader.cpp
  45. +151
    -1
      src/game/states/nest-selection-state.cpp
  46. +7
    -0
      src/game/states/nest-selection-state.hpp
  47. +17
    -10
      src/game/states/nest-view-state.cpp
  48. +2
    -0
      src/game/states/nest-view-state.hpp
  49. +75
    -49
      src/game/systems/astronomy-system.cpp
  50. +5
    -3
      src/game/systems/astronomy-system.hpp
  51. +1
    -1
      src/game/systems/atmosphere-system.cpp
  52. +2
    -7
      src/game/world.cpp

+ 0
- 1
CMakeLists.txt View File

@ -1,6 +1,5 @@
cmake_minimum_required(VERSION 3.25)
option(APPLICATION_NAME "Application name" "Antkeeper")
option(APPLICATION_VERSION "Application version string" "0.0.0")
option(APPLICATION_AUTHOR "Application author" "C. J. Howard")

+ 1
- 1
src/engine/color/aces.hpp View File

@ -66,7 +66,7 @@ constexpr rgb::color_space ap1
* @return Saturation adjustment matrix.
*/
template <class T>
constexpr math::matrix<T, 3, 3> adjust_saturation(T s, const math::vector3<T>& to_y)
[[nodiscard]] constexpr math::matrix<T, 3, 3> adjust_saturation(T s, const math::vector3<T>& to_y) noexcept
{
const math::vector3<T> v = to_y * (T{1} - s);
return math::matrix<T, 3, 3>

+ 1
- 1
src/engine/color/cat.hpp View File

@ -81,7 +81,7 @@ constexpr math::matrix xyz_scaling =
* @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>)
[[nodiscard]] 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>) noexcept
{
// 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]};

+ 1
- 1
src/engine/color/cct.hpp View File

@ -38,7 +38,7 @@ 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)
[[nodiscard]] math::vector2<T> to_ucs(T t) noexcept
{
const T tt = t * t;
return math::vector2<T>

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

@ -34,7 +34,7 @@ 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)
[[nodiscard]] T bv_to_cct(T bv) noexcept
{
return T{4600} * (T{1} / (T{0.92} * bv + T{1.7}) + T{1} / (T{0.92} * bv + T{0.62}));
}

+ 17
- 23
src/engine/color/rgb.hpp View File

@ -43,7 +43,7 @@ namespace rgb {
* @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)
[[nodiscard]] 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 =
{
@ -106,7 +106,17 @@ struct color_space
* @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 oetf);
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 oetf):
r(r),
g(g),
b(b),
w(w),
eotf(eotf),
oetf(oetf),
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]}
{}
/**
* Measures the luminance of a linear RGB color.
@ -114,28 +124,12 @@ struct color_space
* @param x Linear RGB color.
* @return return Luminance of @p x.
*/
constexpr T luminance(const math::vector3<T>& x) const;
[[nodiscard]] inline constexpr T luminance(const math::vector3<T>& x) const noexcept
{
return math::dot(x, to_y);
}
};
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 oetf):
r(r),
g(g),
b(b),
w(w),
eotf(eotf),
oetf(oetf),
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.
*
@ -146,7 +140,7 @@ constexpr T color_space::luminance(const math::vector3& x) const
* @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>)
[[nodiscard]] 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;
}

+ 16
- 22
src/engine/color/srgb.hpp View File

@ -28,49 +28,43 @@
namespace color {
/**
* Maps a non-linear sRGB signal to a linear sRGB color.
* sRGB opto-electronic transfer function (OETF). Maps a linear sRGB color to a non-linear sRGB signal.
*
* @param x Non-linear sRGB signal.
* @param x Linear sRGB color.
*
* @return Linear sRGB color.
* @return Non-linear sRGB signal.
*
* @see IEC 61966-2-1:1999
*/
template <class T>
math::vector3<T> srgb_eotf(const math::vector3<T>& x)
[[nodiscard]] math::vector3<T> srgb_oetf(const math::vector3<T>& x)
{
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 x > T{0.0031308} ? std::pow(x, T{1.0 / 2.4}) * T{1.055} - T{0.055} : x * T{12.92};
};
return math::vector3<T>
{
f(x[0]),
f(x[1]),
f(x[2])
};
return {f(x[0]), f(x[1]), f(x[2])};
}
/**
* Maps a linear sRGB color to a non-linear sRGB signal.
* sRGB electro-optical transfer function (EOTF). Maps a non-linear sRGB signal to a linear sRGB color.
*
* @param x Linear sRGB color.
* @param x Non-linear sRGB signal.
*
* @return Non-linear sRGB signal.
* @return Linear sRGB color.
*
* @see IEC 61966-2-1:1999
*/
template <class T>
math::vector3<T> srgb_oetf(const math::vector3<T>& x)
[[nodiscard]] math::vector3<T> srgb_eotf(const math::vector3<T>& x)
{
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 x > T{0.0031308 * 12.92} ? std::pow((x + T{0.055}) / T{1.055}, T{2.4}) : x / T{12.92};
};
return math::vector3<T>
{
f(x[0]),
f(x[1]),
f(x[2])
};
return {f(x[0]), f(x[1]), f(x[2])};
}
/// sRGB color space.

+ 1
- 1
src/engine/color/ucs.hpp View File

@ -35,7 +35,7 @@ namespace ucs {
* @return CIE xyY color.
*/
template <class T>
constexpr math::vector3<T> to_xyy(const math::vector2<T>& uv, T y = T{1})
[[nodiscard]] constexpr math::vector3<T> to_xyy(const math::vector2<T>& uv, T y = T{1}) noexcept
{
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};

+ 3
- 3
src/engine/color/xyy.hpp View File

@ -34,7 +34,7 @@ namespace xyy {
* @return return Luminance of @p x.
*/
template <class T>
inline constexpr T luminance(const math::vector3<T>& x)
[[nodiscard]] inline constexpr T luminance(const math::vector3<T>& x) noexcept
{
return x[2];
}
@ -46,7 +46,7 @@ inline constexpr T luminance(const math::vector3& x)
* @return CIE 1960 UCS color.
*/
template <class T>
constexpr math::vector2<T> to_ucs(const math::vector3<T>& x)
[[nodiscard]] constexpr math::vector2<T> to_ucs(const math::vector3<T>& x) noexcept
{
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};
@ -59,7 +59,7 @@ constexpr math::vector2 to_ucs(const math::vector3& x)
* @return CIE XYZ color.
*/
template <class T>
constexpr math::vector3<T> to_xyz(const math::vector3<T>& x)
[[nodiscard]] constexpr math::vector3<T> to_xyz(const math::vector3<T>& x) noexcept
{
return math::vector3<T>{(x[0] * x[2]) / x[1], x[2], ((T{1} - x[0] - x[1]) * x[2]) / x[1]};
}

+ 20
- 20
src/engine/color/xyz.hpp View File

@ -38,7 +38,7 @@ namespace xyz {
* @return return Luminance of @p x.
*/
template <class T>
inline constexpr T luminance(const math::vector3<T>& x)
[[nodiscard]] inline constexpr T luminance(const math::vector3<T>& x) noexcept
{
return x[1];
}
@ -50,7 +50,7 @@ inline constexpr T luminance(const math::vector3& x)
* @return CIE xyY color.
*/
template <class T>
constexpr math::vector3<T> to_xyy(const math::vector3<T>& x)
[[nodiscard]] constexpr math::vector3<T> to_xyy(const math::vector3<T>& x) noexcept
{
const T sum = x[0] + x[1] + x[2];
return math::vector3<T>{x[0] / sum, x[1] / sum, x[1]};
@ -65,15 +65,15 @@ constexpr math::vector3 to_xyy(const math::vector3& x)
* @see match(T)
*/
template <class T>
T match_x(T lambda)
[[nodiscard]] T match_x(T lambda)
{
const T t0 = (lambda - T(442.0)) * ((lambda < T(442.0)) ? T(0.0624) : T(0.0374));
const T t1 = (lambda - T(599.8)) * ((lambda < T(599.8)) ? T(0.0264) : T(0.0323));
const T t2 = (lambda - T(501.1)) * ((lambda < T(501.1)) ? T(0.0490) : T(0.0382));
const T t0 = (lambda - T{442.0}) * ((lambda < T{442.0}) ? T{0.0624} : T{0.0374});
const T t1 = (lambda - T{599.8}) * ((lambda < T{599.8}) ? T{0.0264} : T{0.0323});
const T t2 = (lambda - T{501.1}) * ((lambda < T{501.1}) ? T{0.0490} : T{0.0382});
const T x0 = T( 0.362) * std::exp(T(-0.5) * t0 * t0);
const T x1 = T( 1.056) * std::exp(T(-0.5) * t1 * t1);
const T x2 = T(-0.065) * std::exp(T(-0.5) * t2 * t2);
const T x0 = T{ 0.362} * std::exp(T{-0.5} * t0 * t0);
const T x1 = T{ 1.056} * std::exp(T{-0.5} * t1 * t1);
const T x2 = T{-0.065} * std::exp(T{-0.5} * t2 * t2);
return x0 + x1 + x2;
}
@ -87,13 +87,13 @@ T match_x(T lambda)
* @see match(T)
*/
template <class T>
T match_y(T lambda)
[[nodiscard]] T match_y(T lambda)
{
const T t0 = (lambda - T(568.8)) * ((lambda < T(568.8)) ? T(0.0213) : T(0.0247));
const T t1 = (lambda - T(530.9)) * ((lambda < T(530.9)) ? T(0.0613) : T(0.0322));
const T t0 = (lambda - T{568.8}) * ((lambda < T{568.8}) ? T{0.0213} : T{0.0247});
const T t1 = (lambda - T{530.9}) * ((lambda < T{530.9}) ? T{0.0613} : T{0.0322});
const T y0 = T(0.821) * std::exp(T(-0.5) * t0 * t0);
const T y1 = T(0.286) * std::exp(T(-0.5) * t1 * t1);
const T y0 = T{0.821} * std::exp(T{-0.5} * t0 * t0);
const T y1 = T{0.286} * std::exp(T{-0.5} * t1 * t1);
return y0 + y1;
}
@ -107,13 +107,13 @@ T match_y(T lambda)
* @see match(T)
*/
template <class T>
T match_z(T lambda)
[[nodiscard]] T match_z(T lambda)
{
const T t0 = (lambda - T(437.0)) * ((lambda < T(437.0)) ? T(0.0845) : T(0.0278));
const T t1 = (lambda - T(459.0)) * ((lambda < T(459.0)) ? T(0.0385) : T(0.0725));
const T t0 = (lambda - T{437.0}) * ((lambda < T{437.0}) ? T{0.0845} : T{0.0278});
const T t1 = (lambda - T{459.0}) * ((lambda < T{459.0}) ? T{0.0385} : T{0.0725});
const T z0 = T(1.217) * std::exp(T(-0.5) * t0 * t0);
const T z1 = T(0.681) * std::exp(T(-0.5) * t1 * t1);
const T z0 = T{1.217} * std::exp(T{-0.5} * t0 * t0);
const T z1 = T{0.681} * std::exp(T{-0.5} * t1 * t1);
return z0 + z1;
}
@ -131,7 +131,7 @@ T match_z(T lambda)
* @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> match(T lambda)
[[nodiscard]] math::vector3<T> match(T lambda)
{
return math::vector3<T>
{

+ 8
- 19
src/engine/geom/intersection.hpp View File

@ -116,35 +116,24 @@ template
* @param hypersphere Hypersphere.
*
* @return Tuple containing the distances along the ray to the first and second points of intersection, or `std::nullopt` if no intersection occurred.
*
* @see Haines, E., Günther, J., & Akenine-Möller, T. (2019). Precision improvements for ray/sphere intersection. Ray Tracing Gems: High-Quality and Real-Time Rendering with DXR and Other APIs, 87-94.
*/
template <class T, std::size_t N>
[[nodiscard]] std::optional<std::tuple<T, T>> intersection(const ray<T, N>& ray, const hypersphere<T, N>& hypersphere) noexcept
{
const math::vector<T, N> displacement = ray.origin - hypersphere.center;
const T b = math::dot(displacement, ray.direction);
const T c = math::sqr_length(displacement) - hypersphere.radius * hypersphere.radius;
T h = b * b - c;
const math::vector<T, N> d = ray.origin - hypersphere.center;
const T b = math::dot(d, ray.direction);
const math::vector<T, N> qc = d - ray.direction * b;
const T h = hypersphere.radius * hypersphere.radius - math::dot(qc, qc);
if (h < T{0})
{
return std::nullopt;
}
h = std::sqrt(h);
T t0 = -b - h;
T t1 = -b + h;
if (t0 > t1)
{
std::swap(t0, t1);
}
if (t0 < T{0})
{
return std::nullopt;
}
return std::tuple<T, T>{t0, t1};
const T sqrt_h = std::sqrt(h);
return std::tuple<T, T>{-b - sqrt_h, -b + sqrt_h};
}
/**

+ 13
- 13
src/engine/gl/framebuffer.cpp View File

@ -18,7 +18,7 @@
*/
#include <engine/gl/framebuffer.hpp>
#include <engine/gl/texture-2d.hpp>
#include <engine/gl/texture.hpp>
#include <glad/glad.h>
namespace gl {
@ -31,9 +31,9 @@ static constexpr GLenum attachment_lut[] =
};
framebuffer::framebuffer(int width, int height):
dimensions{width, height}
m_dimensions{width, height}
{
glGenFramebuffers(1, &gl_framebuffer_id);
glGenFramebuffers(1, &m_gl_framebuffer_id);
}
framebuffer::framebuffer():
@ -42,38 +42,38 @@ framebuffer::framebuffer():
framebuffer::~framebuffer()
{
if (gl_framebuffer_id)
if (m_gl_framebuffer_id)
{
glDeleteFramebuffers(1, &gl_framebuffer_id);
glDeleteFramebuffers(1, &m_gl_framebuffer_id);
}
}
void framebuffer::resize(const std::array<int, 2>& dimensions)
{
this->dimensions = dimensions;
m_dimensions = dimensions;
}
void framebuffer::attach(framebuffer_attachment_type attachment_type, texture_2d* texture)
void framebuffer::attach(framebuffer_attachment_type attachment_type, texture* texture, std::uint8_t level)
{
glBindFramebuffer(GL_FRAMEBUFFER, gl_framebuffer_id);
glBindFramebuffer(GL_FRAMEBUFFER, m_gl_framebuffer_id);
GLenum gl_attachment = attachment_lut[static_cast<std::size_t>(attachment_type)];
glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attachment, GL_TEXTURE_2D, texture->m_gl_texture_id, 0);
glFramebufferTexture(GL_FRAMEBUFFER, gl_attachment, texture->m_gl_texture_id, level);
if (attachment_type == framebuffer_attachment_type::color)
{
color_attachment = texture;
m_color_attachment = texture;
}
else if (attachment_type == framebuffer_attachment_type::depth)
{
depth_attachment = texture;
m_depth_attachment = texture;
}
else if (attachment_type == framebuffer_attachment_type::stencil)
{
stencil_attachment = texture;
m_stencil_attachment = texture;
}
if (!color_attachment)
if (!m_color_attachment)
{
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);

+ 48
- 49
src/engine/gl/framebuffer.hpp View File

@ -26,7 +26,7 @@
namespace gl {
class rasterizer;
class texture_2d;
class texture;
enum class framebuffer_attachment_type: std::uint8_t
{
@ -59,64 +59,63 @@ public:
* Attaches a color, depth, or stencil texture to the framebuffer.
*
* @param attachment_type Type of attachment.
* @param texture Texture to attach.
* @param level Mip level of the texture to attach.
*/
void attach(framebuffer_attachment_type attachment_type, texture_2d* texture);
void attach(framebuffer_attachment_type attachment_type, texture* texture, std::uint8_t level = 0);
/// Returns the dimensions of the framebuffer, in pixels.
const std::array<int, 2>& get_dimensions() const;
[[nodiscard]] inline const std::array<int, 2>& get_dimensions() const noexcept
{
return m_dimensions;
}
const texture_2d* get_color_attachment() const;
texture_2d* get_color_attachment();
const texture_2d* get_depth_attachment() const;
texture_2d* get_depth_attachment();
const texture_2d* get_stencil_attachment() const;
texture_2d* get_stencil_attachment();
/// Returns the attached color texture, if any.
/// @{
[[nodiscard]] inline const texture* get_color_attachment() const noexcept
{
return m_color_attachment;
}
[[nodiscard]] inline texture* get_color_attachment() noexcept
{
return m_color_attachment;
}
/// @}
/// Returns the attached depth texture, if any.
/// @{
[[nodiscard]] inline const texture* get_depth_attachment() const noexcept
{
return m_depth_attachment;
}
[[nodiscard]] inline texture* get_depth_attachment() noexcept
{
return m_depth_attachment;
}
/// @}
/// Returns the attached stencil texture, if any.
/// @{
[[nodiscard]] inline const texture* get_stencil_attachment() const noexcept
{
return m_stencil_attachment;
}
[[nodiscard]] inline texture* get_stencil_attachment() noexcept
{
return m_stencil_attachment;
}
/// @}
private:
friend class rasterizer;
unsigned int gl_framebuffer_id{0};
std::array<int, 2> dimensions{0, 0};
texture_2d* color_attachment{nullptr};
texture_2d* depth_attachment{nullptr};
texture_2d* stencil_attachment{nullptr};
unsigned int m_gl_framebuffer_id{0};
std::array<int, 2> m_dimensions{0, 0};
texture* m_color_attachment{nullptr};
texture* m_depth_attachment{nullptr};
texture* m_stencil_attachment{nullptr};
};
inline const std::array<int, 2>& framebuffer::get_dimensions() const
{
return dimensions;
}
inline const texture_2d* framebuffer::get_color_attachment() const
{
return color_attachment;
}
inline texture_2d* framebuffer::get_color_attachment()
{
return color_attachment;
}
inline const texture_2d* framebuffer::get_depth_attachment() const
{
return depth_attachment;
}
inline texture_2d* framebuffer::get_depth_attachment()
{
return depth_attachment;
}
inline const texture_2d* framebuffer::get_stencil_attachment() const
{
return stencil_attachment;
}
inline texture_2d* framebuffer::get_stencil_attachment()
{
return stencil_attachment;
}
} // namespace gl
#endif // ANTKEEPER_GL_FRAMEBUFFER_HPP

+ 6
- 4
src/engine/gl/rasterizer.cpp View File

@ -57,11 +57,13 @@ rasterizer::rasterizer():
// Setup default framebuffer
default_framebuffer = std::make_unique<framebuffer>();
default_framebuffer->gl_framebuffer_id = 0;
default_framebuffer->dimensions = {scissor_box[2], scissor_box[3]};
default_framebuffer->m_gl_framebuffer_id = 0;
default_framebuffer->m_dimensions = {scissor_box[2], scissor_box[3]};
// Bind default framebuffer
bound_framebuffer = default_framebuffer.get();
glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
}
rasterizer::~rasterizer()
@ -69,14 +71,14 @@ rasterizer::~rasterizer()
void rasterizer::context_resized(int width, int height)
{
default_framebuffer->dimensions = {width, height};
default_framebuffer->m_dimensions = {width, height};
}
void rasterizer::use_framebuffer(const gl::framebuffer& framebuffer)
{
if (bound_framebuffer != &framebuffer)
{
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.gl_framebuffer_id);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.m_gl_framebuffer_id);
bound_framebuffer = &framebuffer;
}
}

+ 64
- 2
src/engine/gl/texture.cpp View File

@ -149,18 +149,69 @@ texture::~texture()
glDeleteTextures(1, &m_gl_texture_id);
}
void texture::read(std::span<std::byte> data, gl::pixel_type type, gl::pixel_format format, std::uint8_t level) const
{
const GLenum gl_format = pixel_format_lut[std::to_underlying(format)];
const GLenum gl_type = pixel_type_lut[std::to_underlying(type)];
glBindTexture(m_gl_texture_target, m_gl_texture_id);
glGetTexImage(m_gl_texture_target, static_cast<GLint>(level), gl_format, gl_type, data.data());
}
void texture::set_filters(texture_min_filter min_filter, texture_mag_filter mag_filter)
{
m_filters = {min_filter, mag_filter};
GLenum gl_min_filter = min_filter_lut[std::to_underlying(min_filter)];
GLenum gl_mag_filter = mag_filter_lut[std::to_underlying(mag_filter)];
const GLenum gl_min_filter = min_filter_lut[std::to_underlying(min_filter)];
const GLenum gl_mag_filter = mag_filter_lut[std::to_underlying(mag_filter)];
glBindTexture(m_gl_texture_target, m_gl_texture_id);
glTexParameteri(m_gl_texture_target, GL_TEXTURE_MIN_FILTER, gl_min_filter);
glTexParameteri(m_gl_texture_target, GL_TEXTURE_MAG_FILTER, gl_mag_filter);
}
void texture::set_min_filter(texture_min_filter filter)
{
const GLenum gl_min_filter = min_filter_lut[std::to_underlying(filter)];
glBindTexture(m_gl_texture_target, m_gl_texture_id);
glTexParameteri(m_gl_texture_target, GL_TEXTURE_MIN_FILTER, gl_min_filter);
}
void texture::set_mag_filter(texture_mag_filter filter)
{
const GLenum gl_mag_filter = mag_filter_lut[std::to_underlying(filter)];
glBindTexture(m_gl_texture_target, m_gl_texture_id);
glTexParameteri(m_gl_texture_target, GL_TEXTURE_MAG_FILTER, gl_mag_filter);
}
void texture::set_base_level(std::uint8_t level)
{
m_base_level = level;
glBindTexture(m_gl_texture_target, m_gl_texture_id);
glTexParameteri(m_gl_texture_target, GL_TEXTURE_BASE_LEVEL, static_cast<GLint>(m_base_level));
}
void texture::set_max_level(std::uint8_t level)
{
m_max_level = level;
glBindTexture(m_gl_texture_target, m_gl_texture_id);
glTexParameteri(m_gl_texture_target, GL_TEXTURE_MAX_LEVEL, static_cast<GLint>(m_max_level));
}
void texture::set_mipmap_range(std::uint8_t base_level, std::uint8_t max_level)
{
m_base_level = base_level;
m_max_level = max_level;
glBindTexture(m_gl_texture_target, m_gl_texture_id);
glTexParameteri(m_gl_texture_target, GL_TEXTURE_BASE_LEVEL, static_cast<GLint>(m_base_level));
glTexParameteri(m_gl_texture_target, GL_TEXTURE_MAX_LEVEL, static_cast<GLint>(m_max_level));
}
void texture::set_max_anisotropy(float anisotropy)
{
m_max_anisotropy = std::max<float>(0.0f, std::min<float>(1.0f, anisotropy));
@ -273,6 +324,7 @@ void texture::resize(std::uint16_t width, std::uint16_t height, std::uint16_t de
}
glGenerateMipmap(m_gl_texture_target);
glTexParameteriv(m_gl_texture_target, GL_TEXTURE_SWIZZLE_RGBA, gl_swizzle_mask);
/// @TODO: remove this
@ -300,6 +352,16 @@ void texture::update_cube_faces(unsigned int gl_internal_format, unsigned int gl
const auto layout = texture_cube::infer_cube_map_layout(width, height);
const auto face_size = texture_cube::infer_cube_map_face_size(layout, width, height);
if (!data)
{
for (int i = 0; i < 6; ++i)
{
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, gl_internal_format, face_size, face_size, 0, gl_format, gl_type, nullptr);
}
return;
}
std::size_t channel_count = 0;
switch (m_pixel_format)
{

+ 62
- 1
src/engine/gl/texture.hpp View File

@ -29,6 +29,7 @@
#include <array>
#include <cstdint>
#include <cstddef>
#include <span>
#include <tuple>
namespace gl {
@ -51,13 +52,59 @@ public:
virtual ~texture();
/**
* Sets the texture filtering modes.
* Reads texture pixel data from the GPU.
*
* @param[out] data Pixel data buffer.
* @param[in] type Returned pixel component data type.
* @param[in] format Returned pixel format.
* @param[in] level Mip level to read.
*/
void read(std::span<std::byte> data, gl::pixel_type type, gl::pixel_format format, std::uint8_t level = 0) const;
/**
* Sets the texture filter modes.
*
* @param min_filter Texture minification filter mode.
* @param mag_filter Texture magnification filter mode.
*/
void set_filters(texture_min_filter min_filter, texture_mag_filter mag_filter);
/**
* Sets the texture minification filter mode.
*
* @param filter Texture minification filter mode.
*/
void set_min_filter(texture_min_filter filter);
/**
* Sets the texture magnification filter mode.
*
* @param filter Texture magnification filter mode.
*/
void set_mag_filter(texture_mag_filter filter);
/**
* Sets the index of lowest mipmap level.
*
* @param level Index of the lowest mipmap level.
*/
void set_base_level(std::uint8_t level);
/**
* Sets the index of highest mipmap level.
*
* @param level Index of the highest mipmap level.
*/
void set_max_level(std::uint8_t level);
/**
* Sets the range of mipmap levels.
*
* @param base Index of the lowest mipmap level
* @param max Index of the highest mipmap level.
*/
void set_mipmap_range(std::uint8_t base_level, std::uint8_t max_level);
/**
* Sets the maximum anisotropy.
*
@ -122,6 +169,18 @@ public:
return m_filters;
}
/// Returns the index of the lowest mipmap level.
[[nodiscard]] inline std::uint8_t get_base_level() const noexcept
{
return m_base_level;
}
/// Returns the index of the highest mipmap level.
[[nodiscard]] inline std::uint8_t get_max_level() const noexcept
{
return m_max_level;
}
/// Returns the maximum anisotropy.
[[nodiscard]] inline float get_max_anisotropy() const noexcept
{
@ -197,6 +256,8 @@ private:
gl::color_space m_color_space{};
std::array<texture_wrapping, 3> m_wrapping{texture_wrapping::repeat, texture_wrapping::repeat, texture_wrapping::repeat};
std::tuple<texture_min_filter, texture_mag_filter> m_filters{texture_min_filter::linear_mipmap_linear, texture_mag_filter::linear};
std::uint8_t m_base_level{};
std::uint8_t m_max_level{255};
float m_max_anisotropy{};
};

+ 1
- 1
src/engine/physics/gas/atmosphere.hpp View File

@ -239,7 +239,7 @@ namespace density {
template <class T>
T triangular(T d0, T z, T a, T b, T c)
{
return d0 * max(T(0), max(T(0), c - z) / (a - c) - max(T(0), z - c) / (b - c) + T(1));
return d0 * std::max(T(0), std::max(T(0), c - z) / (a - c) - std::max(T(0), z - c) / (b - c) + T(1));
}
} // namespace density

+ 7
- 0
src/engine/render/passes/final-pass.cpp View File

@ -99,6 +99,9 @@ void final_pass::render(render::context& ctx)
{
command();
}
// Increment current frame
++frame;
}
void final_pass::set_color_texture(const gl::texture_2d* texture)
@ -187,6 +190,10 @@ void final_pass::rebuild_command_buffer()
{
command_buffer.emplace_back([&, var](){var->update(time);});
}
if (const auto frame_var = shader_program->variable("frame"))
{
command_buffer.emplace_back([&, frame_var](){frame_var->update(frame);});
}
command_buffer.emplace_back
(

+ 1
- 0
src/engine/render/passes/final-pass.hpp View File

@ -62,6 +62,7 @@ private:
float blue_noise_scale;
float2 resolution;
float time;
int frame{};
std::vector<std::function<void()>> command_buffer;
};

+ 0
- 13
src/engine/render/passes/ground-pass.cpp View File

@ -37,7 +37,6 @@
#include <engine/scene/camera.hpp>
#include <engine/scene/collection.hpp>
#include <engine/scene/directional-light.hpp>
#include <engine/scene/ambient-light.hpp>
#include <engine/utility/fundamental-types.hpp>
#include <engine/color/color.hpp>
#include <engine/math/interpolation.hpp>
@ -92,7 +91,6 @@ void ground_pass::render(render::context& ctx)
const float4x4& view_projection = ctx.view_projection;
float4x4 model_view_projection = projection * model_view;
float3 ambient_light_color = {0.0f, 0.0f, 0.0f};
float3 directional_light_color = {0.0f, 0.0f, 0.0f};
float3 directional_light_direction = {0.0f, 0.0f, 0.0f};
@ -107,14 +105,6 @@ void ground_pass::render(render::context& ctx)
const scene::light* light = static_cast<const scene::light*>(object);
switch (light->get_light_type())
{
// Add ambient light
case scene::light_type::ambient:
{
// Pre-expose light
ambient_light_color = light->get_scaled_color_tween().interpolate(ctx.alpha) * ctx.exposure;
break;
}
// Add directional light
case scene::light_type::directional:
{
@ -149,8 +139,6 @@ void ground_pass::render(render::context& ctx)
directional_light_colors_var->update(0, &directional_light_color, 1);
if (directional_light_directions_var)
directional_light_directions_var->update(0, &directional_light_direction, 1);
if (ambient_light_colors_var)
ambient_light_colors_var->update(0, &ambient_light_color, 1);
ground_material->update(ctx.alpha);
@ -186,7 +174,6 @@ void ground_pass::set_ground_model(std::shared_ptr model)
camera_position_var = shader_program->get_var("camera.position");
directional_light_colors_var = shader_program->get_var("directional_light_colors");
directional_light_directions_var = shader_program->get_var("directional_light_directions");
ambient_light_colors_var = shader_program->get_var("ambient_light_colors");
}
}
}

+ 0
- 1
src/engine/render/passes/ground-pass.hpp View File

@ -55,7 +55,6 @@ private:
const gl::shader_variable* camera_position_var;
const gl::shader_variable* directional_light_colors_var;
const gl::shader_variable* directional_light_directions_var;
const gl::shader_variable* ambient_light_colors_var;
std::shared_ptr<model> ground_model;
const material* ground_material;

+ 56
- 27
src/engine/render/passes/material-pass.cpp View File

@ -38,11 +38,11 @@
#include <engine/render/context.hpp>
#include <engine/scene/camera.hpp>
#include <engine/scene/collection.hpp>
#include <engine/scene/ambient-light.hpp>
#include <engine/scene/directional-light.hpp>
#include <engine/scene/spot-light.hpp>
#include <engine/scene/point-light.hpp>
#include <engine/scene/rectangle-light.hpp>
#include <engine/scene/light-probe.hpp>
#include <engine/config.hpp>
#include <engine/math/quaternion.hpp>
#include <engine/math/projection.hpp>
@ -122,6 +122,9 @@ material_pass::material_pass(gl::rasterizer* rasterizer, const gl::framebuffer*
// Load LTC LUT textures
ltc_lut_1 = resource_manager->load<gl::texture_2d>("ltc-lut-1.tex");
ltc_lut_2 = resource_manager->load<gl::texture_2d>("ltc-lut-2.tex");
// Load IBL BRDF LUT texture
brdf_lut = resource_manager->load<gl::texture_2d>("brdf-lut.tex");
}
void material_pass::render(render::context& ctx)
@ -315,36 +318,32 @@ void material_pass::evaluate_camera(const render::context& ctx)
void material_pass::evaluate_lighting(const render::context& ctx)
{
// Reset light and shadow counts
ambient_light_count = 0;
point_light_count = 0;
light_probe_count = 0;
directional_light_count = 0;
directional_shadow_count = 0;
spot_light_count = 0;
point_light_count = 0;
rectangle_light_count = 0;
const auto& light_probes = ctx.collection->get_objects(scene::light_probe::object_type_id);
for (const scene::object_base* object: light_probes)
{
if (!light_probe_count)
{
const scene::light_probe& light_probe = static_cast<const scene::light_probe&>(*object);
++light_probe_count;
light_probe_luminance_texture = light_probe.get_luminance_texture().get();
light_probe_illuminance_texture = light_probe.get_illuminance_texture().get();
}
}
const auto& lights = ctx.collection->get_objects(scene::light::object_type_id);
for (const scene::object_base* object: lights)
{
const scene::light& light = static_cast<const scene::light&>(*object);
switch (light.get_light_type())
{
// Add ambient light
case scene::light_type::ambient:
{
const std::size_t index = ambient_light_count;
++ambient_light_count;
if (ambient_light_count > ambient_light_colors.size())
{
ambient_light_colors.resize(ambient_light_count);
}
ambient_light_colors[index] = static_cast<const scene::ambient_light&>(light).get_colored_illuminance() * ctx.camera->get_exposure_normalization();
break;
}
{
// Add directional light
case scene::light_type::directional:
{
@ -376,7 +375,7 @@ void material_pass::evaluate_lighting(const render::context& ctx)
directional_shadow_matrices.resize(directional_shadow_count);
}
directional_shadow_maps[index] = directional_light.get_shadow_framebuffer()->get_depth_attachment();
directional_shadow_maps[index] = static_cast<const gl::texture_2d*>(directional_light.get_shadow_framebuffer()->get_depth_attachment());
directional_shadow_biases[index] = directional_light.get_shadow_bias();
directional_shadow_splits[index] = &directional_light.get_shadow_cascade_distances();
directional_shadow_matrices[index] = &directional_light.get_shadow_cascade_matrices();
@ -458,12 +457,12 @@ void material_pass::evaluate_lighting(const render::context& ctx)
}
// Generate lighting state hash
lighting_state_hash = std::hash<std::size_t>{}(ambient_light_count);
lighting_state_hash = std::hash<std::size_t>{}(light_probe_count);
lighting_state_hash = hash::combine(lighting_state_hash, std::hash<std::size_t>{}(directional_light_count));
lighting_state_hash = hash::combine(lighting_state_hash, std::hash<std::size_t>{}(directional_shadow_count));
lighting_state_hash = hash::combine(lighting_state_hash, std::hash<std::size_t>{}(point_light_count));
lighting_state_hash = hash::combine(lighting_state_hash, std::hash<std::size_t>{}(spot_light_count));
lighting_state_hash = hash::combine(lighting_state_hash, std::hash<std::size_t>{}(point_light_count));
lighting_state_hash = hash::combine(lighting_state_hash, std::hash<std::size_t>{}(rectangle_light_count));
}
void material_pass::evaluate_misc(const render::context& ctx)
@ -498,7 +497,7 @@ std::unique_ptr material_pass::generate_shader_program(const
definitions["FRAGMENT_OUTPUT_COLOR"] = std::to_string(0);
definitions["AMBIENT_LIGHT_COUNT"] = std::to_string(ambient_light_count);
definitions["LIGHT_PROBE_COUNT"] = std::to_string(light_probe_count);
definitions["DIRECTIONAL_LIGHT_COUNT"] = std::to_string(directional_light_count);
definitions["DIRECTIONAL_SHADOW_COUNT"] = std::to_string(directional_shadow_count);
definitions["POINT_LIGHT_COUNT"] = std::to_string(point_light_count);
@ -547,6 +546,7 @@ void material_pass::build_shader_command_buffer(std::vector
command_buffer.emplace_back([&, clip_depth_var](){clip_depth_var->update(clip_depth);});
}
// LTC variables
if (auto ltc_lut_1_var = shader_program.variable("ltc_lut_1"))
{
if (auto ltc_lut_2_var = shader_program.variable("ltc_lut_2"))
@ -562,12 +562,41 @@ void material_pass::build_shader_command_buffer(std::vector
}
}
// Update ambient light variables
if (ambient_light_count)
// IBL variables
if (auto brdf_lut_var = shader_program.variable("brdf_lut"))
{
command_buffer.emplace_back
(
[&, brdf_lut_var]()
{
brdf_lut_var->update(*brdf_lut);
}
);
}
// Update light probe variables
if (light_probe_count)
{
if (auto ambient_light_colors_var = shader_program.variable("ambient_light_colors"))
if (auto light_probe_luminance_texture_var = shader_program.variable("light_probe_luminance_texture"))
{
command_buffer.emplace_back([&, ambient_light_colors_var](){ambient_light_colors_var->update(std::span<const float3>{ambient_light_colors.data(), ambient_light_count});});
command_buffer.emplace_back
(
[&, light_probe_luminance_texture_var]()
{
light_probe_luminance_texture_var->update(*light_probe_luminance_texture);
}
);
}
if (auto light_probe_illuminance_texture_var = shader_program.variable("light_probe_illuminance_texture"))
{
command_buffer.emplace_back
(
[&, light_probe_illuminance_texture_var]()
{
light_probe_illuminance_texture_var->update(*light_probe_illuminance_texture);
}
);
}
}

+ 7
- 3
src/engine/render/passes/material-pass.hpp View File

@ -97,9 +97,10 @@ private:
float2 clip_depth;
float log_depth_coef;
// Ambient lights
std::vector<float3> ambient_light_colors;
std::size_t ambient_light_count;
// Light probes
const gl::texture_cube* light_probe_luminance_texture{};
const gl::texture_1d* light_probe_illuminance_texture{};
std::size_t light_probe_count;
// Point lights
std::vector<float3> point_light_colors;
@ -134,6 +135,9 @@ private:
std::shared_ptr<gl::texture_2d> ltc_lut_1;
std::shared_ptr<gl::texture_2d> ltc_lut_2;
// IBL
std::shared_ptr<gl::texture_2d> brdf_lut;
// Misc
float time;
float timestep;

+ 620
- 176
src/engine/render/passes/sky-pass.cpp
File diff suppressed because it is too large
View File


+ 193
- 28
src/engine/render/passes/sky-pass.hpp View File

@ -33,6 +33,7 @@
#include <engine/gl/drawing-mode.hpp>
#include <engine/math/se3.hpp>
#include <engine/scene/object.hpp>
#include <engine/scene/light-probe.hpp>
class resource_manager;
@ -43,6 +44,8 @@ class model;
/**
*
*
* @see Hillaire, Sébastien. "A scalable and production ready sky and atmosphere rendering technique." Computer Graphics Forum. Vol. 39. No. 4. 2020.
*/
class sky_pass: public pass
{
@ -51,6 +54,128 @@ public:
virtual ~sky_pass() = default;
void render(render::context& ctx) override;
/// @name Transmittance LUT
/// @{
/**
* Sets the number of transmittance integration samples.
*
* @param count Integration sample count.
*
* @note Triggers rebuilding of transmittance LUT shader.
* @note Triggers rendering of transmittance LUT.
*/
void set_transmittance_lut_sample_count(std::uint16_t count);
/**
* Sets the resolution of the transmittance LUT.
*
* @param resolution Resolution of the transmittance LUT texture, in pixels.
*
* @note Triggers rendering of transmittance LUT.
*/
void set_transmittance_lut_resolution(const math::vector2<std::uint16_t>& resolution);
/// Returns the number of transmittance integration samples.
[[nodiscard]] inline std::uint16_t get_transmittance_lut_sample_count() const noexcept
{
return m_transmittance_lut_sample_count;
}
/// Returns the resolution of the transmittance LUT texture, in pixels.
[[nodiscard]] inline const math::vector2<std::uint16_t>& get_transmittance_lut_resolution() const noexcept
{
return m_transmittance_lut_resolution;
}
/// @}
/// @name Multiscattering LUT
/// @{
/**
* Sets the number of multiscattering directions to sample.
*
* @param count Multiscattering direction sample count.
*
* @note Triggers rebuilding of multiscattering LUT shader.
* @note Triggers rendering of multiscattering LUT.
*/
void set_multiscattering_lut_direction_sample_count(std::uint16_t count);
/**
* Sets the number of multiscattering scatter events to sample per sample direction.
*
* @param count Multiscattering scatter sample count.
*
* @note Triggers rebuilding of multiscattering LUT shader.
* @note Triggers rendering of multiscattering LUT.
*/
void set_multiscattering_lut_scatter_sample_count(std::uint16_t count);
/**
* Sets the resolution of the multiscattering LUT.
*
* @param resolution Resolution of the multiscattering LUT texture, in pixels.
*
* @note Triggers rendering of multiscattering LUT.
*/
void set_multiscattering_lut_resolution(const math::vector2<std::uint16_t>& resolution);
/// Returns the number of multiscattering direction samples.
[[nodiscard]] inline std::uint16_t get_multiscattering_lut_direction_sample_count() const noexcept
{
return m_multiscattering_lut_direction_sample_count;
}
/// Returns the number of multiscattering scatter samples per direction.
[[nodiscard]] inline std::uint16_t get_multiscattering_lut_scatter_sample_count() const noexcept
{
return m_multiscattering_lut_scatter_sample_count;
}
/// Returns the resolution of the multiscattering LUT texture, in pixels.
[[nodiscard]] inline const math::vector2<std::uint16_t>& get_multiscattering_lut_resolution() const noexcept
{
return m_multiscattering_lut_resolution;
}
/// @}
/// @name Luminance LUT
/// @{
/**
* Sets the number of luminance integration samples.
*
* @param count Integration sample count.
*
* @note Triggers rebuilding of luminance LUT shader.
* @note Triggers rendering of luminance LUT.
*/
void set_luminance_lut_sample_count(std::uint16_t count);
/**
* Sets the resolution of the luminance LUT.
*
* @param resolution Resolution of the luminance LUT texture, in pixels.
*
* @note Triggers rendering of luminance LUT.
*/
void set_luminance_lut_resolution(const math::vector2<std::uint16_t>& resolution);
/// Returns the number of luminance integration samples.
[[nodiscard]] inline std::uint16_t get_luminance_lut_sample_count() const noexcept
{
return m_luminance_lut_sample_count;
}
/// Returns the resolution of the luminance LUT texture, in pixels.
[[nodiscard]] inline const math::vector2<std::uint16_t>& get_luminance_lut_resolution() const noexcept
{
return m_luminance_lut_resolution;
}
/// @}
void update_tweens();
void set_magnification(float scale);
@ -71,7 +196,8 @@ public:
void set_rayleigh_parameters(float scale_height, const float3& scattering);
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_airglow_luminance(const float3& luminance);
void set_ground_albedo(const float3& albedo);
void set_moon_position(const float3& position);
void set_moon_rotation(const math::quaternion<float>& rotation);
@ -82,35 +208,63 @@ public:
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);
void set_sky_probe(std::shared_ptr<scene::light_probe> probe);
private:
void rebuild_transmittance_lut_shader_program();
void rebuild_transmittance_lut_command_buffer();
void rebuild_multiscattering_lut_shader_program();
void rebuild_multiscattering_lut_command_buffer();
void rebuild_luminance_lut_shader_program();
void rebuild_luminance_lut_command_buffer();
void rebuild_sky_lut_command_buffer();
void rebuild_sky_probe_command_buffer();
std::unique_ptr<gl::vertex_buffer> quad_vbo;
std::unique_ptr<gl::vertex_array> quad_vao;
std::unique_ptr<gl::texture_2d> transmittance_lut_texture;
std::unique_ptr<gl::framebuffer> transmittance_lut_framebuffer;
float2 transmittance_lut_resolution;
std::shared_ptr<gl::shader_template> transmittance_lut_shader_template;
std::unique_ptr<gl::shader_program> transmittance_lut_shader_program;
bool render_transmittance_lut;
std::vector<std::function<void()>> transmittance_lut_command_buffer;
std::unique_ptr<gl::texture_2d> sky_lut_texture;
std::unique_ptr<gl::framebuffer> sky_lut_framebuffer;
std::shared_ptr<gl::shader_template> sky_lut_shader_template;
std::unique_ptr<gl::shader_program> sky_lut_shader_program;
float2 sky_lut_resolution;
std::vector<std::function<void()>> sky_lut_command_buffer;
// Transmittance
std::uint16_t m_transmittance_lut_sample_count{40};
math::vector2<std::uint16_t> m_transmittance_lut_resolution{256, 64};
std::unique_ptr<gl::texture_2d> m_transmittance_lut_texture;
std::unique_ptr<gl::framebuffer> m_transmittance_lut_framebuffer;
std::shared_ptr<gl::shader_template> m_transmittance_lut_shader_template;
std::unique_ptr<gl::shader_program> m_transmittance_lut_shader_program;
std::vector<std::function<void()>> m_transmittance_lut_command_buffer;
bool m_render_transmittance_lut{false};
// Multiscattering
std::uint16_t m_multiscattering_lut_direction_sample_count{64};
std::uint16_t m_multiscattering_lut_scatter_sample_count{20};
math::vector2<std::uint16_t> m_multiscattering_lut_resolution{32, 32};
std::unique_ptr<gl::texture_2d> m_multiscattering_lut_texture;
std::unique_ptr<gl::framebuffer> m_multiscattering_lut_framebuffer;
std::shared_ptr<gl::shader_template> m_multiscattering_lut_shader_template;
std::unique_ptr<gl::shader_program> m_multiscattering_lut_shader_program;
std::vector<std::function<void()>> m_multiscattering_lut_command_buffer;
bool m_render_multiscattering_lut{false};
// Luminance
std::uint16_t m_luminance_lut_sample_count{30};
math::vector2<std::uint16_t> m_luminance_lut_resolution{200, 100};
std::unique_ptr<gl::texture_2d> m_luminance_lut_texture;
std::unique_ptr<gl::framebuffer> m_luminance_lut_framebuffer;
std::shared_ptr<gl::shader_template> m_luminance_lut_shader_template;
std::unique_ptr<gl::shader_program> m_luminance_lut_shader_program;
std::vector<std::function<void()>> m_luminance_lut_command_buffer;
bool m_render_luminance_lut{false};
// Sky probe
std::shared_ptr<scene::light_probe> m_sky_probe;
std::vector<std::unique_ptr<gl::framebuffer>> m_sky_probe_framebuffers;
std::shared_ptr<gl::shader_template> m_sky_probe_shader_template;
std::unique_ptr<gl::shader_program> m_sky_probe_shader_program;
std::shared_ptr<gl::shader_template> m_cubemap_downsample_shader_template;
std::unique_ptr<gl::shader_program> m_cubemap_downsample_shader_program;
std::vector<std::function<void()>> m_sky_probe_command_buffer;
float3 dominant_light_direction;
float3 dominant_light_illuminance;
@ -126,8 +280,10 @@ private:
const gl::shader_variable* sun_angular_radius_var;
const gl::shader_variable* atmosphere_radii_var;
const gl::shader_variable* observer_position_var;
const gl::shader_variable* sky_illuminance_lut_var;
const gl::shader_variable* sky_illuminance_lut_resolution_var;
const gl::shader_variable* sky_transmittance_lut_var;
const gl::shader_variable* sky_transmittance_lut_resolution_var;
const gl::shader_variable* sky_luminance_lut_var;
const gl::shader_variable* sky_luminance_lut_resolution_var;
std::shared_ptr<gl::shader_program> moon_shader_program;
const gl::shader_variable* moon_model_var;
@ -138,6 +294,11 @@ private:
const gl::shader_variable* moon_sunlight_illuminance_var;
const gl::shader_variable* moon_planetlight_direction_var;
const gl::shader_variable* moon_planetlight_illuminance_var;
const gl::shader_variable* moon_albedo_map_var;
const gl::shader_variable* moon_normal_map_var;
const gl::shader_variable* moon_observer_position_var;
const gl::shader_variable* moon_sky_transmittance_lut_var;
const gl::shader_variable* moon_atmosphere_radii_var;
std::shared_ptr<render::model> sky_model;
const material* sky_material;
@ -152,6 +313,9 @@ private:
gl::drawing_mode moon_model_drawing_mode;
std::size_t moon_model_start_index;
std::size_t moon_model_index_count;
std::shared_ptr<gl::texture_2d> m_moon_albedo_map;
std::shared_ptr<gl::texture_2d> m_moon_normal_map;
std::shared_ptr<render::model> stars_model;
const material* star_material;
@ -160,10 +324,10 @@ private:
std::size_t stars_model_start_index;
std::size_t stars_model_index_count;
std::unique_ptr<gl::shader_program> star_shader_program;
const gl::shader_variable* star_model_view_var;
const gl::shader_variable* star_projection_var;
const gl::shader_variable* star_model_view_projection_var;
const gl::shader_variable* star_exposure_var;
const gl::shader_variable* star_distance_var;
const gl::shader_variable* star_inv_resolution_var;
float2 mouse_position;
@ -186,14 +350,15 @@ private:
float sun_angular_radius;
float atmosphere_upper_limit;
float3 atmosphere_radii;
float4 atmosphere_radii;
float observer_elevation;
tween<float3> observer_position_tween;
float4 rayleigh_parameters;
float4 mie_parameters;
float3 ozone_distribution;
float3 ozone_absorption;
float3 airglow_illuminance;
float3 airglow_luminance;
math::vector3<float> m_ground_albedo{};
float magnification;
};

+ 19
- 14
src/engine/render/renderer.cpp View File

@ -24,6 +24,7 @@
#include <engine/scene/camera.hpp>
#include <engine/scene/static-mesh.hpp>
#include <engine/scene/billboard.hpp>
#include <engine/scene/light-probe.hpp>
#include <engine/scene/text.hpp>
#include <engine/render/model.hpp>
#include <engine/gl/drawing-mode.hpp>
@ -37,19 +38,23 @@
namespace render {
renderer::renderer()
{
culling_stage = std::make_unique<render::culling_stage>();
queue_stage = std::make_unique<render::queue_stage>();
renderer::renderer(gl::rasterizer& rasterizer, ::resource_manager& resource_manager)
{
m_light_probe_stage = std::make_unique<render::light_probe_stage>(rasterizer, resource_manager);
m_culling_stage = std::make_unique<render::culling_stage>();
m_queue_stage = std::make_unique<render::queue_stage>();
}
void renderer::render(float t, float dt, float alpha, const scene::collection& collection)
{
// Init render context
ctx.collection = &collection;
ctx.t = t;
ctx.dt = dt;
ctx.alpha = alpha;
m_ctx.collection = &collection;
m_ctx.t = t;
m_ctx.dt = dt;
m_ctx.alpha = alpha;
// Execute light probe stage
m_light_probe_stage->execute(m_ctx);
// Get list of cameras to be sorted
const auto& cameras = collection.get_objects(scene::camera::object_type_id);
@ -67,20 +72,20 @@ void renderer::render(float t, float dt, float alpha, const scene::collection& c
}
// Update render context camera
ctx.camera = &camera;
m_ctx.camera = &camera;
// Clear render queues
ctx.objects.clear();
ctx.operations.clear();
m_ctx.objects.clear();
m_ctx.operations.clear();
// Execute culling stage
culling_stage->execute(ctx);
m_culling_stage->execute(m_ctx);
// Execute queue stage
queue_stage->execute(ctx);
m_queue_stage->execute(m_ctx);
// Pass render context to the camera's compositor
compositor->composite(ctx);
compositor->composite(m_ctx);
}
}

+ 11
- 5
src/engine/render/renderer.hpp View File

@ -23,7 +23,10 @@
#include <engine/render/context.hpp>
#include <engine/render/stages/culling-stage.hpp>
#include <engine/render/stages/queue-stage.hpp>
#include <engine/render/stages/light-probe-stage.hpp>
#include <engine/scene/collection.hpp>
#include <engine/gl/rasterizer.hpp>
#include <engine/resources/resource-manager.hpp>
#include <memory>
namespace render {
@ -36,8 +39,11 @@ class renderer
public:
/**
* Constructs a renderer.
*
* @param rasterizer GL rasterizer.
* @param resource_maanger Resource manager for loading shader templates.
*/
renderer();
renderer(gl::rasterizer& rasterizer, ::resource_manager& resource_manager);
/**
* Renders a collection of scene objects.
@ -50,10 +56,10 @@ public:
void render(float t, float dt, float alpha, const scene::collection& collection);
private:
render::context ctx;
std::unique_ptr<render::culling_stage> culling_stage;
std::unique_ptr<render::queue_stage> queue_stage;
render::context m_ctx;
std::unique_ptr<render::light_probe_stage> m_light_probe_stage;
std::unique_ptr<render::culling_stage> m_culling_stage;
std::unique_ptr<render::queue_stage> m_queue_stage;
};
} // namespace render

+ 153
- 0
src/engine/render/stages/light-probe-stage.cpp View File

@ -0,0 +1,153 @@
/*
* Copyright (C) 2023 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 <engine/render/stages/light-probe-stage.hpp>
#include <engine/render/vertex-attribute.hpp>
#include <engine/scene/light-probe.hpp>
#include <engine/scene/collection.hpp>
#include <algorithm>
#include <execution>
#include <stdexcept>
#include <glad/glad.h>
namespace render {
light_probe_stage::light_probe_stage(gl::rasterizer& rasterizer, ::resource_manager& resource_manager):
m_rasterizer(&rasterizer)
{
// Build quad VBO and VAO
{
const math::vector2<float> vertex_positions[] =
{
{-1.0f, 1.0f},
{-1.0f, -1.0f},
{ 1.0f, 1.0f},
{ 1.0f, -1.0f}
};
const auto vertex_data = std::as_bytes(std::span{vertex_positions});
const std::size_t vertex_size = 2;
const std::size_t vertex_stride = sizeof(float) * vertex_size;
m_quad_vbo = std::make_unique<gl::vertex_buffer>(gl::buffer_usage::static_draw, vertex_data.size(), vertex_data);
m_quad_vao = std::make_unique<gl::vertex_array>();
// Define position vertex attribute
gl::vertex_attribute position_attribute;
position_attribute.buffer = m_quad_vbo.get();
position_attribute.offset = 0;
position_attribute.stride = vertex_stride;
position_attribute.type = gl::vertex_attribute_type::float_32;
position_attribute.components = 2;
// Bind vertex attributes to VAO
m_quad_vao->bind(render::vertex_attribute::position, position_attribute);
}
// Load cubemap to spherical harmonics shader template
m_cubemap_to_sh_shader_template = resource_manager.load<gl::shader_template>("cubemap-to-sh.glsl");
// Build cubemap to spherical harmonics shader program
rebuild_cubemap_to_sh_shader_program();
}
void light_probe_stage::execute(render::context& ctx)
{
// Get all light probes in the collection
const auto& light_probes = ctx.collection->get_objects(scene::light_probe::object_type_id);
bool state_bound = false;
// For each light probe
std::for_each
(
std::execution::seq,
std::begin(light_probes),
std::end(light_probes),
[&](scene::object_base* object)
{
scene::light_probe& light_probe = static_cast<scene::light_probe&>(*object);
if (!light_probe.is_illuminance_outdated() && !m_reproject_sh)
{
return;
}
// Setup viewport and bind cubemap to spherical harmonics shader program
if (!state_bound)
{
glDisable(GL_BLEND);
m_rasterizer->set_viewport(0, 0, 12, 1);
m_rasterizer->use_program(*m_cubemap_to_sh_shader_program);
state_bound = true;
}
// Bind light probe illuminance framebuffer
m_rasterizer->use_framebuffer(*light_probe.get_illuminance_framebuffer());
// Update cubemap to spherical harmonics cubemap variable with light probe luminance texture
m_cubemap_var->update(*light_probe.get_luminance_texture());
// Draw quad
m_rasterizer->draw_arrays(*m_quad_vao, gl::drawing_mode::triangle_strip, 0, 4);
// Mark light probe illuminance as current
light_probe.set_illuminance_outdated(false);
}
);
m_reproject_sh = false;
}
void light_probe_stage::set_sh_sample_count(std::size_t count)
{
if (m_sh_sample_count != count)
{
m_sh_sample_count = count;
sh_parameters_changed();
}
}
void light_probe_stage::rebuild_cubemap_to_sh_shader_program()
{
m_cubemap_to_sh_shader_program = m_cubemap_to_sh_shader_template->build({{"SAMPLE_COUNT", std::to_string(m_sh_sample_count)}});
if (!m_cubemap_to_sh_shader_program->linked())
{
debug::log::error("Failed to build cubemap to spherical harmonics shader program: {}", m_cubemap_to_sh_shader_program->info());
debug::log::warning("{}", m_cubemap_to_sh_shader_template->configure(gl::shader_stage::vertex));
m_cubemap_var = nullptr;
throw std::runtime_error("Failed to build cubemap to spherical harmonics shader program.");
}
else
{
m_cubemap_var = m_cubemap_to_sh_shader_program->variable("cubemap");
if (!m_cubemap_var)
{
throw std::runtime_error("Cubemap to spherical harmonics shader program has no `cubemap` variable.");
}
}
}
void light_probe_stage::sh_parameters_changed()
{
rebuild_cubemap_to_sh_shader_program();
m_reproject_sh = true;
}
} // namespace render

+ 91
- 0
src/engine/render/stages/light-probe-stage.hpp View File

@ -0,0 +1,91 @@
/*
* Copyright (C) 2023 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_RENDER_LIGHT_PROBE_STAGE_HPP
#define ANTKEEPER_RENDER_LIGHT_PROBE_STAGE_HPP
#include <engine/render/stage.hpp>
#include <engine/gl/shader-template.hpp>
#include <engine/gl/shader-program.hpp>
#include <engine/gl/shader-variable.hpp>
#include <engine/gl/rasterizer.hpp>
#include <engine/gl/vertex-array.hpp>
#include <engine/gl/vertex-buffer.hpp>
#include <engine/resources/resource-manager.hpp>
#include <functional>
#include <memory>
#include <vector>
namespace render {
/**
* Updates light probes.
*/
class light_probe_stage: public stage
{
public:
/**
* Constructs a light probe stage.
*
* @param rasterizer GL rasterizer.
* @param resource_manager Resource manager for loading shader templates.
*
* @exception std::runtime_error Failed to build cubemap to spherical harmonics shader program.
* @exception std::runtime_error Cubemap to spherical harmonics shader program has no `cubemap` variable.
*/
light_probe_stage(gl::rasterizer& rasterizer, ::resource_manager& resource_manager);
void execute(render::context& ctx) override;
/**
* Sets the number of samples to use when projecting cubemaps into spherical harmonics.
*
* @param count Sample count.
*
* @warning Triggers rebuilding of cubemap to spherical harmonics shader program.
* @warning Triggers recalculation of the illuminance of all light probes on next call to `execute()`.
*
* @exception std::runtime_error Failed to build cubemap to spherical harmonics shader program.
* @exception std::runtime_error Cubemap to spherical harmonics shader program has no `cubemap` variable.
*/
void set_sh_sample_count(std::size_t count);
/// Returns the number of samples used when projecting cubemaps into spherical harmonics.
[[nodiscard]] inline std::size_t get_sh_sample_count() const noexcept
{
return m_sh_sample_count;
}
private:
void rebuild_cubemap_to_sh_shader_program();
void sh_parameters_changed();
gl::rasterizer* m_rasterizer;
std::unique_ptr<gl::vertex_buffer> m_quad_vbo;
std::unique_ptr<gl::vertex_array> m_quad_vao;
std::shared_ptr<gl::shader_template> m_cubemap_to_sh_shader_template;
std::unique_ptr<gl::shader_program> m_cubemap_to_sh_shader_program;
const gl::shader_variable* m_cubemap_var{};
std::size_t m_sh_sample_count{1024};
bool m_reproject_sh{true};
};
} // namespace render
#endif // ANTKEEPER_RENDER_LIGHT_PROBE_STAGE_HPP

+ 0
- 34
src/engine/scene/ambient-light.cpp View File

@ -1,34 +0,0 @@
/*
* Copyright (C) 2023 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 <engine/scene/ambient-light.hpp>
namespace scene {
void ambient_light::color_updated()
{
m_colored_illuminance = m_color * m_illuminance;
}
void ambient_light::illuminance_updated()
{
m_colored_illuminance = m_color * m_illuminance;
}
} // namespace scene

+ 0
- 90
src/engine/scene/ambient-light.hpp View File

@ -1,90 +0,0 @@
/*
* Copyright (C) 2023 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_SCENE_AMBIENT_LIGHT_HPP
#define ANTKEEPER_SCENE_AMBIENT_LIGHT_HPP
#include <engine/scene/light.hpp>
#include <engine/math/vector.hpp>
namespace scene {
/**
* Omnidirectional source of illuminance.
*/
class ambient_light: public light
{
public:
[[nodiscard]] inline light_type get_light_type() const noexcept override
{
return light_type::ambient;
}
/**
* Sets the color of the light.
*
* @param color Light color.
*/
inline void set_color(const math::vector3<float>& color) noexcept
{
m_color = color;
color_updated();
}
/**
* Sets the illuminance of the light on a surface perpendicular to the light direction.
*
* @param illuminance Illuminance on a surface perpendicular to the light direction.
*/
inline void set_illuminance(float illuminance) noexcept
{
m_illuminance = illuminance;
illuminance_updated();
}
/// Returns the color of the light.
[[nodiscard]] inline const math::vector3<float>& get_color() const noexcept
{
return m_color;
}
/// Returns the illuminance of the light on a surface perpendicular to the light direction.
[[nodiscard]] inline float get_illuminance() const noexcept
{
return m_illuminance;
}
/// Returns the color-modulated illuminance of the light on a surface perpendicular to the light direction.
[[nodiscard]] inline const math::vector3<float>& get_colored_illuminance() const noexcept
{
return m_colored_illuminance;
}
private:
void color_updated();
void illuminance_updated();
math::vector3<float> m_color{1.0f, 1.0f, 1.0f};
float m_illuminance{};
math::vector3<float> m_colored_illuminance{};
};
} // namespace scene
#endif // ANTKEEPER_SCENE_AMBIENT_LIGHT_HPP

+ 25
- 4
src/engine/scene/camera.cpp View File

@ -63,18 +63,38 @@ float3 camera::unproject(const float3& window, const float4& viewport) const
return math::vector<float, 3>(result) * (1.0f / result[3]);
}
void camera::set_perspective(float fov, float aspect_ratio, float clip_near, float clip_far)
void camera::set_perspective(float vertical_fov, float aspect_ratio, float clip_near, float clip_far)
{
m_orthographic = false;
// Update perspective projection parameters
m_fov = fov;
m_vertical_fov = vertical_fov;
m_aspect_ratio = aspect_ratio;
m_clip_near = clip_near;
m_clip_far = clip_far;
// Recalculate projection matrix
m_projection = math::perspective_half_z(m_fov, m_aspect_ratio, m_clip_far, m_clip_near);
m_projection = math::perspective_half_z(m_vertical_fov, m_aspect_ratio, m_clip_far, m_clip_near);
// Recalculate view-projection matrix
m_view_projection = m_projection * m_view;
m_inverse_view_projection = math::inverse(m_view_projection);
// Recalculate view frustum
update_frustum();
}
void camera::set_vertical_fov(float vertical_fov)
{
if (m_orthographic)
{
return;
}
m_vertical_fov = vertical_fov;
// Recalculate projection matrix
m_projection = math::perspective_half_z(m_vertical_fov, m_aspect_ratio, m_clip_far, m_clip_near);
// Recalculate view-projection matrix
m_view_projection = m_projection * m_view;
@ -110,7 +130,8 @@ void camera::set_orthographic(float clip_left, float clip_right, float clip_bott
void camera::set_exposure_value(float ev100)
{
m_exposure_value = ev100;
m_exposure_normalization = 1.0f / (std::exp2(m_exposure_value) * 1.2f);
// m_exposure_normalization = 1.0f / (std::exp2(m_exposure_value) * 1.2f);
m_exposure_normalization = 1.0f / (std::exp2(m_exposure_value));
}
void camera::transformed()

+ 14
- 7
src/engine/scene/camera.hpp View File

@ -68,13 +68,20 @@ public:
/**
* Sets the camera's projection matrix using perspective projection.
*
* @param fov Vertical field of view.
* @param vertical_fov Vertical field of view, in radians.
* @param aspect_ratio Aspect ratio.
* @param clip_near Distance to near clipping plane.
* @param clip_far Distance to far clipping plane.
*/
void set_perspective(float fov, float aspect_ratio, float clip_near, float clip_far);
void set_perspective(float vertical_fov, float aspect_ratio, float clip_near, float clip_far);
/**
* Sets the camera's vertical field of view.
*
* @param vertical_fov Vertical field of view, in radians.
*/
void set_vertical_fov(float vertical_fov);
/**
* Sets the camera's projection matrix using orthographic projection.
*
@ -181,10 +188,10 @@ public:
return m_clip_far;
}
/// Returns the camera's field of view, in radians.
[[nodiscard]] inline float get_fov() const noexcept
/// Returns the camera's vertical field of view, in radians.
[[nodiscard]] inline float get_vertical_fov() const noexcept
{
return m_fov;
return m_vertical_fov;
}
/// Returns the camera's aspect ratio.
@ -262,7 +269,7 @@ private:
float m_clip_top{1.0f};
float m_clip_near{-1.0f};
float m_clip_far{1.0f};
float m_fov{math::half_pi<float>};
float m_vertical_fov{math::half_pi<float>};
float m_aspect_ratio{1.0f};
float m_exposure_value{0.0f};
float m_exposure_normalization{1.0f / 1.2f};

+ 70
- 0
src/engine/scene/light-probe.cpp View File

@ -0,0 +1,70 @@
/*
* Copyright (C) 2023 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 <engine/scene/light-probe.hpp>
namespace scene {
light_probe::light_probe()
{
// Allocate illuminance texture
m_illuminance_texture = std::make_shared<gl::texture_1d>(12, gl::pixel_type::float_32, gl::pixel_format::rgba);
m_illuminance_texture->set_filters(gl::texture_min_filter::nearest, gl::texture_mag_filter::nearest);
// Allocate and init illuminance framebuffer
m_illuminance_framebuffer = std::make_shared<gl::framebuffer>(12, 1);
m_illuminance_framebuffer->attach(gl::framebuffer_attachment_type::color, m_illuminance_texture.get());
// Init illuminance matrices
m_illuminance_matrices[0] = {};
m_illuminance_matrices[1] = {};
m_illuminance_matrices[2] = {};
}
void light_probe::update_illuminance_matrices()
{
m_illuminance_texture->read(std::as_writable_bytes(std::span{m_illuminance_matrices}), gl::pixel_type::float_32, gl::pixel_format::rgba, 0);
}
void light_probe::set_luminance_texture(std::shared_ptr<gl::texture_cube> texture)
{
if (m_luminance_texture != texture)
{
m_luminance_texture = texture;
set_luminance_outdated(true);
set_illuminance_outdated(true);
}
}
void light_probe::set_luminance_outdated(bool outdated)
{
m_luminance_outdated = outdated;
}
void light_probe::set_illuminance_outdated(bool outdated)
{
m_illuminance_outdated = outdated;
}
void light_probe::transformed()
{
m_bounds = {get_translation(), get_translation()};
}
} // namespace scene

+ 139
- 0
src/engine/scene/light-probe.hpp View File

@ -0,0 +1,139 @@
/*
* Copyright (C) 2023 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_SCENE_LIGHT_PROBE_HPP
#define ANTKEEPER_SCENE_LIGHT_PROBE_HPP
#include <engine/scene/object.hpp>
#include <engine/gl/texture-1d.hpp>
#include <engine/gl/texture-cube.hpp>
#include <engine/gl/framebuffer.hpp>
#include <engine/math/matrix.hpp>
#include <memory>
#include <span>
namespace scene {
/**
*
*/
class light_probe: public object<light_probe>
{
public:
/// Constructs a light probe.
light_probe();
/**
* Updates the light probe's illuminance matrices from its illuminance texture.
*
* @warning Reads texture data from the GPU.
*/
void update_illuminance_matrices();
/**
* Sets the light probe's luminance texture.
*
* @param texture Luminance cubemap texture.
*
* @note Marks the light probe's luminance as outdated if the luminance texture has changed.
* @note Marks the light probe's illuminance as outdated if the luminance texture has changed.
*/
void set_luminance_texture(std::shared_ptr<gl::texture_cube> texture);
/**
* Marks the light probe's luminance as either outdated or current.
*
* @param outdated `true` if the light probe's luminance is outdated, `false` otherwise.
*/
void set_luminance_outdated(bool outdated);
/**
* Marks the light probe's illuminance as either outdated or current.
*
* @param outdated `true` if the light probe's illuminance is outdated, `false` otherwise.
*/
void set_illuminance_outdated(bool outdated);
/// Returns the light probe's luminance texture.
[[nodiscard]] inline const std::shared_ptr<gl::texture_cube>& get_luminance_texture() const noexcept
{
return m_luminance_texture;
}
/**
* Returns the light probe's illuminance texture.
*
* The illuminance texture is a 12x1 RGBA floating-point LUT which encodes the column vectors of three spherical harmonics illuminance matrices in the layout `R0,R1,R2,R3,G0,G1,G2,G3,B0,B1,B2,B3`. The matrices `R`, `G`, and `B` can be used to recover illuminance of the red, green, and blue color channels, respectively, for a given surface normal, `n`, as follows: `(dot(n, R * n), dot(n, G * n), dot(n, B * n))`, where `n = (x, y, z, 1)`.
*/
[[nodiscard]] inline const std::shared_ptr<gl::texture_1d>& get_illuminance_texture() const noexcept
{
return m_illuminance_texture;
}
/// Returns the light probe's illuminance framebuffer.
[[nodiscard]] inline const std::shared_ptr<gl::framebuffer>& get_illuminance_framebuffer() const noexcept
{
return m_illuminance_framebuffer;
}
/**
* Returns the light probe's illuminance matrices.
*
* @return Red, green, and blue illuminance matrices.
*
* @warning The light probe's illuminance matrices must first be updated.
*
* @see light_probe::update_illuminance_matrices()
*/
[[nodiscard]] inline std::span<const math::matrix4<float>, 3> get_illuminance_matrices() const noexcept
{
return m_illuminance_matrices;
}
/// Returns `true` if the light probe's luminance is outdated.
[[nodiscard]] inline bool is_luminance_outdated() const noexcept
{
return m_luminance_outdated;
}
/// Returns `true` if the light probe's illuminance is outdated.
[[nodiscard]] inline bool is_illuminance_outdated() const noexcept
{
return m_illuminance_outdated;
}
[[nodiscard]] inline const aabb_type& get_bounds() const noexcept override
{
return m_bounds;
}
private:
void transformed() override;
aabb_type m_bounds{};
std::shared_ptr<gl::texture_cube> m_luminance_texture;
std::shared_ptr<gl::texture_1d> m_illuminance_texture;
std::shared_ptr<gl::framebuffer> m_illuminance_framebuffer;
math::matrix4<float> m_illuminance_matrices[3];
bool m_luminance_outdated{};
bool m_illuminance_outdated{};
};
} // namespace scene
#endif // ANTKEEPER_SCENE_LIGHT_PROBE_HPP

+ 1
- 7
src/engine/scene/light-type.hpp View File

@ -27,9 +27,6 @@ namespace scene {
/// Light types.
enum class light_type: std::uint8_t
{
/// Ambient light.
ambient,
/// Directional light.
directional,
@ -40,10 +37,7 @@ enum class light_type: std::uint8_t
point,
/// Rectangle light.
rectangle,
/// Sky light.
sky
rectangle
};
} // namespace scene

+ 3
- 3
src/engine/scene/light.hpp View File

@ -34,14 +34,14 @@ public:
/// Returns an enumeration denoting the light object type.
[[nodiscard]] virtual light_type get_light_type() const noexcept = 0;
inline const aabb_type& get_bounds() const noexcept override
[[nodiscard]] inline const aabb_type& get_bounds() const noexcept override
{
return m_bounds;
}
private:
virtual void transformed();
aabb_type m_bounds{{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}};
void transformed() override;
aabb_type m_bounds{};
};
} // namespace scene

+ 0
- 25
src/engine/scene/sky-light.cpp View File

@ -1,25 +0,0 @@
/*
* Copyright (C) 2023 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 <engine/scene/sky-light.hpp>
namespace scene {
} // namespace scene

+ 0
- 47
src/engine/scene/sky-light.hpp View File

@ -1,47 +0,0 @@
/*
* Copyright (C) 2023 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_SCENE_SKY_LIGHT_HPP
#define ANTKEEPER_SCENE_SKY_LIGHT_HPP
#include <engine/scene/light.hpp>
#include <engine/math/vector.hpp>
namespace scene {
/**
*
*/
class sky_light: public light
{
public:
[[nodiscard]] inline light_type get_light_type() const noexcept override
{
return light_type::sky;
}
private:
};
} // namespace scene
#endif // ANTKEEPER_SCENE_SKY_LIGHT_HPP

+ 2
- 2
src/game/components/atmosphere-component.hpp View File

@ -74,8 +74,8 @@ struct atmosphere_component
/// (Dependent) Ozone absorption coefficients.
double3 ozone_absorption;
/// Airglow illuminance, in lux.
double3 airglow_illuminance;
/// Airglow luminance, in cd/m^2.
double3 airglow_luminance;
};

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

@ -159,6 +159,15 @@ void reset_control_profile(::control_profile& profile)
// Save camera
mappings.emplace("save_camera", std::make_unique<input::key_mapping>(nullptr, input::scancode::left_ctrl, 0, false));
mappings.emplace("save_camera", std::make_unique<input::key_mapping>(nullptr, input::scancode::right_ctrl, 0, false));
// Adjust exposure
mappings.emplace("adjust_exposure", std::make_unique<input::key_mapping>(nullptr, input::scancode::b, 0, false));
// Adjust time
mappings.emplace("adjust_time", std::make_unique<input::key_mapping>(nullptr, input::scancode::t, 0, false));
// Adjust time
mappings.emplace("adjust_zoom", std::make_unique<input::key_mapping>(nullptr, input::scancode::z, 0, false));
}
void apply_control_profile(::game& ctx, const ::control_profile& profile)
@ -215,6 +224,9 @@ void apply_control_profile(::game& ctx, const ::control_profile& profile)
add_mappings(ctx.keeper_action_map, ctx.camera_9_action, "camera_9");
add_mappings(ctx.keeper_action_map, ctx.camera_10_action, "camera_10");
add_mappings(ctx.keeper_action_map, ctx.save_camera_action, "save_camera");
add_mappings(ctx.keeper_action_map, ctx.adjust_exposure_action, "adjust_exposure");
add_mappings(ctx.keeper_action_map, ctx.adjust_time_action, "adjust_time");
add_mappings(ctx.keeper_action_map, ctx.adjust_zoom_action, "adjust_zoom");
}
void update_control_profile(::game& ctx, ::control_profile& profile)
@ -295,6 +307,9 @@ void update_control_profile(::game& ctx, ::control_profile& profile)
add_mappings(ctx.keeper_action_map, ctx.camera_9_action, "camera_9");
add_mappings(ctx.keeper_action_map, ctx.camera_10_action, "camera_10");
add_mappings(ctx.keeper_action_map, ctx.save_camera_action, "save_camera");
add_mappings(ctx.keeper_action_map, ctx.adjust_exposure_action, "adjust_exposure");
add_mappings(ctx.keeper_action_map, ctx.adjust_time_action, "adjust_time");
add_mappings(ctx.keeper_action_map, ctx.adjust_zoom_action, "adjust_zoom");
}
void setup_window_controls(::game& ctx)
@ -608,5 +623,8 @@ void disable_keeper_controls(::game& ctx)
ctx.mouse_grip_action.reset();
ctx.mouse_zoom_action.reset();
ctx.focus_action.reset();
ctx.adjust_exposure_action.reset();
ctx.adjust_time_action.reset();
ctx.adjust_zoom_action.reset();
}

+ 6
- 4
src/game/game.cpp View File

@ -737,11 +737,12 @@ void game::setup_rendering()
surface_clear_pass = std::make_unique<render::clear_pass>(window->get_rasterizer(), hdr_framebuffer.get());
surface_clear_pass->set_clear_color({0.0f, 0.0f, 0.0f, 1.0f});
surface_clear_pass->set_cleared_buffers(true, true, false);
surface_clear_pass->set_clear_depth(-1.0f);
surface_clear_pass->set_clear_stencil(0);
surface_clear_pass->set_cleared_buffers(true, true, true);
sky_pass = std::make_unique<render::sky_pass>(window->get_rasterizer(), hdr_framebuffer.get(), resource_manager.get());
sky_pass->set_magnification(3.0f);
// sky_pass->set_magnification(3.0f);
ground_pass = std::make_unique<render::ground_pass>(window->get_rasterizer(), hdr_framebuffer.get(), resource_manager.get());
@ -786,7 +787,7 @@ void game::setup_rendering()
}
// Create renderer
renderer = std::make_unique<render::renderer>();
renderer = std::make_unique<render::renderer>(*window->get_rasterizer(), *resource_manager);
debug::log::trace("Set up rendering");
}
@ -987,7 +988,7 @@ void game::setup_ui()
// Update camera projection matrix
surface_camera->set_perspective
(
surface_camera->get_fov(),
surface_camera->get_vertical_fov(),
viewport_aspect_ratio,
surface_camera->get_clip_near(),
surface_camera->get_clip_far()
@ -1085,6 +1086,7 @@ void game::setup_systems()
// RGB wavelengths for atmospheric scatteering
rgb_wavelengths = {680, 550, 440};
// rgb_wavelengths = {602.21436, 541.0647, 448.14404};
// Setup atmosphere system
atmosphere_system = std::make_unique<::atmosphere_system>(*entity_registry);

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

@ -51,7 +51,6 @@
#include <engine/scene/directional-light.hpp>
#include <engine/scene/rectangle-light.hpp>
#include <engine/scene/spot-light.hpp>
#include <engine/scene/ambient-light.hpp>
#include <engine/scene/camera.hpp>
#include <engine/scene/billboard.hpp>
#include <engine/scene/collection.hpp>
@ -239,6 +238,9 @@ public:
input::action camera_9_action;
input::action camera_10_action;
input::action save_camera_action;
input::action adjust_exposure_action;
input::action adjust_time_action;
input::action adjust_zoom_action;
std::vector<std::shared_ptr<::event::subscription>> window_action_subscriptions;
std::vector<std::shared_ptr<::event::subscription>> menu_action_subscriptions;
@ -332,11 +334,9 @@ public:
std::shared_ptr<scene::camera> surface_camera;
std::unique_ptr<scene::directional_light> sun_light;
std::unique_ptr<scene::directional_light> moon_light;
std::unique_ptr<scene::ambient_light> sky_light;
std::unique_ptr<scene::collection> underground_scene;
std::shared_ptr<scene::camera> underground_camera;
std::unique_ptr<scene::directional_light> underground_directional_light;
std::unique_ptr<scene::ambient_light> underground_ambient_light;
std::unique_ptr<scene::rectangle_light> underground_rectangle_light;
scene::collection* active_scene;

+ 5
- 5
src/game/loaders/entity-archetype-loader.cpp View File

@ -68,12 +68,12 @@ static bool load_component_atmosphere(entity::archetype& archetype, const json&
if (element.contains("ozone_mode"))
component.ozone_mode = element["ozone_mode"].get<double>();
if (element.contains("airglow_illuminance"))
if (element.contains("airglow_luminance"))
{
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>();
const auto& airglow_luminance = element["airglow_luminance"];
component.airglow_luminance.x() = airglow_luminance[0].get<double>();
component.airglow_luminance.y() = airglow_luminance[1].get<double>();
component.airglow_luminance.z() = airglow_luminance[2].get<double>();
}
archetype.stamps.push_back

+ 151
- 1
src/game/states/nest-selection-state.cpp View File

@ -207,7 +207,7 @@ nest_selection_state::nest_selection_state(::game& ctx):
ctx.ui_clear_pass->set_cleared_buffers(false, true, false);
// Set world time
::world::set_time(ctx, 2022, 6, 21, 18, 0, 0.0);
::world::set_time(ctx, 2022, 6, 21, 12, 0, 0.0);
// Init time scale
double time_scale = 60.0;
@ -296,6 +296,24 @@ nest_selection_state::nest_selection_state(::game& ctx):
ctx.entity_registry->emplace<rigid_body_constraint_component>(spring_eid, std::move(spring));
*/
sky_probe = std::make_shared<scene::light_probe>();
sky_probe->set_luminance_texture(std::make_shared<gl::texture_cube>(384, 512, gl::pixel_type::float_16, gl::pixel_format::rgb));
ctx.sky_pass->set_sky_probe(sky_probe);
ctx.surface_scene->add_object(*sky_probe);
// Create sphere
auto sphere_eid = ctx.entity_registry->create();
auto sphere_static_mesh = std::make_shared<scene::static_mesh>(ctx.resource_manager->load<render::model>("sphere.mdl"));
ctx.entity_registry->emplace<scene_component>(sphere_eid, std::move(sphere_static_mesh), std::uint8_t{1});
ctx.entity_registry->patch<scene_component>
(
sphere_eid,
[&](auto& component)
{
component.object->set_translation({0.0f, 10.0f, 0.0f});
}
);
// Queue enable game controls
ctx.function_queue.push
(
@ -494,6 +512,102 @@ void nest_selection_state::setup_controls()
)
);
// Enable/toggle mouse look
action_subscriptions.emplace_back
(
ctx.mouse_pick_action.get_activated_channel().subscribe
(
[&](const auto& event)
{
mouse_drag = true;
}
)
);
// Disable mouse look
action_subscriptions.emplace_back
(
ctx.mouse_pick_action.get_deactivated_channel().subscribe
(
[&](const auto& event)
{
mouse_drag = false;
}
)
);
// Enable/toggle adjust exposure
action_subscriptions.emplace_back
(
ctx.adjust_exposure_action.get_activated_channel().subscribe
(
[&](const auto& event)
{
adjust_exposure = true;
}
)
);
// Disable adjust exposure
action_subscriptions.emplace_back
(
ctx.adjust_exposure_action.get_deactivated_channel().subscribe
(
[&](const auto& event)
{
adjust_exposure = false;
}
)
);
// Enable/toggle adjust time
action_subscriptions.emplace_back
(
ctx.adjust_time_action.get_activated_channel().subscribe
(
[&](const auto& event)
{
adjust_time = true;
}
)
);
// Disable adjust time
action_subscriptions.emplace_back
(
ctx.adjust_time_action.get_deactivated_channel().subscribe
(
[&](const auto& event)
{
adjust_time = false;
}
)
);
// Enable/toggle adjust zoom
action_subscriptions.emplace_back
(
ctx.adjust_zoom_action.get_activated_channel().subscribe
(
[&](const auto& event)
{
adjust_zoom = true;
}
)
);
// Disable adjust zoom
action_subscriptions.emplace_back
(
ctx.adjust_zoom_action.get_deactivated_channel().subscribe
(
[&](const auto& event)
{
adjust_zoom = false;
}
)
);
constexpr float movement_speed = 200.0f;
auto move_first_person_camera_rig = [&](const float2& direction, float speed)
@ -545,6 +659,42 @@ void nest_selection_state::setup_controls()
(
[&, move_first_person_camera_rig](const auto& event)
{
if (adjust_time)
{
const double sensitivity = 1.0 / static_cast<double>(ctx.window->get_viewport_size().x());
const double t = ctx.astronomy_system->get_time();
::world::set_time(ctx, t + static_cast<double>(event.difference.x()) * sensitivity);
/*
sky_probe->update_illuminance_matrices();
const auto matrices = sky_probe->get_illuminance_matrices();
for (std::size_t i = 0; i < 3; ++i)
{
const auto m = matrices[i];
debug::log::warning("\nmat4({},{},{},{},\n{},{},{},{},\n{},{},{},{},\n{},{},{},{});", m[0][0], m[0][1], m[0][2], m[0][3], m[1][0], m[1][1], m[1][2], m[1][3], m[2][0], m[2][1], m[2][2], m[2][3], m[3][0], m[3][1], m[3][2], m[3][3]);
}
*/
}
if (adjust_exposure)
{
const float sensitivity = 8.0f / static_cast<float>(ctx.window->get_viewport_size().y());
ctx.surface_camera->set_exposure_value(ctx.surface_camera->get_exposure_value() + static_cast<float>(event.difference.y()) * sensitivity);
}
if (adjust_zoom)
{
const float sensitivity = math::radians(45.0f) / static_cast<float>(ctx.window->get_viewport_size().y());
const float min_hfov = math::radians(1.0f);
const float max_hfov = math::radians(90.0f);
const float aspect_ratio = ctx.surface_camera->get_aspect_ratio();
const float hfov = std::min<float>(std::max<float>(math::horizontal_fov(ctx.surface_camera->get_vertical_fov(), aspect_ratio) + static_cast<float>(event.difference.y()) * sensitivity, min_hfov), max_hfov);
const float vfov = math::vertical_fov(hfov, aspect_ratio);
ctx.surface_camera->set_vertical_fov(vfov);
}
if (!mouse_look)
{
return;

+ 7
- 0
src/game/states/nest-selection-state.hpp View File

@ -25,6 +25,7 @@
#include <engine/utility/fundamental-types.hpp>
#include <engine/render/model.hpp>
#include <engine/animation/ik/solvers/ccd-ik-solver.hpp>
#include <engine/scene/light-probe.hpp>
class nest_selection_state: public game_state
{
@ -48,6 +49,10 @@ private:
std::shared_ptr<render::model> worker_model;
bool mouse_look{false};
bool mouse_drag{false};
bool adjust_exposure{false};
bool adjust_time{false};
bool adjust_zoom{false};
bool moving{false};
float2 movement_direction{0.0f, 0.0f};
@ -74,6 +79,8 @@ private:
double first_person_camera_pitch{0.0};
std::shared_ptr<ccd_ik_solver> larva_ik_solver;
std::shared_ptr<scene::light_probe> sky_probe;
};
#endif // ANTKEEPER_NEST_SELECTION_STATE_HPP

+ 17
- 10
src/game/states/nest-view-state.cpp View File

@ -85,7 +85,7 @@
nest_view_state::nest_view_state(::game& ctx):
game_state(ctx)
{
debug::log::trace("Entering nest selection state...");
debug::log::trace("Entering nest view state...");
// Create world if not yet created
if (ctx.entities.find("earth") == ctx.entities.end())
@ -125,11 +125,10 @@ nest_view_state::nest_view_state(::game& ctx):
// ctx.underground_directional_light->set_shadow_cascade_distribution(0.8f);
// ctx.underground_scene->add_object(*ctx.underground_directional_light);
// Create ambient light
ctx.underground_ambient_light = std::make_unique<scene::ambient_light>();
ctx.underground_ambient_light->set_color({1.0f, 1.0f, 1.0f});
ctx.underground_ambient_light->set_illuminance(0.075f);
ctx.underground_scene->add_object(*ctx.underground_ambient_light);
ctx.underground_clear_pass->set_clear_color({0.214f, 0.214f, 0.214f, 1.0f});
light_probe = std::make_shared<scene::light_probe>();
light_probe->set_luminance_texture(ctx.resource_manager->load<gl::texture_cube>("grey-furnace.tex"));
ctx.underground_scene->add_object(*light_probe);
//const float color_temperature = 5000.0f;
//const math::vector3<float> light_color = color::aces::ap1<float>.from_xyz * color::cat::matrix(color::illuminant::deg2::d50<float>, color::aces::white_point<float>) * color::cct::to_xyz(color_temperature);
@ -183,6 +182,14 @@ nest_view_state::nest_view_state(::game& ctx):
// Create cocoon
auto cocoon_eid = ctx.entity_registry->create();
ctx.entity_registry->emplace<scene_component>(cocoon_eid, std::make_shared<scene::static_mesh>(worker_phenome.cocoon->model), std::uint8_t{2});
ctx.entity_registry->patch<scene_component>
(
cocoon_eid,
[&](auto& component)
{
component.object->set_translation({-5.0f, 0.0f, 5.0f});
}
);
// Create larva
auto larva_eid = ctx.entity_registry->create();
@ -206,7 +213,7 @@ nest_view_state::nest_view_state(::game& ctx):
suzanne_eid,
[&](auto& component)
{
component.object->set_translation({0.0f, 0.0f, 0.0f});
component.object->set_translation({-13.0f, 0.0f, -5.0f});
}
);
@ -264,12 +271,12 @@ nest_view_state::nest_view_state(::game& ctx):
// Refresh frame scheduler
ctx.frame_scheduler.refresh();
debug::log::trace("Entered nest selection state");
debug::log::trace("Entered nest view state");
}
nest_view_state::~nest_view_state()
{
debug::log::trace("Exiting nest selection state...");
debug::log::trace("Exiting nest view state...");
// Disable game controls
::disable_game_controls(ctx);
@ -277,7 +284,7 @@ nest_view_state::~nest_view_state()
destroy_third_person_camera_rig();
debug::log::trace("Exited nest selection state");
debug::log::trace("Exited nest view state");
}
void nest_view_state::create_third_person_camera_rig()

+ 2
- 0
src/game/states/nest-view-state.hpp View File

@ -29,6 +29,7 @@
#include <engine/geom/primitives/ray.hpp>
#include <engine/geom/primitives/plane.hpp>
#include <engine/math/angles.hpp>
#include <engine/scene/light-probe.hpp>
class nest_view_state: public game_state
{
@ -105,6 +106,7 @@ private:
std::vector<std::optional<camera_preset>> camera_presets{10};
std::shared_ptr<render::material_float3> light_rectangle_emissive;
std::shared_ptr<scene::light_probe> light_probe;
};
#endif // ANTKEEPER_NEST_VIEW_STATE_HPP

+ 75
- 49
src/game/systems/astronomy-system.cpp View File

@ -47,7 +47,6 @@ astronomy_system::astronomy_system(entity::registry& registry):
reference_body_eid(entt::null),
transmittance_samples(0),
sun_light(nullptr),
sky_light(nullptr),
moon_light(nullptr),
sky_pass(nullptr),
starlight_illuminance{0, 0, 0}
@ -91,8 +90,6 @@ astronomy_system::~astronomy_system()
void astronomy_system::update(float t, float dt)
{
double3 sky_light_illuminance = {0.0, 0.0, 0.0};
// Add scaled timestep to current time
set_time(time_days + dt * time_scale);
@ -119,6 +116,11 @@ void astronomy_system::update(float t, float dt)
if (!reference_body || !reference_orbit)
return;
// if (sky_pass)
// {
// sky_pass->set_ground_albedo(math::vector3<float>{1.0f, 1.0f, 1.0f} * static_cast<float>(reference_body->albedo));
// }
// Update ICRF to EUS transformation
update_icrf_to_eus(*reference_body, *reference_orbit);
@ -183,7 +185,7 @@ void astronomy_system::update(float t, float dt)
const geom::ray<double, 3> ray = {{0, 0, 0}, observer_blackbody_direction_eus};
// Integrate atmospheric spectral transmittance factor between observer and blackbody
const double3 transmittance = integrate_transmittance(*observer, *reference_body, *reference_atmosphere, ray);
double3 transmittance = integrate_transmittance(*observer, *reference_body, *reference_atmosphere, ray);
// Attenuate illuminance from blackbody reaching observer by spectral transmittance factor
observer_blackbody_transmitted_illuminance *= transmittance;
@ -203,25 +205,16 @@ void astronomy_system::update(float t, float dt)
);
sun_light->set_illuminance(static_cast<float>(math::max(observer_blackbody_transmitted_illuminance)));
sun_light->set_color(math::vector3<float>(observer_blackbody_transmitted_illuminance / math::max(observer_blackbody_transmitted_illuminance)));
}
// Update sky light
if (sky_light != nullptr)
{
// Calculate sky illuminance
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_illuminance, sky_illuminance};
// Add starlight illuminance to sky light illuminance
sky_light_illuminance += starlight_illuminance;
// Update sky light
sky_light->set_illuminance(static_cast<float>(math::max(sky_light_illuminance)));
sky_light->set_color(math::vector3<float>(sky_light_illuminance / math::max(sky_light_illuminance)));
const auto max_component = math::max(observer_blackbody_transmitted_illuminance);
if (max_component > 0.0)
{
sun_light->set_color(math::vector3<float>(observer_blackbody_transmitted_illuminance / max_component));
}
else
{
sun_light->set_color({});
}
}
// Upload blackbody params to sky pass
@ -274,8 +267,8 @@ void astronomy_system::update(float t, float dt)
double3 observer_reflector_transmittance = {1, 1, 1};
if (reference_atmosphere)
{
const geom::ray<double, 3> ray = {{0, 0, 0}, observer_reflector_direction_eus};
observer_reflector_transmittance = integrate_transmittance(*observer, *reference_body, *reference_atmosphere, ray);
// const geom::ray<double, 3> 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
@ -302,14 +295,23 @@ void astronomy_system::update(float t, float dt)
this->sky_pass->set_moon_illuminance(float3(observer_reflector_illuminance / observer_reflector_transmittance), float3(observer_reflector_illuminance));
}
if (this->moon_light)
if (moon_light)
{
const float3 reflector_up_eus = float3(icrf_to_eus.r * double3{0, 0, 1});
this->moon_light->set_illuminance(static_cast<float>(math::max(observer_reflector_illuminance)));
this->moon_light->set_color(math::vector3<float>(observer_reflector_illuminance / math::max(observer_reflector_illuminance)));
moon_light->set_illuminance(static_cast<float>(math::max(observer_reflector_illuminance)));
const auto max_component = math::max(observer_reflector_illuminance);
if (max_component > 0.0)
{
moon_light->set_color(math::vector3<float>(observer_reflector_illuminance / max_component));
}
else
{
moon_light->set_color({});
}
this->moon_light->set_rotation
moon_light->set_rotation
(
math::look_rotation
(
@ -356,11 +358,6 @@ void astronomy_system::set_sun_light(scene::directional_light* light)
sun_light = light;
}
void astronomy_system::set_sky_light(scene::ambient_light* light)
{
sky_light = light;
}
void astronomy_system::set_moon_light(scene::directional_light* light)
{
moon_light = light;
@ -391,9 +388,15 @@ void astronomy_system::set_sky_pass(::render::sky_pass* pass)
const auto reference_body = registry.try_get<celestial_body_component>(reference_body_eid);
if (reference_body)
{
sky_pass->set_planet_radius(static_cast<float>(reference_body->radius));
// sky_pass->set_ground_albedo(math::vector3<float>{1.0f, 1.0f, 1.0f} * static_cast<float>(reference_body->albedo));
}
else
{
sky_pass->set_planet_radius(0.0f);
// sky_pass->set_ground_albedo({0.0f, 0.0f, 0.0f});
}
}
}
}
@ -560,7 +563,7 @@ void astronomy_system::update_icrf_to_eus(const ::celestial_body_component& body
double3 astronomy_system::integrate_transmittance(const ::observer_component& observer, const ::celestial_body_component& body, const ::atmosphere_component& atmosphere, geom::ray<double, 3> ray) const
{
double3 transmittance = {1, 1, 1};
math::vector3<double> transmittance = {1, 1, 1};
// Make ray height relative to center of reference body
ray.origin.y() += body.radius + observer.elevation;
@ -572,24 +575,47 @@ double3 astronomy_system::integrate_transmittance(const ::observer_component& ob
// Check for intersection between the ray and atmosphere
auto intersection = geom::intersection(ray, atmosphere_sphere);
if (intersection)
if (intersection && std::get<1>(*intersection) > 0.0)
{
// Get point of intersection
const double3 intersection_point = ray.extrapolate(std::get<1>(*intersection));
// Determine height at ray origin and cosine of the angle between the ray direction and local zenith direction at ray origin
const double height = math::length(ray.origin);
const double cos_view_zenith = math::dot(ray.direction, ray.origin) / height;
// Precalculate terms re-used in sample height calculation
const double sqr_height = height * height;
const double height_cos_view_zenith = height * cos_view_zenith;
const double two_height_cos_view_zenith = 2.0 * height_cos_view_zenith;
// Get distance to upper limit of atmosphere
const double sample_end_distance = std::get<1>(*intersection);
// Integrate atmospheric particle densities
math::vector3<double> densities{};
double previous_sample_distance = 0.0;
for (std::size_t i = 0; i < transmittance_samples; ++i)
{
// Determine distance along sample ray to sample point and length of the sample
const double sample_distance = (static_cast<double>(i) + 0.5) / static_cast<double>(transmittance_samples) * sample_end_distance;
const double sample_length = sample_distance - previous_sample_distance;
previous_sample_distance = sample_distance;
// Calculate sample elevation
const double sample_height = std::sqrt(sample_distance * sample_distance + sqr_height + two_height_cos_view_zenith * sample_distance);
const double sample_elevation = sample_height - body.radius;
// Weigh and sum atmospheric particle densities at sample elevation
densities.x() += physics::gas::atmosphere::density::exponential(1.0, sample_elevation, atmosphere.rayleigh_scale_height) * sample_length;
densities.y() += physics::gas::atmosphere::density::exponential(1.0, sample_elevation, atmosphere.mie_scale_height) * sample_length;
densities.x() += physics::gas::atmosphere::density::triangular(1.0, sample_elevation, atmosphere.ozone_lower_limit, atmosphere.ozone_upper_limit, atmosphere.ozone_mode) * sample_length;
}
// 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 extinction coefficients from integrated atmospheric particle densities
const math::vector3<double> extinction = densities.x() * atmosphere.rayleigh_scattering +
densities.y() * atmosphere.mie_extinction +
densities.z() * atmosphere.ozone_absorption;
// 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());
// Calculate transmittance factor from extinction coefficients
transmittance = {std::exp(-extinction.x()), std::exp(-extinction.y()), std::exp(-extinction.z())};
}
return transmittance;

+ 5
- 3
src/game/systems/astronomy-system.hpp View File

@ -23,7 +23,6 @@
#include "game/systems/updatable-system.hpp"
#include <engine/entity/id.hpp>
#include <engine/scene/directional-light.hpp>
#include <engine/scene/ambient-light.hpp>
#include <engine/utility/fundamental-types.hpp>
#include <engine/math/se3.hpp>
#include <engine/render/passes/sky-pass.hpp>
@ -81,11 +80,15 @@ public:
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_starlight_illuminance(const double3& illuminance);
void set_sky_pass(::render::sky_pass* pass);
[[nodiscard]] inline double get_time() const noexcept
{
return time_days;
}
private:
void on_observer_modified(entity::registry& registry, entity::id entity_id);
void on_observer_destroyed(entity::registry& registry, entity::id entity_id);
@ -152,7 +155,6 @@ private:
math::transformation::se3<double> icrf_to_eus;
scene::directional_light* sun_light;
scene::ambient_light* sky_light;
scene::directional_light* moon_light;
::render::sky_pass* sky_pass;
double3 starlight_illuminance;

+ 1
- 1
src/game/systems/atmosphere-system.cpp View File

@ -144,7 +144,7 @@ void atmosphere_system::update_sky_pass()
sky_pass->set_rayleigh_parameters(static_cast<float>(component->rayleigh_scale_height), math::vector<float, 3>(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_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::vector<float, 3>(component->ozone_absorption));
sky_pass->set_airglow_illuminance(math::vector<float, 3>(component->airglow_illuminance));
sky_pass->set_airglow_luminance(math::vector<float, 3>(component->airglow_luminance));
}
void atmosphere_system::on_atmosphere_construct(entity::registry& registry, entity::id entity_id)

+ 2
- 7
src/game/world.cpp View File

@ -63,7 +63,6 @@
#include <engine/utility/image.hpp>
#include <engine/utility/json.hpp>
#include <engine/resources/resource-manager.hpp>
#include <engine/scene/ambient-light.hpp>
#include <engine/scene/directional-light.hpp>
#include <engine/scene/text.hpp>
#include <algorithm>
@ -169,7 +168,7 @@ void set_time(::game& ctx, double t)
ctx.astronomy_system->set_time(t);
ctx.orbit_system->set_time(t);
debug::log::info("Set time to UT1 {}", t);
// debug::log::info("Set time to UT1 {}", t);
}
catch (const std::exception& e)
{
@ -368,16 +367,11 @@ void create_sun(::game& ctx)
ctx.sun_light->set_shadow_cascade_coverage(0.15f);
ctx.sun_light->set_shadow_cascade_distribution(0.8f);
// Create sky ambient light scene object
ctx.sky_light = std::make_unique<scene::ambient_light>();
// Add sun light scene objects to surface scene
ctx.surface_scene->add_object(*ctx.sun_light);
ctx.surface_scene->add_object(*ctx.sky_light);
// Pass direct sun light scene object to shadow map pass and astronomy system
ctx.astronomy_system->set_sun_light(ctx.sun_light.get());
ctx.astronomy_system->set_sky_light(ctx.sky_light.get());
}
debug::log::trace("Generated Sun");
@ -517,6 +511,7 @@ void enter_ecoregion(::game& ctx, const ecoregion& ecoregion)
// Setup sky
ctx.sky_pass->set_sky_model(ctx.resource_manager->load<render::model>("celestial-hemisphere.mdl"));
ctx.sky_pass->set_ground_albedo(ecoregion.terrain_albedo);
auto terrestrial_hemisphere_model = ctx.resource_manager->load<render::model>("terrestrial-hemisphere.mdl");
terrestrial_hemisphere_model->get_groups().front().material = ecoregion.horizon_material;
ctx.ground_pass->set_ground_model(terrestrial_hemisphere_model);

Loading…
Cancel
Save