Browse Source

Add rectangle area light. Replace sphere light with point light. Improve interface of all light classes

master
C. J. Howard 1 year ago
parent
commit
1a6cfa65ff
33 changed files with 749 additions and 429 deletions
  1. +0
    -1
      CMakeLists.txt
  2. +6
    -6
      src/engine/color/cat.hpp
  3. +5
    -5
      src/engine/color/rgb.hpp
  4. +15
    -15
      src/engine/color/srgb.hpp
  5. +4
    -15
      src/engine/physics/light/blackbody.hpp
  6. +6
    -0
      src/engine/render/passes/final-pass.cpp
  7. +71
    -51
      src/engine/render/passes/material-pass.cpp
  8. +13
    -4
      src/engine/render/passes/material-pass.hpp
  9. +18
    -3
      src/engine/render/passes/sky-pass.cpp
  10. +5
    -6
      src/engine/scene/ambient-light.cpp
  11. +35
    -6
      src/engine/scene/ambient-light.hpp
  12. +26
    -0
      src/engine/scene/collection.hpp
  13. +13
    -3
      src/engine/scene/directional-light.cpp
  14. +48
    -19
      src/engine/scene/directional-light.hpp
  15. +5
    -2
      src/engine/scene/light-type.hpp
  16. +25
    -20
      src/engine/scene/object.hpp
  17. +34
    -0
      src/engine/scene/point-light.cpp
  18. +91
    -0
      src/engine/scene/point-light.hpp
  19. +80
    -0
      src/engine/scene/rectangle-light.cpp
  20. +129
    -0
      src/engine/scene/rectangle-light.hpp
  21. +0
    -116
      src/engine/scene/sphere-light.hpp
  22. +8
    -8
      src/engine/scene/spot-light.hpp
  23. +7
    -4
      src/game/components/blackbody-component.hpp
  24. +7
    -2
      src/game/game.cpp
  25. +2
    -3
      src/game/game.hpp
  26. +1
    -1
      src/game/states/nest-selection-state.cpp
  27. +44
    -33
      src/game/states/nest-view-state.cpp
  28. +2
    -0
      src/game/states/nest-view-state.hpp
  29. +13
    -38
      src/game/systems/astronomy-system.cpp
  30. +0
    -4
      src/game/systems/astronomy-system.hpp
  31. +28
    -42
      src/game/systems/blackbody-system.cpp
  32. +8
    -11
      src/game/systems/blackbody-system.hpp
  33. +0
    -11
      src/game/world.cpp

+ 0
- 1
CMakeLists.txt View File

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

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

@ -37,9 +37,9 @@ namespace cat {
template <class T> template <class T>
constexpr math::matrix<T, 3, 3> bradford = constexpr math::matrix<T, 3, 3> bradford =
{ {
0.8951, -0.7502, 0.0389,
0.2664, 1.7135, -0.0685,
-0.1614, 0.0367, 1.0296
T{ 0.8951}, T{-0.7502}, T{ 0.0389},
T{ 0.2664}, T{ 1.7135}, T{-0.0685},
T{-0.1614}, T{ 0.0367}, T{ 1.0296}
}; };
/** /**
@ -50,9 +50,9 @@ constexpr math::matrix bradford =
template <class T> template <class T>
constexpr math::matrix<T, 3, 3> von_kries = constexpr math::matrix<T, 3, 3> von_kries =
{ {
0.40024, -0.22630, 0.00000,
0.70760, 1.16532, 0.00000,
-0.08081, 0.04570, 0.91822
T{ 0.40024}, T{-0.22630}, T{0.00000},
T{ 0.70760}, T{ 1.16532}, T{0.00000},
T{-0.08081}, T{ 0.04570}, T{0.91822}
}; };
/** /**

+ 5
- 5
src/engine/color/rgb.hpp View File

@ -86,8 +86,8 @@ struct color_space
/// Function pointer to the electro-optical transfer function. /// Function pointer to the electro-optical transfer function.
const transfer_function_type eotf; const transfer_function_type eotf;
/// Function pointer to the inverse electro-optical transfer function.
const transfer_function_type inverse_eotf;
/// Function pointer to the opto-electrical transfer function.
const transfer_function_type oetf;
/// Matrix which transforms an RGB color to a CIE XYZ color. /// Matrix which transforms an RGB color to a CIE XYZ color.
const math::matrix3x3<T> to_xyz; const math::matrix3x3<T> to_xyz;
@ -106,7 +106,7 @@ struct color_space
* @param b CIE xy chromaticity coordinates of the blue primary. * @param b CIE xy chromaticity coordinates of the blue primary.
* @param w CIE xy chromaticity coordinates of the white point. * @param w CIE xy chromaticity coordinates of the white point.
*/ */
constexpr color_space(const math::vector2<T>& r, const math::vector2<T>& g, const math::vector2<T>& b, const math::vector2<T>& w, transfer_function_type eotf, transfer_function_type inverse_eotf);
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);
/** /**
* Measures the luminance of a linear RGB color. * Measures the luminance of a linear RGB color.
@ -118,13 +118,13 @@ struct color_space
}; };
template <class T> template <class T>
constexpr color_space<T>::color_space(const math::vector2<T>& r, const math::vector2<T>& g, const math::vector2<T>& b, const math::vector2<T>& w, transfer_function_type eotf, transfer_function_type inverse_eotf):
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), r(r),
g(g), g(g),
b(b), b(b),
w(w), w(w),
eotf(eotf), eotf(eotf),
inverse_eotf(inverse_eotf),
oetf(oetf),
to_xyz(color::rgb::to_xyz<T>(r, g, b, w)), to_xyz(color::rgb::to_xyz<T>(r, g, b, w)),
from_xyz(math::inverse(to_xyz)), from_xyz(math::inverse(to_xyz)),
to_y{to_xyz[0][1], to_xyz[1][1], to_xyz[2][1]} to_y{to_xyz[0][1], to_xyz[1][1], to_xyz[2][1]}

+ 15
- 15
src/engine/color/srgb.hpp View File

@ -28,14 +28,14 @@
namespace color { namespace color {
/** /**
* sRGB electro-optical transfer function (EOTF), also known as the sRGB decoding function.
* Maps a non-linear sRGB signal to a linear sRGB color.
* *
* @param v sRGB electrical signal (gamma-encoded sRGB).
* @param x Non-linear sRGB signal.
* *
* @return Corresponding luminance of the signal (linear sRGB).
* @return Linear sRGB color.
*/ */
template <class T> template <class T>
math::vector3<T> srgb_eotf(const math::vector3<T>& v)
math::vector3<T> srgb_eotf(const math::vector3<T>& x)
{ {
auto f = [](T x) -> T auto f = [](T x) -> T
{ {
@ -44,21 +44,21 @@ math::vector3 srgb_eotf(const math::vector3& v)
return math::vector3<T> return math::vector3<T>
{ {
f(v[0]),
f(v[1]),
f(v[2])
f(x[0]),
f(x[1]),
f(x[2])
}; };
} }
/** /**
* sRGB inverse electro-optical transfer function (EOTF), also known as the sRGB encoding function.
* Maps a linear sRGB color to a non-linear sRGB signal.
* *
* @param l sRGB luminance (linear sRGB).
* @param x Linear sRGB color.
* *
* @return Corresponding electrical signal (gamma-encoded sRGB).
* @return Non-linear sRGB signal.
*/ */
template <class T> template <class T>
math::vector3<T> srgb_inverse_eotf(const math::vector3<T>& l)
math::vector3<T> srgb_oetf(const math::vector3<T>& x)
{ {
auto f = [](T x) -> T auto f = [](T x) -> T
{ {
@ -67,9 +67,9 @@ math::vector3 srgb_inverse_eotf(const math::vector3& l)
return math::vector3<T> return math::vector3<T>
{ {
f(l[0]),
f(l[1]),
f(l[2])
f(x[0]),
f(x[1]),
f(x[2])
}; };
} }
@ -82,7 +82,7 @@ constexpr rgb::color_space srgb
{T{0.15}, T{0.06}}, {T{0.15}, T{0.06}},
color::illuminant::deg2::d65<T>, color::illuminant::deg2::d65<T>,
&srgb_eotf<T>, &srgb_eotf<T>,
&srgb_inverse_eotf
&srgb_oetf<T>
); );
} // namespace color } // namespace color

+ 4
- 15
src/engine/physics/light/blackbody.hpp View File

@ -63,17 +63,6 @@ T radiant_flux(T t, T a);
template <class T> template <class T>
T radiant_intensity(T t, T a, T omega); T radiant_intensity(T t, T a, T omega);
/**
* Calculates the spectral exitance of a blackbody for the given wavelength.
*
* @param t Temperature of the blackbody, in kelvin.
* @param lambda Wavelength of light, in meters.
* @param c Speed of light in medium.
* @return Spectral exitance, in watt per square meter, per meter.
*/
template <class T>
T spectral_exitance(T t, T lambda, T c = constants::speed_of_light<T>);
/** /**
* Calculates the spectral flux of a blackbody for the given wavelength. * Calculates the spectral flux of a blackbody for the given wavelength.
* *
@ -84,7 +73,7 @@ T spectral_exitance(T t, T lambda, T c = constants::speed_of_light);
* @return Spectral flux of the blackbody, in watt per meter. * @return Spectral flux of the blackbody, in watt per meter.
*/ */
template <class T> template <class T>
T spectral_flux(T t, T a, T lambda, T c = constants::speed_of_light<T>);
T spectral_flux(T t, T a, T lambda, T c = constants::speed_of_light<T>);
/** /**
* Calculates the spectral intensity of a blackbody for the given wavelength. * Calculates the spectral intensity of a blackbody for the given wavelength.
@ -97,7 +86,7 @@ T spectral_flux(T t, T a, T lambda, T c = constants::speed_of_light);
* @return Spectral intensity of the blackbody for the given wavelength, in watt per steradian per meter. * @return Spectral intensity of the blackbody for the given wavelength, in watt per steradian per meter.
*/ */
template <class T> template <class T>
T spectral_intensity(T t, T a, T lambda, T omega, T c = constants::speed_of_light<T>);
T spectral_intensity(T t, T a, T lambda, T omega, T c = constants::speed_of_light<T>);
/** /**
* Calculates the spectral radiance of a blackbody for the given wavelength. * Calculates the spectral radiance of a blackbody for the given wavelength.
@ -136,7 +125,7 @@ T spectral_exitance(T t, T lambda, T c)
const T lambda2 = lambda * lambda; const T lambda2 = lambda * lambda;
// First radiation constant (c1) // First radiation constant (c1)
const T c1 = T(2) * math::pi<T> * hc * c;
const T c1 = math::two_pi<T> * hc * c;
// Second radiation constant (c2) // Second radiation constant (c2)
const T c2 = hc / constants::boltzmann<T>; const T c2 = hc / constants::boltzmann<T>;
@ -163,7 +152,7 @@ T spectral_radiance(T t, T lambda, T c)
const T lambda2 = lambda * lambda; const T lambda2 = lambda * lambda;
// First radiation constant (c1L) // First radiation constant (c1L)
const T c1l = T(2) * hc * c;
const T c1l = T{2} * hc * c;
// Second radiation constant (c2) // Second radiation constant (c2)
const T c2 = hc / constants::boltzmann<T>; const T c2 = hc / constants::boltzmann<T>;

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

@ -35,6 +35,7 @@
#include <cmath> #include <cmath>
#include <glad/glad.h> #include <glad/glad.h>
#include <engine/utility/hash/fnv1a.hpp> #include <engine/utility/hash/fnv1a.hpp>
#include <engine/debug/log.hpp>
namespace render { namespace render {
@ -49,6 +50,11 @@ final_pass::final_pass(gl::rasterizer* rasterizer, const gl::framebuffer* frameb
// Load shader template and build shader program // Load shader template and build shader program
auto shader_template = resource_manager->load<gl::shader_template>("final.glsl"); auto shader_template = resource_manager->load<gl::shader_template>("final.glsl");
shader_program = shader_template->build(); shader_program = shader_template->build();
if (!shader_program->linked())
{
debug::log::error("Failed to final pass shader program: {}", shader_program->info());
debug::log::warning("{}", shader_template->configure(gl::shader_stage::vertex));
}
const float2 vertex_positions[] = const float2 vertex_positions[] =
{ {

+ 71
- 51
src/engine/render/passes/material-pass.cpp View File

@ -41,7 +41,8 @@
#include <engine/scene/ambient-light.hpp> #include <engine/scene/ambient-light.hpp>
#include <engine/scene/directional-light.hpp> #include <engine/scene/directional-light.hpp>
#include <engine/scene/spot-light.hpp> #include <engine/scene/spot-light.hpp>
#include <engine/scene/sphere-light.hpp>
#include <engine/scene/point-light.hpp>
#include <engine/scene/rectangle-light.hpp>
#include <engine/config.hpp> #include <engine/config.hpp>
#include <engine/math/quaternion.hpp> #include <engine/math/quaternion.hpp>
#include <engine/math/projection.hpp> #include <engine/math/projection.hpp>
@ -117,7 +118,11 @@ bool operation_compare(const render::operation* a, const render::operation* b)
material_pass::material_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffer, resource_manager* resource_manager): material_pass::material_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffer, resource_manager* resource_manager):
pass(rasterizer, framebuffer) pass(rasterizer, 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");
}
void material_pass::render(render::context& ctx) void material_pass::render(render::context& ctx)
{ {
@ -315,7 +320,8 @@ void material_pass::evaluate_lighting(const render::context& ctx)
directional_light_count = 0; directional_light_count = 0;
directional_shadow_count = 0; directional_shadow_count = 0;
spot_light_count = 0; spot_light_count = 0;
sphere_light_count = 0;
point_light_count = 0;
rectangle_light_count = 0;
const auto& lights = ctx.collection->get_objects(scene::light::object_type_id); const auto& lights = ctx.collection->get_objects(scene::light::object_type_id);
for (const scene::object_base* object: lights) for (const scene::object_base* object: lights)
@ -335,9 +341,7 @@ void material_pass::evaluate_lighting(const render::context& ctx)
ambient_light_colors.resize(ambient_light_count); ambient_light_colors.resize(ambient_light_count);
} }
ambient_light_colors[index] = static_cast<const scene::ambient_light&>(light).get_illuminance() * ctx.camera->get_exposure_normalization();
ambient_light_colors[index] = static_cast<const scene::ambient_light&>(light).get_colored_illuminance() * ctx.camera->get_exposure_normalization();
break; break;
} }
@ -355,7 +359,7 @@ void material_pass::evaluate_lighting(const render::context& ctx)
directional_light_directions.resize(directional_light_count); directional_light_directions.resize(directional_light_count);
} }
directional_light_colors[index] = directional_light.get_illuminance() * ctx.camera->get_exposure_normalization();
directional_light_colors[index] = directional_light.get_colored_illuminance() * ctx.camera->get_exposure_normalization();
directional_light_directions[index] = directional_light.get_direction(); directional_light_directions[index] = directional_light.get_direction();
// Add directional shadow // Add directional shadow
@ -396,51 +400,53 @@ void material_pass::evaluate_lighting(const render::context& ctx)
spot_light_cutoffs.resize(spot_light_count); spot_light_cutoffs.resize(spot_light_count);
} }
spot_light_colors[index] = spot_light.get_luminous_power() * ctx.camera->get_exposure_normalization();
spot_light_colors[index] = spot_light.get_luminous_flux() * ctx.camera->get_exposure_normalization();
spot_light_positions[index] = spot_light.get_translation(); spot_light_positions[index] = spot_light.get_translation();
spot_light_directions[index] = spot_light.get_direction(); spot_light_directions[index] = spot_light.get_direction();
spot_light_cutoffs[index] = spot_light.get_cosine_cutoff(); spot_light_cutoffs[index] = spot_light.get_cosine_cutoff();
break; break;
} }
// Add sphere light
case scene::light_type::sphere:
// Add point light
case scene::light_type::point:
{ {
const scene::sphere_light& sphere_light = static_cast<const scene::sphere_light&>(light);
const scene::point_light& point_light = static_cast<const scene::point_light&>(light);
if (sphere_light.get_radius() == 0.0f)
const std::size_t index = point_light_count;
++point_light_count;
if (point_light_count > point_light_colors.size())
{ {
const std::size_t index = point_light_count;
++point_light_count;
if (point_light_count > point_light_colors.size())
{
point_light_colors.resize(point_light_count);
point_light_positions.resize(point_light_count);
}
point_light_colors[index] = sphere_light.get_spectral_luminous_power() * ctx.camera->get_exposure_normalization();
point_light_positions[index] = sphere_light.get_translation();
point_light_colors.resize(point_light_count);
point_light_positions.resize(point_light_count);
} }
else
point_light_colors[index] = point_light.get_colored_luminous_flux() * ctx.camera->get_exposure_normalization();
point_light_positions[index] = point_light.get_translation();
break;
}
// Add rectangle light
case scene::light_type::rectangle:
{
const scene::rectangle_light& rectangle_light = static_cast<const scene::rectangle_light&>(light);
const std::size_t index = rectangle_light_count;
++rectangle_light_count;
if (rectangle_light_count > rectangle_light_colors.size())
{ {
const std::size_t index = sphere_light_count;
++sphere_light_count;
if (sphere_light_count > sphere_light_colors.size())
{
sphere_light_colors.resize(sphere_light_count);
sphere_light_positions_radii.resize(sphere_light_count);
}
sphere_light_colors[index] = sphere_light.get_spectral_luminous_power() * ctx.camera->get_exposure_normalization();
const auto& position = sphere_light.get_translation();
auto& position_radius = sphere_light_positions_radii[index];
position_radius[0] = position.x();
position_radius[1] = position.y();
position_radius[2] = position.z();
position_radius[3] = sphere_light.get_radius();
rectangle_light_colors.resize(rectangle_light_count);
rectangle_light_corners.resize(rectangle_light_count * 4);
}
rectangle_light_colors[index] = rectangle_light.get_colored_luminance() * ctx.camera->get_exposure_normalization();
const auto corners = rectangle_light.get_corners();
for (std::size_t i = 0; i < 4; ++i)
{
rectangle_light_corners[index * 4 + i] = corners[i];
} }
break; break;
@ -457,7 +463,7 @@ void material_pass::evaluate_lighting(const render::context& ctx)
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>{}(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>{}(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>{}(spot_light_count));
lighting_state_hash = hash::combine(lighting_state_hash, std::hash<std::size_t>{}(sphere_light_count));
lighting_state_hash = hash::combine(lighting_state_hash, std::hash<std::size_t>{}(point_light_count));
} }
void material_pass::evaluate_misc(const render::context& ctx) void material_pass::evaluate_misc(const render::context& ctx)
@ -497,7 +503,7 @@ std::unique_ptr material_pass::generate_shader_program(const
definitions["DIRECTIONAL_SHADOW_COUNT"] = std::to_string(directional_shadow_count); definitions["DIRECTIONAL_SHADOW_COUNT"] = std::to_string(directional_shadow_count);
definitions["POINT_LIGHT_COUNT"] = std::to_string(point_light_count); definitions["POINT_LIGHT_COUNT"] = std::to_string(point_light_count);
definitions["SPOT_LIGHT_COUNT"] = std::to_string(spot_light_count); definitions["SPOT_LIGHT_COUNT"] = std::to_string(spot_light_count);
definitions["SPHERE_LIGHT_COUNT"] = std::to_string(sphere_light_count);
definitions["RECTANGLE_LIGHT_COUNT"] = std::to_string(rectangle_light_count);
auto shader_program = shader_template.build(definitions); auto shader_program = shader_template.build(definitions);
@ -541,6 +547,21 @@ void material_pass::build_shader_command_buffer(std::vector
command_buffer.emplace_back([&, clip_depth_var](){clip_depth_var->update(clip_depth);}); command_buffer.emplace_back([&, clip_depth_var](){clip_depth_var->update(clip_depth);});
} }
if (auto ltc_lut_1_var = shader_program.variable("ltc_lut_1"))
{
if (auto ltc_lut_2_var = shader_program.variable("ltc_lut_2"))
{
command_buffer.emplace_back
(
[&, ltc_lut_1_var, ltc_lut_2_var]()
{
ltc_lut_1_var->update(*ltc_lut_1);
ltc_lut_2_var->update(*ltc_lut_2);
}
);
}
}
// Update ambient light variables // Update ambient light variables
if (ambient_light_count) if (ambient_light_count)
{ {
@ -646,21 +667,20 @@ void material_pass::build_shader_command_buffer(std::vector
} }
} }
// Update sphere light variables
if (sphere_light_count)
if (rectangle_light_count)
{ {
if (auto sphere_light_colors_var = shader_program.variable("sphere_light_colors"))
if (auto rectangle_light_colors_var = shader_program.variable("rectangle_light_colors"))
{ {
auto sphere_light_positions_radii_var = shader_program.variable("sphere_light_positions_radii");
auto rectangle_light_corners_var = shader_program.variable("rectangle_light_corners");
if (sphere_light_positions_radii_var)
if (rectangle_light_corners_var)
{ {
command_buffer.emplace_back command_buffer.emplace_back
( (
[&, sphere_light_colors_var, sphere_light_positions_radii_var]()
[&, rectangle_light_colors_var, rectangle_light_corners_var]()
{ {
sphere_light_colors_var->update(std::span<const float3>{sphere_light_colors.data(), sphere_light_count});
sphere_light_positions_radii_var->update(std::span<const float4>{sphere_light_positions_radii.data(), sphere_light_count});
rectangle_light_colors_var->update(std::span<const float3>{rectangle_light_colors.data(), rectangle_light_count});
rectangle_light_corners_var->update(std::span<const float3>{rectangle_light_corners.data(), rectangle_light_count * 4});
} }
); );
} }

+ 13
- 4
src/engine/render/passes/material-pass.hpp View File

@ -47,6 +47,11 @@ public:
/// Sets the material to be used when a render operation is missing a material. If no fallback material is specified, render operations without materials will not be processed. /// Sets the material to be used when a render operation is missing a material. If no fallback material is specified, render operations without materials will not be processed.
void set_fallback_material(std::shared_ptr<render::material> fallback); void set_fallback_material(std::shared_ptr<render::material> fallback);
inline void set_mouse_position(const float2& position)
{
mouse_position = position;
}
private: private:
struct shader_cache_entry struct shader_cache_entry
{ {
@ -120,10 +125,14 @@ private:
std::vector<float2> spot_light_cutoffs; std::vector<float2> spot_light_cutoffs;
std::size_t spot_light_count; std::size_t spot_light_count;
// Sphere lights
std::vector<float3> sphere_light_colors;
std::vector<float4> sphere_light_positions_radii;
std::size_t sphere_light_count;
// Rectangle lights
std::vector<float3> rectangle_light_colors;
std::vector<float3> rectangle_light_corners;
std::size_t rectangle_light_count;
// LTC
std::shared_ptr<gl::texture_2d> ltc_lut_1;
std::shared_ptr<gl::texture_2d> ltc_lut_2;
// Misc // Misc
float time; float time;

+ 18
- 3
src/engine/render/passes/sky-pass.cpp View File

@ -366,7 +366,7 @@ void sky_pass::set_sky_model(std::shared_ptr model)
{ {
sky_shader_program = sky_material->get_shader_template()->build(); sky_shader_program = sky_material->get_shader_template()->build();
if (sky_shader_program)
if (sky_shader_program->linked())
{ {
model_view_projection_var = sky_shader_program->variable("model_view_projection"); model_view_projection_var = sky_shader_program->variable("model_view_projection");
mouse_var = sky_shader_program->variable("mouse"); mouse_var = sky_shader_program->variable("mouse");
@ -379,6 +379,11 @@ void sky_pass::set_sky_model(std::shared_ptr model)
sky_illuminance_lut_var = sky_shader_program->variable("sky_illuminance_lut"); sky_illuminance_lut_var = sky_shader_program->variable("sky_illuminance_lut");
sky_illuminance_lut_resolution_var = sky_shader_program->variable("sky_illuminance_lut_resolution"); sky_illuminance_lut_resolution_var = sky_shader_program->variable("sky_illuminance_lut_resolution");
} }
else
{
debug::log::error("Failed to build sky shader program: {}", sky_shader_program->info());
debug::log::warning("{}", sky_material->get_shader_template()->configure(gl::shader_stage::vertex));
}
} }
} }
else else
@ -408,7 +413,7 @@ void sky_pass::set_moon_model(std::shared_ptr model)
{ {
moon_shader_program = moon_material->get_shader_template()->build(); moon_shader_program = moon_material->get_shader_template()->build();
if (moon_shader_program)
if (moon_shader_program->linked())
{ {
moon_model_var = moon_shader_program->variable("model"); moon_model_var = moon_shader_program->variable("model");
moon_view_projection_var = moon_shader_program->variable("view_projection"); moon_view_projection_var = moon_shader_program->variable("view_projection");
@ -419,6 +424,11 @@ void sky_pass::set_moon_model(std::shared_ptr model)
moon_planetlight_direction_var = moon_shader_program->variable("planetlight_direction"); moon_planetlight_direction_var = moon_shader_program->variable("planetlight_direction");
moon_planetlight_illuminance_var = moon_shader_program->variable("planetlight_illuminance"); moon_planetlight_illuminance_var = moon_shader_program->variable("planetlight_illuminance");
} }
else
{
debug::log::error("Failed to build moon shader program: {}", moon_shader_program->info());
debug::log::warning("{}", moon_material->get_shader_template()->configure(gl::shader_stage::vertex));
}
} }
} }
else else
@ -447,13 +457,18 @@ void sky_pass::set_stars_model(std::shared_ptr model)
{ {
star_shader_program = star_material->get_shader_template()->build(); star_shader_program = star_material->get_shader_template()->build();
if (star_shader_program)
if (star_shader_program->linked())
{ {
star_model_view_var = star_shader_program->variable("model_view"); star_model_view_var = star_shader_program->variable("model_view");
star_projection_var = star_shader_program->variable("projection"); star_projection_var = star_shader_program->variable("projection");
star_distance_var = star_shader_program->variable("star_distance"); star_distance_var = star_shader_program->variable("star_distance");
star_exposure_var = star_shader_program->variable("camera.exposure"); star_exposure_var = star_shader_program->variable("camera.exposure");
} }
else
{
debug::log::error("Failed to build star shader program: {}", star_shader_program->info());
debug::log::warning("{}", star_material->get_shader_template()->configure(gl::shader_stage::vertex));
}
} }
} }
else else

src/engine/scene/sphere-light.cpp → src/engine/scene/ambient-light.cpp View File

@ -17,19 +17,18 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <engine/scene/sphere-light.hpp>
#include <engine/math/numbers.hpp>
#include <engine/scene/ambient-light.hpp>
namespace scene { namespace scene {
float sphere_light::get_luminance() const noexcept
void ambient_light::color_updated()
{ {
return m_luminous_power / (4.0f * m_radius * m_radius * math::sqr_pi<float>);
m_colored_illuminance = m_color * m_illuminance;
} }
math::vector<float, 3> sphere_light::get_spectral_luminance() const noexcept
void ambient_light::illuminance_updated()
{ {
return m_color * get_luminance();
m_colored_illuminance = m_color * m_illuminance;
} }
} // namespace scene } // namespace scene

+ 35
- 6
src/engine/scene/ambient-light.hpp View File

@ -37,23 +37,52 @@ public:
} }
/** /**
* Sets the illuminance of the ambient light.
* Sets the color of the light.
* *
* @param illuminance Illuminance, in *lx*.
* @param color Light color.
*/ */
inline void set_illuminance(const math::vector<float, 3>& illuminance) noexcept
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; m_illuminance = illuminance;
illuminance_updated();
} }
/// Returns the illuminance of the ambient light, in *lx*.
[[nodiscard]] inline const math::vector<float, 3>& get_illuminance() const noexcept
/// 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; 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: private:
math::vector<float, 3> m_illuminance{0.0f, 0.0f, 0.0f};
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 } // namespace scene

+ 26
- 0
src/engine/scene/collection.hpp View File

@ -32,6 +32,9 @@ namespace scene {
class collection class collection
{ {
public: public:
/// @name Objects
/// @{
/** /**
* Adds an object to the collection. * Adds an object to the collection.
* *
@ -66,10 +69,33 @@ public:
{ {
return m_object_map[type_id]; return m_object_map[type_id];
} }
/// @}
/// @name Settings
/// @{
/**
* Sets the scale of the scene.
*
* @param scale Ratio of meters to scene units.
*/
inline void set_scale(float scale) noexcept
{
m_scale = scale;
}
/// Returns the ratio of meters to scene units.
[[nodiscard]] inline float get_scale() const noexcept
{
return m_scale;
}
/// @}
private: private:
std::vector<object_base*> m_objects; std::vector<object_base*> m_objects;
mutable std::unordered_map<std::size_t, std::vector<object_base*>> m_object_map; mutable std::unordered_map<std::size_t, std::vector<object_base*>> m_object_map;
float m_scale{1.0f};
}; };
} // namespace scene } // namespace scene

+ 13
- 3
src/engine/scene/directional-light.cpp View File

@ -26,9 +26,9 @@ directional_light::directional_light():
m_shadow_cascade_matrices(m_shadow_cascade_count) m_shadow_cascade_matrices(m_shadow_cascade_count)
{} {}
void directional_light::set_direction(const math::vector<float, 3>& direction)
void directional_light::set_direction(const math::vector3<float>& direction)
{ {
set_rotation(math::rotation(math::vector<float, 3>{0.0f, 0.0f, -1.0f}, direction));
set_rotation(math::rotation(math::vector3<float>{0.0f, 0.0f, -1.0f}, direction));
} }
void directional_light::set_shadow_caster(bool caster) noexcept void directional_light::set_shadow_caster(bool caster) noexcept
@ -65,7 +65,17 @@ void directional_light::set_shadow_cascade_distribution(float weight) noexcept
void directional_light::transformed() void directional_light::transformed()
{ {
m_direction = get_rotation() * math::vector<float, 3>{0.0f, 0.0f, -1.0f};
m_direction = get_rotation() * math::vector3<float>{0.0f, 0.0f, -1.0f};
}
void directional_light::color_updated()
{
m_colored_illuminance = m_color * m_illuminance;
}
void directional_light::illuminance_updated()
{
m_colored_illuminance = m_color * m_illuminance;
} }
} // namespace scene } // namespace scene

+ 48
- 19
src/engine/scene/directional-light.hpp View File

@ -43,37 +43,61 @@ public:
return light_type::directional; return light_type::directional;
} }
/// Returns a unit vector pointing in the light direction.
[[nodiscard]] inline const math::vector<float, 3>& get_direction() const noexcept
{
return m_direction;
}
/// @name Light /// @name Light
/// @{ /// @{
/** /**
* Sets the illuminance of the directional light.
* Sets the direction of the directional light.
*
* @param direction Unit-length light direction vector.
*/
void set_direction(const math::vector3<float>& direction);
/**
* 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, in *lx*.
* @param illuminance Illuminance on a surface perpendicular to the light direction.
*/ */
inline void set_illuminance(const math::vector<float, 3>& illuminance) noexcept
inline void set_illuminance(float illuminance) noexcept
{ {
m_illuminance = illuminance; m_illuminance = illuminance;
illuminance_updated();
} }
/// Returns the illuminance of the directional light, in *lx*.
[[nodiscard]] inline const math::vector<float, 3>& get_illuminance() const noexcept
/// Returns a unit vector pointing in the light direction.
[[nodiscard]] inline const math::vector3<float>& get_direction() const noexcept
{
return m_direction;
}
/// 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; return m_illuminance;
} }
/**
* Sets the direction of the directional light.
*
* @param direction Unit-length light direction vector.
*/
void set_direction(const math::vector<float, 3>& direction);
/// 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;
}
/// @} /// @}
@ -186,9 +210,14 @@ public:
private: private:
void transformed() override; void transformed() override;
void color_updated();
void illuminance_updated();
math::vector3<float> m_direction{0.0f, 0.0f, -1.0f};
math::vector3<float> m_color{1.0f, 1.0f, 1.0f};
float m_illuminance{};
math::vector3<float> m_colored_illuminance{};
math::vector<float, 3> m_illuminance{0.0f, 0.0f, 0.0f};
math::vector<float, 3> m_direction{0.0f, 0.0f, -1.0f};
bool m_shadow_caster{false}; bool m_shadow_caster{false};
std::shared_ptr<gl::framebuffer> m_shadow_framebuffer{nullptr}; std::shared_ptr<gl::framebuffer> m_shadow_framebuffer{nullptr};
float m_shadow_bias{0.005f}; float m_shadow_bias{0.005f};

+ 5
- 2
src/engine/scene/light-type.hpp View File

@ -36,8 +36,11 @@ enum class light_type: std::uint8_t
/// Spot light. /// Spot light.
spot, spot,
/// Sphere light.
sphere
/// Point light.
point,
/// Rectangle light.
rectangle
}; };
} // namespace scene } // namespace scene

+ 25
- 20
src/engine/scene/object.hpp View File

@ -57,7 +57,9 @@ public:
void look_at(const vector_type& position, const vector_type& target, const vector_type& up); void look_at(const vector_type& position, const vector_type& target, const vector_type& up);
/** /**
* Sets the scene object's transform.
* Sets the transform of the object.
*
* @param transform Object transform.
*/ */
inline void set_transform(const transform_type& transform) inline void set_transform(const transform_type& transform)
{ {
@ -66,7 +68,9 @@ public:
} }
/** /**
* Sets the scene object's translation.
* Sets the translation of the object.
*
* @param translation Object translation.
*/ */
inline void set_translation(const vector_type& translation) inline void set_translation(const vector_type& translation)
{ {
@ -75,58 +79,59 @@ public:
} }
/** /**
* Sets the scene object's rotation.
* Sets the rotation of the object.
*
* @param rotation Object rotation.
*/ */
inline void set_rotation(const quaternion_type& rotation) inline void set_rotation(const quaternion_type& rotation)
{ {
m_transform.rotation = rotation; m_transform.rotation = rotation;
transformed(); transformed();
} }
/** /**
* Sets the scene object's scale.
* Sets the scale of the object.
*
* @params scale Object scale.
*/ */
/// @{
inline void set_scale(const vector_type& scale) inline void set_scale(const vector_type& scale)
{ {
m_transform.scale = scale; m_transform.scale = scale;
transformed(); transformed();
} }
inline void set_scale(float scale)
{
m_transform.scale = {scale, scale, scale};
transformed();
}
/// @}
/**
* Returns the transform.
*/
/// Returns the transform of the object.
[[nodiscard]] inline const transform_type& get_transform() const noexcept [[nodiscard]] inline const transform_type& get_transform() const noexcept
{ {
return m_transform; return m_transform;
} }
/**
* Returns the transform's translation vector.
*/
/// Returns the translation of the object.
[[nodiscard]] inline const vector_type& get_translation() const noexcept [[nodiscard]] inline const vector_type& get_translation() const noexcept
{ {
return m_transform.translation; return m_transform.translation;
} }
/**
* Returns the transform's rotation quaternion.
*/
/// Returns the rotation of the object.
[[nodiscard]] inline const quaternion_type& get_rotation() const noexcept [[nodiscard]] inline const quaternion_type& get_rotation() const noexcept
{ {
return m_transform.rotation; return m_transform.rotation;
} }
/**
* Returns the transform's scale vector.
*/
/// Returns the scale of the object.
[[nodiscard]] inline const vector_type& get_scale() const noexcept [[nodiscard]] inline const vector_type& get_scale() const noexcept
{ {
return m_transform.scale; return m_transform.scale;
} }
/**
* Returns the bounds of the object.
*/
/// Returns the bounds of the object.
[[nodiscard]] virtual const aabb_type& get_bounds() const noexcept = 0; [[nodiscard]] virtual const aabb_type& get_bounds() const noexcept = 0;
protected: protected:

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

@ -0,0 +1,34 @@
/*
* 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/point-light.hpp>
namespace scene {
void point_light::color_updated()
{
m_colored_luminous_flux = m_color * m_luminous_flux;
}
void point_light::luminous_flux_updated()
{
m_colored_luminous_flux = m_color * m_luminous_flux;
}
} // namespace scene

+ 91
- 0
src/engine/scene/point-light.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_SCENE_POINT_LIGHT_HPP
#define ANTKEEPER_SCENE_POINT_LIGHT_HPP
#include <engine/scene/light.hpp>
#include <engine/math/vector.hpp>
namespace scene {
/**
* Light source that radiates outward from a point.
*/
class point_light: public light
{
public:
/// Returns light_type::point.
[[nodiscard]] inline light_type get_light_type() const noexcept override
{
return light_type::point;
}
/**
* Sets the color of the light.
*
* @param color Light color.
*/
inline void set_color(const math::vector<float, 3>& color) noexcept
{
m_color = color;
color_updated();
}
/**
* Sets the luminous flux of the light.
*
* @param luminous_flux Luminous flux.
*/
inline void set_luminous_flux(float luminous_flux) noexcept
{
m_luminous_flux = luminous_flux;
luminous_flux_updated();
}
/// Returns the color of the light.
[[nodiscard]] inline const math::vector3<float>& get_color() const noexcept
{
return m_color;
}
/// Returns the luminous flux of the light.
[[nodiscard]] inline float get_luminous_flux() const noexcept
{
return m_luminous_flux;
}
/// Returns the color-modulated luminous flux of light.
[[nodiscard]] inline const math::vector3<float>& get_colored_luminous_flux() const noexcept
{
return m_colored_luminous_flux;
}
private:
void color_updated();
void luminous_flux_updated();
math::vector3<float> m_color{1.0f, 1.0f, 1.0f};
float m_luminous_flux{};
math::vector3<float> m_colored_luminous_flux{};
};
} // namespace scene
#endif // ANTKEEPER_SCENE_POINT_LIGHT_HPP

+ 80
- 0
src/engine/scene/rectangle-light.cpp View File

@ -0,0 +1,80 @@
/*
* 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/rectangle-light.hpp>
#include <engine/math/numbers.hpp>
namespace scene {
rectangle_light::rectangle_light()
{
transformed();
}
void rectangle_light::transformed()
{
const auto& transform = get_transform();
// Update corner positions
// m_corners[0] = transform * math::vector3<float>{-0.5f, 0.0f, -0.5f};
// m_corners[1] = transform * math::vector3<float>{ 0.5f, 0.0f, -0.5f};
// m_corners[2] = transform * math::vector3<float>{ 0.5f, 0.0f, 0.5f};
// m_corners[3] = transform * math::vector3<float>{-0.5f, 0.0f, 0.5f};
m_corners[0] = transform * math::vector3<float>{-0.5f, -0.5f, 0.0f};
m_corners[1] = transform * math::vector3<float>{-0.5f, 0.5f, 0.0f};
m_corners[2] = transform * math::vector3<float>{ 0.5f, 0.5f, 0.0f};
m_corners[3] = transform * math::vector3<float>{ 0.5f, -0.5f, 0.0f};
// Update area
m_area = get_scale().x() * get_scale().z();
area_updated();
}
void rectangle_light::area_updated()
{
// Calculate luminance from luminous flux
m_luminance = m_luminous_flux / (m_area * math::pi<float>);
m_colored_luminance = m_color * m_luminance;
}
void rectangle_light::color_updated()
{
m_colored_luminous_flux = m_color * m_luminous_flux;
m_colored_luminance = m_color * m_luminance;
}
void rectangle_light::luminous_flux_updated()
{
m_colored_luminous_flux = m_color * m_luminous_flux;
// Calculate luminance from luminous flux
m_luminance = m_luminous_flux / (m_area * math::pi<float>);
m_colored_luminance = m_color * m_luminance;
}
void rectangle_light::luminance_updated()
{
m_colored_luminance = m_color * m_luminance;
// Calculate luminous flux from luminance
m_luminous_flux = m_luminance * (m_area * math::pi<float>);
m_colored_luminous_flux = m_color * m_luminous_flux;
}
} // namespace scene

+ 129
- 0
src/engine/scene/rectangle-light.hpp View File

@ -0,0 +1,129 @@
/*
* 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_RECTANGLE_LIGHT_HPP
#define ANTKEEPER_SCENE_RECTANGLE_LIGHT_HPP
#include <engine/scene/light.hpp>
#include <engine/math/vector.hpp>
namespace scene {
/**
* Rectangular area light.
*/
class rectangle_light: public light
{
public:
rectangle_light();
/// Returns light_type::rectangle.
[[nodiscard]] inline light_type get_light_type() const noexcept override
{
return light_type::rectangle;
}
/**
* Sets the color of the light.
*
* @param color Light color.
*/
inline void set_color(const math::vector<float, 3>& color) noexcept
{
m_color = color;
color_updated();
}
/**
* Sets the luminous flux of the light.
*
* @param luminous_flux Luminous flux.
*/
inline void set_luminous_flux(float luminous_flux) noexcept
{
m_luminous_flux = luminous_flux;
luminous_flux_updated();
}
/**
* Sets the luminance of the light.
*
* @param luminance Luminance.
*/
inline void set_luminance(float luminance) noexcept
{
m_luminance = luminance;
luminance_updated();
}
/// Returns the color of the light.
[[nodiscard]] inline const math::vector<float, 3>& get_color() const noexcept
{
return m_color;
}
/// Returns the luminous flux of the light.
[[nodiscard]] inline float get_luminous_flux() const noexcept
{
return m_luminous_flux;
}
/// Returns the color-modulated luminous flux of the light.
[[nodiscard]] inline const math::vector<float, 3>& get_colored_luminous_flux() const noexcept
{
return m_colored_luminous_flux;
}
/// Returns the luminance of the light.
[[nodiscard]] inline float get_luminance() const noexcept
{
return m_luminance;
}
/// Returns the color-modulated luminance of the light.
[[nodiscard]] inline const math::vector<float, 3>& get_colored_luminance() const noexcept
{
return m_colored_luminance;
}
/// Returns the positions of the light corners.
[[nodiscard]] inline std::span<const math::vector3<float>, 4> get_corners() const noexcept
{
return m_corners;
}
private:
void transformed() override;
void area_updated();
void color_updated();
void luminous_flux_updated();
void luminance_updated();
float m_area{1.0f};
math::vector3<float> m_corners[4];
math::vector3<float> m_color{1.0f, 1.0f, 1.0f};
float m_luminous_flux{};
math::vector3<float> m_colored_luminous_flux{};
float m_luminance{};
math::vector3<float> m_colored_luminance;
};
} // namespace scene
#endif // ANTKEEPER_SCENE_RECTANGLE_LIGHT_HPP

+ 0
- 116
src/engine/scene/sphere-light.hpp View File

@ -1,116 +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_SPHERE_LIGHT_HPP
#define ANTKEEPER_SCENE_SPHERE_LIGHT_HPP
#include <engine/scene/light.hpp>
#include <engine/math/vector.hpp>
namespace scene {
/**
* Light source that radiates outward from a sphere.
*/
class sphere_light: public light
{
public:
/// Returns light_type::sphere.
[[nodiscard]] inline light_type get_light_type() const noexcept override
{
return light_type::sphere;
}
/**
* Sets the color of the sphere light.
*
* @param color Light color.
*/
inline void set_color(const math::vector<float, 3>& color) noexcept
{
m_color = color;
update_spectral_luminous_power();
}
/**
* Sets the luminous power of the sphere light.
*
* @param luminous_power Luminous power.
*/
inline void set_luminous_power(float luminous_power) noexcept
{
m_luminous_power = luminous_power;
update_spectral_luminous_power();
}
/**
* Sets the radius of the sphere light.
*
* @param radius Radius of the sphere light.
*/
inline void set_radius(float radius) noexcept
{
m_radius = radius;
}
/// Returns the color of the sphere light.
[[nodiscard]] inline const math::vector<float, 3>& get_color() const noexcept
{
return m_color;
}
/// Returns the luminous power of the sphere light.
[[nodiscard]] inline float get_luminous_power() const noexcept
{
return m_luminous_power;
}
/// Returns the spectral luminous power of the sphere light.
[[nodiscard]] inline const math::vector<float, 3>& get_spectral_luminous_power() const noexcept
{
return m_spectral_luminous_power;
}
/// Returns the radius of the sphere light.
[[nodiscard]] inline float get_radius() const noexcept
{
return m_radius;
}
/// Calculates and returns the luminance of the sphere light.
[[nodiscard]] float get_luminance() const noexcept;
/// Calculates and returns the spectral luminance of the sphere light.
[[nodiscard]] math::vector<float, 3> get_spectral_luminance() const noexcept;
private:
inline void update_spectral_luminous_power() noexcept
{
m_spectral_luminous_power = m_color * m_luminous_power;
}
math::vector<float, 3> m_color{1.0f, 1.0f, 1.0f};
float m_luminous_power{};
math::vector<float, 3> m_spectral_luminous_power{};
float m_radius{};
};
} // namespace scene
#endif // ANTKEEPER_SCENE_SPHERE_LIGHT_HPP

+ 8
- 8
src/engine/scene/spot-light.hpp View File

@ -39,19 +39,19 @@ public:
} }
/** /**
* Sets the luminous power of the spot light.
* Sets the luminous flux of the spot light.
* *
* @param luminous_power Luminous power, in *lm*.
* @param luminous_flux Luminous flux, in *lm*.
*/ */
inline void set_luminous_power(const math::vector<float, 3>& luminous_power) noexcept
inline void set_luminous_flux(const math::vector<float, 3>& luminous_flux) noexcept
{ {
m_luminous_power = luminous_power;
m_luminous_flux = luminous_flux;
} }
/// Returns the luminous power of the spot light, in *lm*.
[[nodiscard]] inline const math::vector<float, 3>& get_luminous_power() const noexcept
/// Returns the luminous flux of the spot light, in *lm*.
[[nodiscard]] inline const math::vector<float, 3>& get_luminous_flux() const noexcept
{ {
return m_luminous_power;
return m_luminous_flux;
} }
/** /**
@ -82,7 +82,7 @@ public:
private: private:
void transformed() override; void transformed() override;
math::vector<float, 3> m_luminous_power{0.0f, 0.0f, 0.0f};
math::vector<float, 3> m_luminous_flux{0.0f, 0.0f, 0.0f};
math::vector<float, 3> m_direction{0.0f, 0.0f, -1.0f}; math::vector<float, 3> m_direction{0.0f, 0.0f, -1.0f};
math::vector<float, 2> m_cutoff{math::pi<float>, math::pi<float>}; math::vector<float, 2> m_cutoff{math::pi<float>, math::pi<float>};
math::vector<float, 2> m_cosine_cutoff{-1.0f, -1.0f}; math::vector<float, 2> m_cosine_cutoff{-1.0f, -1.0f};

+ 7
- 4
src/game/components/blackbody-component.hpp View File

@ -20,16 +20,19 @@
#ifndef ANTKEEPER_GAME_BLACKBODY_COMPONENT_HPP #ifndef ANTKEEPER_GAME_BLACKBODY_COMPONENT_HPP
#define ANTKEEPER_GAME_BLACKBODY_COMPONENT_HPP #define ANTKEEPER_GAME_BLACKBODY_COMPONENT_HPP
#include <engine/math/vector.hpp>
/// Blackbody radiator /// Blackbody radiator
struct blackbody_component struct blackbody_component
{ {
/// Effective temperature, in Kelvin. /// Effective temperature, in Kelvin.
double temperature;
double temperature{};
/// (Dependent) RGB spectral luminance, in cd/m^2.
double3 luminance;
/// Luminance of the blackbody.
double luminance{};
/// Color of the blackbody.
math::vector<double, 3> color{};
}; };
#endif // ANTKEEPER_GAME_BLACKBODY_COMPONENT_HPP #endif // ANTKEEPER_GAME_BLACKBODY_COMPONENT_HPP

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

@ -795,12 +795,16 @@ void game::setup_scenes()
{ {
debug::log::trace("Setting up scenes..."); debug::log::trace("Setting up scenes...");
// Ratio of meters to scene units.
constexpr float scene_scale = 1.0f / 100.0f;
// Get default framebuffer // Get default framebuffer
const auto& viewport_size = window->get_viewport_size(); const auto& viewport_size = window->get_viewport_size();
const float viewport_aspect_ratio = static_cast<float>(viewport_size[0]) / static_cast<float>(viewport_size[1]); const float viewport_aspect_ratio = static_cast<float>(viewport_size[0]) / static_cast<float>(viewport_size[1]);
// Allocate surface scene
// Allocate and init surface scene
surface_scene = std::make_unique<scene::collection>(); surface_scene = std::make_unique<scene::collection>();
surface_scene->set_scale(scene_scale);
// Allocate and init surface camera // Allocate and init surface camera
surface_camera = std::make_shared<scene::camera>(); surface_camera = std::make_shared<scene::camera>();
@ -808,8 +812,9 @@ void game::setup_scenes()
surface_camera->set_compositor(surface_compositor.get()); surface_camera->set_compositor(surface_compositor.get());
surface_camera->set_composite_index(0); surface_camera->set_composite_index(0);
// Allocate underground scene
// Allocate and init underground scene
underground_scene = std::make_unique<scene::collection>(); underground_scene = std::make_unique<scene::collection>();
underground_scene->set_scale(scene_scale);
// Allocate and init underground camera // Allocate and init underground camera
underground_camera = std::make_shared<scene::camera>(); underground_camera = std::make_shared<scene::camera>();

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

@ -49,7 +49,7 @@
#include <engine/utility/frame-scheduler.hpp> #include <engine/utility/frame-scheduler.hpp>
#include <engine/scene/text.hpp> #include <engine/scene/text.hpp>
#include <engine/scene/directional-light.hpp> #include <engine/scene/directional-light.hpp>
#include <engine/scene/sphere-light.hpp>
#include <engine/scene/rectangle-light.hpp>
#include <engine/scene/spot-light.hpp> #include <engine/scene/spot-light.hpp>
#include <engine/scene/ambient-light.hpp> #include <engine/scene/ambient-light.hpp>
#include <engine/scene/camera.hpp> #include <engine/scene/camera.hpp>
@ -333,12 +333,11 @@ public:
std::unique_ptr<scene::directional_light> sun_light; std::unique_ptr<scene::directional_light> sun_light;
std::unique_ptr<scene::directional_light> moon_light; std::unique_ptr<scene::directional_light> moon_light;
std::unique_ptr<scene::ambient_light> sky_light; std::unique_ptr<scene::ambient_light> sky_light;
std::unique_ptr<scene::directional_light> bounce_light;
std::unique_ptr<scene::collection> underground_scene; std::unique_ptr<scene::collection> underground_scene;
std::shared_ptr<scene::camera> underground_camera; std::shared_ptr<scene::camera> underground_camera;
std::unique_ptr<scene::directional_light> underground_directional_light; std::unique_ptr<scene::directional_light> underground_directional_light;
std::unique_ptr<scene::ambient_light> underground_ambient_light; std::unique_ptr<scene::ambient_light> underground_ambient_light;
std::unique_ptr<scene::sphere_light> underground_sphere_light;
std::unique_ptr<scene::rectangle_light> underground_rectangle_light;
scene::collection* active_scene; scene::collection* active_scene;
// Animation // Animation

+ 1
- 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); ctx.ui_clear_pass->set_cleared_buffers(false, true, false);
// Set world time // Set world time
::world::set_time(ctx, 2022, 6, 21, 12, 0, 0.0);
::world::set_time(ctx, 2022, 6, 21, 18, 0, 0.0);
// Init time scale // Init time scale
double time_scale = 60.0; double time_scale = 60.0;

+ 44
- 33
src/game/states/nest-view-state.cpp View File

@ -71,13 +71,16 @@
#include <engine/physics/kinematics/colliders/capsule-collider.hpp> #include <engine/physics/kinematics/colliders/capsule-collider.hpp>
#include <engine/render/passes/clear-pass.hpp> #include <engine/render/passes/clear-pass.hpp>
#include <engine/render/passes/ground-pass.hpp> #include <engine/render/passes/ground-pass.hpp>
#include <engine/render/passes/material-pass.hpp>
#include <engine/resources/resource-manager.hpp> #include <engine/resources/resource-manager.hpp>
#include <engine/utility/state-machine.hpp> #include <engine/utility/state-machine.hpp>
#include <engine/scene/static-mesh.hpp> #include <engine/scene/static-mesh.hpp>
#include <engine/scene/skeletal-mesh.hpp> #include <engine/scene/skeletal-mesh.hpp>
#include <engine/scene/sphere-light.hpp>
#include <engine/scene/rectangle-light.hpp>
#include <engine/scene/point-light.hpp>
#include <engine/geom/intersection.hpp> #include <engine/geom/intersection.hpp>
#include <engine/animation/ease.hpp> #include <engine/animation/ease.hpp>
#include <engine/color/color.hpp>
nest_view_state::nest_view_state(::game& ctx): nest_view_state::nest_view_state(::game& ctx):
game_state(ctx) game_state(ctx)
@ -110,9 +113,10 @@ nest_view_state::nest_view_state(::game& ctx):
debug::log::trace("Generated worker model"); debug::log::trace("Generated worker model");
// Create directional light // Create directional light
ctx.underground_directional_light = std::make_unique<scene::directional_light>();
ctx.underground_directional_light->set_illuminance(float3{0.747f, 0.756f, 1.0f} * 2.0f);
ctx.underground_directional_light->set_direction(math::normalize(math::vector<float, 3>{1, -1, 0}));
// ctx.underground_directional_light = std::make_unique<scene::directional_light>();
// ctx.underground_directional_light->set_color({1.0f, 1.0f, 1.0f});
// ctx.underground_directional_light->set_illuminance(2.0f);
// ctx.underground_directional_light->set_direction(math::normalize(math::vector<float, 3>{0, -1, 0}));
// ctx.underground_directional_light->set_shadow_caster(true); // ctx.underground_directional_light->set_shadow_caster(true);
// ctx.underground_directional_light->set_shadow_framebuffer(ctx.shadow_map_framebuffer); // ctx.underground_directional_light->set_shadow_framebuffer(ctx.shadow_map_framebuffer);
// ctx.underground_directional_light->set_shadow_bias(0.005f); // ctx.underground_directional_light->set_shadow_bias(0.005f);
@ -123,16 +127,41 @@ nest_view_state::nest_view_state(::game& ctx):
// Create ambient light // Create ambient light
ctx.underground_ambient_light = std::make_unique<scene::ambient_light>(); ctx.underground_ambient_light = std::make_unique<scene::ambient_light>();
ctx.underground_ambient_light->set_illuminance(float3{1.0f, 1.0f, 1.0f} * 0.075f);
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_scene->add_object(*ctx.underground_ambient_light);
// Create sphere light
ctx.underground_sphere_light = std::make_unique<scene::sphere_light>();
ctx.underground_sphere_light->set_color({0.8f, 0.88f, 1.0f});
ctx.underground_sphere_light->set_luminous_power(300.0f);
ctx.underground_sphere_light->set_radius(3.0f);
ctx.underground_sphere_light->set_translation(float3{-13.0f, 7.0f, -6.0f});
ctx.underground_scene->add_object(*ctx.underground_sphere_light);
//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);
const math::vector3<float> light_color{1.0f, 1.0f, 1.0f};
// Create rectangle light
ctx.underground_rectangle_light = std::make_unique<scene::rectangle_light>();
ctx.underground_rectangle_light->set_color(light_color);
ctx.underground_rectangle_light->set_luminous_flux(1000.0f);
ctx.underground_rectangle_light->set_translation({-13.0f, 5.0f, -5.0f});
ctx.underground_rectangle_light->set_rotation(math::quaternion<float>::rotate_x(math::radians(90.0f)));
ctx.underground_rectangle_light->set_scale(7.0f);
ctx.underground_scene->add_object(*ctx.underground_rectangle_light);
// Create light rectangle
auto light_rectangle_model = ctx.resource_manager->load<render::model>("light-rectangle.mdl");
auto light_rectangle_material = std::make_shared<render::material>(*light_rectangle_model->get_groups().front().material);
light_rectangle_emissive = std::static_pointer_cast<render::material_float3>(light_rectangle_material->get_variable("emissive"));
light_rectangle_emissive->set(ctx.underground_rectangle_light->get_colored_luminance());
auto light_rectangle_static_mesh = std::make_shared<scene::static_mesh>(light_rectangle_model);
light_rectangle_static_mesh->set_material(0, light_rectangle_material);
auto light_rectangle_eid = ctx.entity_registry->create();
ctx.entity_registry->emplace<scene_component>(light_rectangle_eid, std::move(light_rectangle_static_mesh), std::uint8_t{2});
ctx.entity_registry->patch<scene_component>
(
light_rectangle_eid,
[&](auto& component)
{
component.object->set_transform(ctx.underground_rectangle_light->get_transform());
}
);
// Create chamber // Create chamber
auto chamber_eid = ctx.entity_registry->create(); auto chamber_eid = ctx.entity_registry->create();
@ -177,27 +206,7 @@ nest_view_state::nest_view_state(::game& ctx):
suzanne_eid, suzanne_eid,
[&](auto& component) [&](auto& component)
{ {
component.object->set_translation({-13.0f, -1.0f, -6.0f});
}
);
// Create light sphere
auto light_sphere_model = ctx.resource_manager->load<render::model>("light-sphere.mdl");
auto light_sphere_material = std::make_shared<render::material>(*light_sphere_model->get_groups().front().material);
static_cast<render::material_float3&>(*light_sphere_material->get_variable("emissive")).set(ctx.underground_sphere_light->get_spectral_luminance());
auto light_sphere_static_mesh = std::make_shared<scene::static_mesh>(light_sphere_model);
light_sphere_static_mesh->set_material(0, light_sphere_material);
auto light_sphere_eid = ctx.entity_registry->create();
ctx.entity_registry->emplace<scene_component>(light_sphere_eid, std::move(light_sphere_static_mesh), std::uint8_t{2});
ctx.entity_registry->patch<scene_component>
(
light_sphere_eid,
[&](auto& component)
{
component.object->set_translation(ctx.underground_sphere_light->get_translation());
component.object->set_scale(math::vector<float, 3>{1, 1, 1} * ctx.underground_sphere_light->get_radius());
component.object->set_translation({-13.0f, 0.5f, -6.0f});
} }
); );
@ -336,6 +345,8 @@ void nest_view_state::rotate_third_person_camera(const input::mouse_moved_event&
void nest_view_state::handle_mouse_motion(const input::mouse_moved_event& event) void nest_view_state::handle_mouse_motion(const input::mouse_moved_event& event)
{ {
ctx.underground_material_pass->set_mouse_position(float2(event.position));
if (!mouse_look && !mouse_grip && !mouse_zoom) if (!mouse_look && !mouse_grip && !mouse_zoom)
{ {
return; return;

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

@ -103,6 +103,8 @@ private:
}; };
std::vector<std::optional<camera_preset>> camera_presets{10}; std::vector<std::optional<camera_preset>> camera_presets{10};
std::shared_ptr<render::material_float3> light_rectangle_emissive;
}; };
#endif // ANTKEEPER_NEST_VIEW_STATE_HPP #endif // ANTKEEPER_NEST_VIEW_STATE_HPP

+ 13
- 38
src/game/systems/astronomy-system.cpp View File

@ -37,7 +37,7 @@
#include <engine/astro/apparent-size.hpp> #include <engine/astro/apparent-size.hpp>
#include <engine/geom/solid-angle.hpp> #include <engine/geom/solid-angle.hpp>
#include <engine/math/polynomial.hpp> #include <engine/math/polynomial.hpp>
#include <engine/debug/log.hpp>
astronomy_system::astronomy_system(entity::registry& registry): astronomy_system::astronomy_system(entity::registry& registry):
updatable_system(registry), updatable_system(registry),
time_days(0.0), time_days(0.0),
@ -49,8 +49,6 @@ astronomy_system::astronomy_system(entity::registry& registry):
sun_light(nullptr), sun_light(nullptr),
sky_light(nullptr), sky_light(nullptr),
moon_light(nullptr), moon_light(nullptr),
bounce_light(nullptr),
bounce_albedo{0, 0, 0},
sky_pass(nullptr), sky_pass(nullptr),
starlight_illuminance{0, 0, 0} starlight_illuminance{0, 0, 0}
{ {
@ -159,12 +157,9 @@ void astronomy_system::update(float t, float dt)
} }
); );
constexpr double3 bounce_normal = {0, 1, 0};
double3 bounce_illuminance = {0, 0, 0};
// Update blackbody lighting // Update blackbody lighting
registry.view<celestial_body_component, orbit_component, blackbody_component>().each( registry.view<celestial_body_component, orbit_component, blackbody_component>().each(
[&, bounce_normal](entity::id entity_id, const auto& blackbody_body, const auto& blackbody_orbit, const auto& blackbody)
[&](entity::id entity_id, const auto& blackbody_body, const auto& blackbody_orbit, const auto& blackbody)
{ {
// Transform blackbody position from ICRF frame to EUS frame // Transform blackbody position from ICRF frame to EUS frame
const double3 blackbody_position_eus = icrf_to_eus * blackbody_orbit.position; const double3 blackbody_position_eus = icrf_to_eus * blackbody_orbit.position;
@ -178,7 +173,7 @@ void astronomy_system::update(float t, float dt)
const double observer_blackbody_solid_angle = geom::solid_angle::cone(observer_blackbody_angular_radius); const double observer_blackbody_solid_angle = geom::solid_angle::cone(observer_blackbody_angular_radius);
// Calculate illuminance from blackbody reaching observer // Calculate illuminance from blackbody reaching observer
const double3 observer_blackbody_illuminance = blackbody.luminance * observer_blackbody_solid_angle;
const double3 observer_blackbody_illuminance = blackbody.color * blackbody.luminance * observer_blackbody_solid_angle;
// Calculate illuminance from blackbody reaching observer after atmospheric extinction // Calculate illuminance from blackbody reaching observer after atmospheric extinction
double3 observer_blackbody_transmitted_illuminance = observer_blackbody_illuminance; double3 observer_blackbody_transmitted_illuminance = observer_blackbody_illuminance;
@ -207,10 +202,8 @@ void astronomy_system::update(float t, float dt)
) )
); );
sun_light->set_illuminance(float3(observer_blackbody_transmitted_illuminance));
// Bounce sun light
bounce_illuminance += std::max(0.0, math::dot(bounce_normal, -observer_blackbody_direction_eus)) * observer_blackbody_transmitted_illuminance * bounce_albedo;
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 // Update sky light
@ -227,24 +220,22 @@ void astronomy_system::update(float t, float dt)
sky_light_illuminance += starlight_illuminance; sky_light_illuminance += starlight_illuminance;
// Update sky light // Update sky light
sky_light->set_illuminance(float3(sky_light_illuminance));
// Bounce sky light
bounce_illuminance += sky_light_illuminance * bounce_albedo;
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)));
} }
// Upload blackbody params to sky pass // Upload blackbody params to sky pass
if (this->sky_pass) if (this->sky_pass)
{ {
this->sky_pass->set_sun_position(float3(blackbody_position_eus)); this->sky_pass->set_sun_position(float3(blackbody_position_eus));
this->sky_pass->set_sun_luminance(float3(blackbody.luminance));
this->sky_pass->set_sun_luminance(float3(blackbody.color * blackbody.luminance));
this->sky_pass->set_sun_illuminance(float3(observer_blackbody_illuminance), float3(observer_blackbody_transmitted_illuminance)); this->sky_pass->set_sun_illuminance(float3(observer_blackbody_illuminance), float3(observer_blackbody_transmitted_illuminance));
this->sky_pass->set_sun_angular_radius(static_cast<float>(observer_blackbody_angular_radius)); this->sky_pass->set_sun_angular_radius(static_cast<float>(observer_blackbody_angular_radius));
} }
// Update diffuse reflectors // Update diffuse reflectors
this->registry.view<celestial_body_component, orbit_component, diffuse_reflector_component, transform_component>().each( this->registry.view<celestial_body_component, orbit_component, diffuse_reflector_component, transform_component>().each(
[&, bounce_normal](entity::id entity_id, const auto& reflector_body, const auto& reflector_orbit, const auto& reflector, const auto& transform)
[&](entity::id entity_id, const auto& reflector_body, const auto& reflector_orbit, const auto& reflector, const auto& transform)
{ {
// Transform reflector position from ICRF frame to EUS frame // Transform reflector position from ICRF frame to EUS frame
const double3 reflector_position_eus = icrf_to_eus * reflector_orbit.position; const double3 reflector_position_eus = icrf_to_eus * reflector_orbit.position;
@ -263,7 +254,7 @@ void astronomy_system::update(float t, float dt)
const double reflector_blackbody_solid_angle = geom::solid_angle::cone(reflector_blackbody_angular_radius); const double reflector_blackbody_solid_angle = geom::solid_angle::cone(reflector_blackbody_angular_radius);
// Calculate blackbody illuminance reaching reflector // Calculate blackbody illuminance reaching reflector
const double3 reflector_blackbody_illuminance = blackbody.luminance * reflector_blackbody_solid_angle;
const double3 reflector_blackbody_illuminance = blackbody.color * blackbody.luminance * reflector_blackbody_solid_angle;
// Measure reflector solid angle as seen by observer // Measure reflector solid angle as seen by observer
const double observer_reflector_angular_radius = astro::angular_radius(reflector_body.radius, observer_reflector_distance); const double observer_reflector_angular_radius = astro::angular_radius(reflector_body.radius, observer_reflector_distance);
@ -315,7 +306,9 @@ void astronomy_system::update(float t, float dt)
{ {
const float3 reflector_up_eus = float3(icrf_to_eus.r * double3{0, 0, 1}); const float3 reflector_up_eus = float3(icrf_to_eus.r * double3{0, 0, 1});
this->moon_light->set_illuminance(float3(observer_reflector_illuminance));
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)));
this->moon_light->set_rotation this->moon_light->set_rotation
( (
math::look_rotation math::look_rotation
@ -324,17 +317,9 @@ void astronomy_system::update(float t, float dt)
reflector_up_eus reflector_up_eus
) )
); );
// Bounce moon light
bounce_illuminance += std::max(0.0, math::dot(bounce_normal, -observer_reflector_direction_eus)) * observer_reflector_illuminance * bounce_albedo;
} }
}); });
}); });
if (bounce_light)
{
bounce_light->set_illuminance(float3(bounce_illuminance));
}
} }
void astronomy_system::set_time(double t) void astronomy_system::set_time(double t)
@ -381,16 +366,6 @@ void astronomy_system::set_moon_light(scene::directional_light* light)
moon_light = light; moon_light = light;
} }
void astronomy_system::set_bounce_light(scene::directional_light* light)
{
bounce_light = light;
}
void astronomy_system::set_bounce_albedo(const double3& albedo)
{
bounce_albedo = albedo;
}
void astronomy_system::set_starlight_illuminance(const double3& illuminance) void astronomy_system::set_starlight_illuminance(const double3& illuminance)
{ {
starlight_illuminance = illuminance; starlight_illuminance = illuminance;

+ 0
- 4
src/game/systems/astronomy-system.hpp View File

@ -83,8 +83,6 @@ public:
void set_sun_light(scene::directional_light* light); void set_sun_light(scene::directional_light* light);
void set_sky_light(scene::ambient_light* light); void set_sky_light(scene::ambient_light* light);
void set_moon_light(scene::directional_light* light); void set_moon_light(scene::directional_light* light);
void set_bounce_light(scene::directional_light* light);
void set_bounce_albedo(const double3& albedo);
void set_starlight_illuminance(const double3& illuminance); void set_starlight_illuminance(const double3& illuminance);
void set_sky_pass(::render::sky_pass* pass); void set_sky_pass(::render::sky_pass* pass);
@ -156,8 +154,6 @@ private:
scene::directional_light* sun_light; scene::directional_light* sun_light;
scene::ambient_light* sky_light; scene::ambient_light* sky_light;
scene::directional_light* moon_light; scene::directional_light* moon_light;
scene::directional_light* bounce_light;
double3 bounce_albedo;
::render::sky_pass* sky_pass; ::render::sky_pass* sky_pass;
double3 starlight_illuminance; double3 starlight_illuminance;
}; };

+ 28
- 42
src/game/systems/blackbody-system.cpp View File

@ -24,27 +24,24 @@
#include <engine/math/quadrature.hpp> #include <engine/math/quadrature.hpp>
#include <numeric> #include <numeric>
blackbody_system::blackbody_system(entity::registry& registry): blackbody_system::blackbody_system(entity::registry& registry):
updatable_system(registry),
illuminant(color::illuminant::deg2::d50<double>)
updatable_system(registry)
{ {
// Construct a range of sample wavelengths in the visible spectrum // Construct a range of sample wavelengths in the visible spectrum
visible_wavelengths_nm.resize(780 - 280);
std::iota(visible_wavelengths_nm.begin(), visible_wavelengths_nm.end(), 280);
m_visible_wavelengths_nm.resize(780 - 280);
std::iota(m_visible_wavelengths_nm.begin(), m_visible_wavelengths_nm.end(), 280);
// Set illuminant
set_illuminant(color::illuminant::deg2::d50<double>);
registry.on_construct<::blackbody_component>().connect<&blackbody_system::on_blackbody_construct>(this); registry.on_construct<::blackbody_component>().connect<&blackbody_system::on_blackbody_construct>(this);
registry.on_update<::blackbody_component>().connect<&blackbody_system::on_blackbody_update>(this); registry.on_update<::blackbody_component>().connect<&blackbody_system::on_blackbody_update>(this);
registry.on_construct<::celestial_body_component>().connect<&blackbody_system::on_celestial_body_construct>(this);
registry.on_update<::celestial_body_component>().connect<&blackbody_system::on_celestial_body_update>(this);
} }
blackbody_system::~blackbody_system() blackbody_system::~blackbody_system()
{ {
registry.on_construct<::blackbody_component>().disconnect<&blackbody_system::on_blackbody_construct>(this); registry.on_construct<::blackbody_component>().disconnect<&blackbody_system::on_blackbody_construct>(this);
registry.on_update<::blackbody_component>().disconnect<&blackbody_system::on_blackbody_update>(this); registry.on_update<::blackbody_component>().disconnect<&blackbody_system::on_blackbody_update>(this);
registry.on_construct<::celestial_body_component>().disconnect<&blackbody_system::on_celestial_body_construct>(this);
registry.on_update<::celestial_body_component>().disconnect<&blackbody_system::on_celestial_body_update>(this);
} }
void blackbody_system::update(float t, float dt) void blackbody_system::update(float t, float dt)
@ -52,59 +49,48 @@ void blackbody_system::update(float t, float dt)
void blackbody_system::set_illuminant(const math::vector2<double>& illuminant) void blackbody_system::set_illuminant(const math::vector2<double>& illuminant)
{ {
this->illuminant = illuminant;
m_illuminant = illuminant;
m_xyz_to_rgb = color::aces::ap1<double>.from_xyz * color::cat::matrix(m_illuminant, color::aces::white_point<double>);
} }
void blackbody_system::update_luminance(entity::id entity_id)
void blackbody_system::update_blackbody(entity::id entity_id)
{ {
// Get blackbody and celestial body components of the entity
auto [blackbody, celestial_body] = registry.try_get<blackbody_component, celestial_body_component>(entity_id);
// Abort if entity is missing a blackbody or celestial body component
if (!blackbody || !celestial_body)
return;
// Construct chromatic adaptation transform
const double3x3 cat = color::cat::matrix(illuminant, color::aces::white_point<double>);
// Get blackbody component
auto& blackbody = registry.get<blackbody_component>(entity_id);
// Construct a lambda function which calculates the blackbody's RGB luminance of a given wavelength // Construct a lambda function which calculates the blackbody's RGB luminance of a given wavelength
auto rgb_luminance = [temperature = blackbody->temperature, cat](double wavelength_nm) -> double3
auto rgb_spectral_luminance = [&](double wavelength_nm) -> math::vector3<double>
{ {
// Convert wavelength from nanometers to meters // Convert wavelength from nanometers to meters
const double wavelength_m = wavelength_nm * 1e-9; const double wavelength_m = wavelength_nm * 1e-9;
// Calculate the spectral intensity of the wavelength
const double spectral_radiance = physics::light::blackbody::spectral_radiance<double>(temperature, wavelength_m);
// Calculate the spectral radiance of the wavelength
const double spectral_radiance = physics::light::blackbody::spectral_radiance<double>(blackbody.temperature, wavelength_m);
// Convert spectral radiance to spectral luminance
const double spectral_luminance = spectral_radiance * 1e-9 * physics::light::max_luminous_efficacy<double>;
// Calculate the ACEScg color of the wavelength using CIE color matching functions
double3 spectral_color = color::aces::ap1<double>.from_xyz * cat * color::xyz::match(wavelength_nm);
// Calculate the XYZ color of the wavelength using CIE color matching functions then transform to RGB
const math::vector3<double> rgb_color = m_xyz_to_rgb * color::xyz::match(wavelength_nm);
// Scale the spectral color by spectral intensity
return spectral_color * spectral_radiance * 1e-9 * physics::light::max_luminous_efficacy<double>;
// Scale RGB color by spectral luminance
return rgb_color * spectral_luminance;
}; };
// Integrate the blackbody RGB luminance over wavelengths in the visible spectrum
blackbody->luminance = math::quadrature::simpson(rgb_luminance, visible_wavelengths_nm.begin(), visible_wavelengths_nm.end());
// Integrate the blackbody RGB spectral luminance over wavelengths in the visible spectrum
const math::vector3<double> rgb_luminance = math::quadrature::simpson(rgb_spectral_luminance, m_visible_wavelengths_nm.begin(), m_visible_wavelengths_nm.end());
// Extract luminance and color from RGB luminance
blackbody.luminance = math::max(rgb_luminance);
blackbody.color = rgb_luminance / blackbody.luminance;
} }
void blackbody_system::on_blackbody_construct(entity::registry& registry, entity::id entity_id) void blackbody_system::on_blackbody_construct(entity::registry& registry, entity::id entity_id)
{ {
update_luminance(entity_id);
update_blackbody(entity_id);
} }
void blackbody_system::on_blackbody_update(entity::registry& registry, entity::id entity_id) void blackbody_system::on_blackbody_update(entity::registry& registry, entity::id entity_id)
{ {
update_luminance(entity_id);
}
void blackbody_system::on_celestial_body_construct(entity::registry& registry, entity::id entity_id)
{
update_luminance(entity_id);
}
void blackbody_system::on_celestial_body_update(entity::registry& registry, entity::id entity_id)
{
update_luminance(entity_id);
update_blackbody(entity_id);
} }

+ 8
- 11
src/game/systems/blackbody-system.hpp View File

@ -22,14 +22,13 @@
#include "game/systems/updatable-system.hpp" #include "game/systems/updatable-system.hpp"
#include <engine/entity/id.hpp> #include <engine/entity/id.hpp>
#include <engine/utility/fundamental-types.hpp>
#include <engine/math/vector.hpp>
#include <engine/math/matrix.hpp>
#include "game/components/blackbody-component.hpp" #include "game/components/blackbody-component.hpp"
#include "game/components/celestial-body-component.hpp"
#include <vector> #include <vector>
/** /**
* Calculates the RGB luminous intensity of blackbody radiators.
* Calculates the color and luminance of blackbody radiators.
*/ */
class blackbody_system: class blackbody_system:
public updatable_system public updatable_system
@ -38,7 +37,7 @@ public:
explicit blackbody_system(entity::registry& registry); explicit blackbody_system(entity::registry& registry);
~blackbody_system(); ~blackbody_system();
virtual void update(float t, float dt);
void update(float t, float dt) override;
/** /**
* Sets the blackbody illuminant. * Sets the blackbody illuminant.
@ -48,16 +47,14 @@ public:
void set_illuminant(const math::vector2<double>& illuminant); void set_illuminant(const math::vector2<double>& illuminant);
private: private:
void update_luminance(entity::id entity_id);
void update_blackbody(entity::id entity_id);
void on_blackbody_construct(entity::registry& registry, entity::id entity_id); void on_blackbody_construct(entity::registry& registry, entity::id entity_id);
void on_blackbody_update(entity::registry& registry, entity::id entity_id); void on_blackbody_update(entity::registry& registry, entity::id entity_id);
void on_celestial_body_construct(entity::registry& registry, entity::id entity_id);
void on_celestial_body_update(entity::registry& registry, entity::id entity_id);
math::vector2<double> illuminant;
std::vector<double> visible_wavelengths_nm;
std::vector<double> m_visible_wavelengths_nm;
math::vector2<double> m_illuminant;
math::matrix3x3<double> m_xyz_to_rgb;
}; };

+ 0
- 11
src/game/world.cpp View File

@ -361,7 +361,6 @@ void create_sun(::game& ctx)
// Create sun directional light scene object // Create sun directional light scene object
ctx.sun_light = std::make_unique<scene::directional_light>(); ctx.sun_light = std::make_unique<scene::directional_light>();
ctx.sun_light->set_illuminance({0, 0, 0});
ctx.sun_light->set_shadow_caster(true); ctx.sun_light->set_shadow_caster(true);
ctx.sun_light->set_shadow_framebuffer(ctx.shadow_map_framebuffer); ctx.sun_light->set_shadow_framebuffer(ctx.shadow_map_framebuffer);
ctx.sun_light->set_shadow_bias(0.005f); ctx.sun_light->set_shadow_bias(0.005f);
@ -371,22 +370,14 @@ void create_sun(::game& ctx)
// Create sky ambient light scene object // Create sky ambient light scene object
ctx.sky_light = std::make_unique<scene::ambient_light>(); ctx.sky_light = std::make_unique<scene::ambient_light>();
ctx.sky_light->set_illuminance({0, 0, 0});
// Create bounce directional light scene object
ctx.bounce_light = std::make_unique<scene::directional_light>();
ctx.bounce_light->set_illuminance({0, 0, 0});
ctx.bounce_light->look_at({0, 0, 0}, {0, 1, 0}, {1, 0, 0});
// Add sun light scene objects to surface scene // Add sun light scene objects to surface scene
ctx.surface_scene->add_object(*ctx.sun_light); ctx.surface_scene->add_object(*ctx.sun_light);
ctx.surface_scene->add_object(*ctx.sky_light); ctx.surface_scene->add_object(*ctx.sky_light);
//ctx.surface_scene->add_object(ctx.bounce_light);
// Pass direct sun light scene object to shadow map pass and astronomy system // 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_sun_light(ctx.sun_light.get());
ctx.astronomy_system->set_sky_light(ctx.sky_light.get()); ctx.astronomy_system->set_sky_light(ctx.sky_light.get());
ctx.astronomy_system->set_bounce_light(ctx.bounce_light.get());
} }
debug::log::trace("Generated Sun"); debug::log::trace("Generated Sun");
@ -447,7 +438,6 @@ void create_moon(::game& ctx)
// Create moon directional light scene object // Create moon directional light scene object
ctx.moon_light = std::make_unique<scene::directional_light>(); ctx.moon_light = std::make_unique<scene::directional_light>();
ctx.moon_light->set_illuminance({0, 0, 0});
// Add moon light scene objects to surface scene // Add moon light scene objects to surface scene
ctx.surface_scene->add_object(*ctx.moon_light); ctx.surface_scene->add_object(*ctx.moon_light);
@ -556,7 +546,6 @@ void enter_ecoregion(::game& ctx, const ecoregion& ecoregion)
return y; return y;
} }
); );
ctx.astronomy_system->set_bounce_albedo(double3(ecoregion.terrain_albedo));
} }
debug::log::trace("Entered ecoregion {}", ecoregion.name); debug::log::trace("Entered ecoregion {}", ecoregion.name);

Loading…
Cancel
Save