Browse Source

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

master
C. J. Howard 11 months 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)
option(APPLICATION_NAME "Application name" "Antkeeper")
option(APPLICATION_VERSION "Application version string" "0.0.0")
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>
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>
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.
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.
const math::matrix3x3<T> to_xyz;
@ -106,7 +106,7 @@ 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 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.
@ -118,13 +118,13 @@ struct color_space
};
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),
g(g),
b(b),
w(w),
eotf(eotf),
inverse_eotf(inverse_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]}

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

@ -28,14 +28,14 @@
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>
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
{
@ -44,21 +44,21 @@ math::vector3 srgb_eotf(const math::vector3& v)
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>
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
{
@ -67,9 +67,9 @@ math::vector3 srgb_inverse_eotf(const math::vector3& l)
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}},
color::illuminant::deg2::d65<T>,
&srgb_eotf<T>,
&srgb_inverse_eotf
&srgb_oetf<T>
);
} // 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>
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.
*
@ -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.
*/
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.
@ -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.
*/
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.
@ -136,7 +125,7 @@ T spectral_exitance(T t, T lambda, T c)
const T lambda2 = lambda * lambda;
// 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)
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;
// First radiation constant (c1L)
const T c1l = T(2) * hc * c;
const T c1l = T{2} * hc * c;
// Second radiation constant (c2)
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 <glad/glad.h>
#include <engine/utility/hash/fnv1a.hpp>
#include <engine/debug/log.hpp>
namespace render {
@ -49,6 +50,11 @@ final_pass::final_pass(gl::rasterizer* rasterizer, const gl::framebuffer* frameb
// Load shader template and build shader program
auto shader_template = resource_manager->load<gl::shader_template>("final.glsl");
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[] =
{

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

@ -41,7 +41,8 @@
#include <engine/scene/ambient-light.hpp>
#include <engine/scene/directional-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/math/quaternion.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):
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)
{
@ -315,7 +320,8 @@ void material_pass::evaluate_lighting(const render::context& ctx)
directional_light_count = 0;
directional_shadow_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);
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[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;
}
@ -355,7 +359,7 @@ void material_pass::evaluate_lighting(const render::context& ctx)
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();
// 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_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_directions[index] = spot_light.get_direction();
spot_light_cutoffs[index] = spot_light.get_cosine_cutoff();
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;
@ -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>{}(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>{}(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)
@ -497,7 +503,7 @@ std::unique_ptr material_pass::generate_shader_program(const
definitions["DIRECTIONAL_SHADOW_COUNT"] = std::to_string(directional_shadow_count);
definitions["POINT_LIGHT_COUNT"] = std::to_string(point_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);
@ -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);});
}
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
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
(
[&, 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.
void set_fallback_material(std::shared_ptr<render::material> fallback);
inline void set_mouse_position(const float2& position)
{
mouse_position = position;
}
private:
struct shader_cache_entry
{
@ -120,10 +125,14 @@ private:
std::vector<float2> spot_light_cutoffs;
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
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();
if (sky_shader_program)
if (sky_shader_program->linked())
{
model_view_projection_var = sky_shader_program->variable("model_view_projection");
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_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
@ -408,7 +413,7 @@ void sky_pass::set_moon_model(std::shared_ptr model)
{
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_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_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
@ -447,13 +457,18 @@ void sky_pass::set_stars_model(std::shared_ptr model)
{
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_projection_var = star_shader_program->variable("projection");
star_distance_var = star_shader_program->variable("star_distance");
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

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/>.
*/
#include <engine/scene/sphere-light.hpp>
#include <engine/math/numbers.hpp>
#include <engine/scene/ambient-light.hpp>
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

+ 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;
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;
}
/// 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:
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

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

@ -32,6 +32,9 @@ namespace scene {
class collection
{
public:
/// @name Objects
/// @{
/**
* Adds an object to the collection.
*
@ -66,10 +69,33 @@ public:
{
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:
std::vector<object_base*> m_objects;
mutable std::unordered_map<std::size_t, std::vector<object_base*>> m_object_map;
float m_scale{1.0f};
};
} // 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)
{}
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
@ -65,7 +65,17 @@ void directional_light::set_shadow_cascade_distribution(float weight) noexcept
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

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

@ -43,37 +43,61 @@ public:
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
/// @{
/**
* 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;
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;
}
/**
* 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:
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};
std::shared_ptr<gl::framebuffer> m_shadow_framebuffer{nullptr};
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,
/// Sphere light.
sphere
/// Point light.
point,
/// Rectangle light.
rectangle
};
} // 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);
/**
* Sets the scene object's transform.
* Sets the transform of the object.
*
* @param transform Object 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)
{
@ -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)
{
m_transform.rotation = rotation;
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)
{
m_transform.scale = scale;
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
{
return m_transform;
}
/**
* Returns the transform's translation vector.
*/
/// Returns the translation of the object.
[[nodiscard]] inline const vector_type& get_translation() const noexcept
{
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
{
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
{
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;
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:
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, 2> m_cutoff{math::pi<float>, math::pi<float>};
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
#define ANTKEEPER_GAME_BLACKBODY_COMPONENT_HPP
#include <engine/math/vector.hpp>
/// Blackbody radiator
struct blackbody_component
{
/// 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

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

@ -795,12 +795,16 @@ void game::setup_scenes()
{
debug::log::trace("Setting up scenes...");
// Ratio of meters to scene units.
constexpr float scene_scale = 1.0f / 100.0f;
// Get default framebuffer
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]);
// Allocate surface scene
// Allocate and init surface scene
surface_scene = std::make_unique<scene::collection>();
surface_scene->set_scale(scene_scale);
// Allocate and init surface 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_composite_index(0);
// Allocate underground scene
// Allocate and init underground scene
underground_scene = std::make_unique<scene::collection>();
underground_scene->set_scale(scene_scale);
// Allocate and init underground 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/scene/text.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/ambient-light.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> moon_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::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::sphere_light> underground_sphere_light;
std::unique_ptr<scene::rectangle_light> underground_rectangle_light;
scene::collection* active_scene;
// 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);
// 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
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/render/passes/clear-pass.hpp>
#include <engine/render/passes/ground-pass.hpp>
#include <engine/render/passes/material-pass.hpp>
#include <engine/resources/resource-manager.hpp>
#include <engine/utility/state-machine.hpp>
#include <engine/scene/static-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/animation/ease.hpp>
#include <engine/color/color.hpp>
nest_view_state::nest_view_state(::game& ctx):
game_state(ctx)
@ -110,9 +113,10 @@ nest_view_state::nest_view_state(::game& ctx):
debug::log::trace("Generated worker model");
// 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_framebuffer(ctx.shadow_map_framebuffer);
// ctx.underground_directional_light->set_shadow_bias(0.005f);
@ -123,16 +127,41 @@ nest_view_state::nest_view_state(::game& ctx):
// Create 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);
// 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
auto chamber_eid = ctx.entity_registry->create();
@ -177,27 +206,7 @@ nest_view_state::nest_view_state(::game& ctx):
suzanne_eid,
[&](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)
{
ctx.underground_material_pass->set_mouse_position(float2(event.position));
if (!mouse_look && !mouse_grip && !mouse_zoom)
{
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::shared_ptr<render::material_float3> light_rectangle_emissive;
};
#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/geom/solid-angle.hpp>
#include <engine/math/polynomial.hpp>
#include <engine/debug/log.hpp>
astronomy_system::astronomy_system(entity::registry& registry):
updatable_system(registry),
time_days(0.0),
@ -49,8 +49,6 @@ astronomy_system::astronomy_system(entity::registry& registry):
sun_light(nullptr),
sky_light(nullptr),
moon_light(nullptr),
bounce_light(nullptr),
bounce_albedo{0, 0, 0},
sky_pass(nullptr),
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
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
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);
// 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
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
@ -227,24 +220,22 @@ void astronomy_system::update(float t, float dt)
sky_light_illuminance += starlight_illuminance;
// 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
if (this->sky_pass)
{
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_angular_radius(static_cast<float>(observer_blackbody_angular_radius));
}
// Update diffuse reflectors
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
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);
// 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
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});
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
(
math::look_rotation
@ -324,17 +317,9 @@ void astronomy_system::update(float t, float dt)
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)
@ -381,16 +366,6 @@ void astronomy_system::set_moon_light(scene::directional_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)
{
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_sky_light(scene::ambient_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_sky_pass(::render::sky_pass* pass);
@ -156,8 +154,6 @@ private:
scene::directional_light* sun_light;
scene::ambient_light* sky_light;
scene::directional_light* moon_light;
scene::directional_light* bounce_light;
double3 bounce_albedo;
::render::sky_pass* sky_pass;
double3 starlight_illuminance;
};

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

@ -24,27 +24,24 @@
#include <engine/math/quadrature.hpp>
#include <numeric>
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
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_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()
{
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_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)
@ -52,59 +49,48 @@ void blackbody_system::update(float t, float dt)
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
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
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)
{
update_luminance(entity_id);
update_blackbody(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 <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/celestial-body-component.hpp"
#include <vector>
/**
* Calculates the RGB luminous intensity of blackbody radiators.
* Calculates the color and luminance of blackbody radiators.
*/
class blackbody_system:
public updatable_system
@ -38,7 +37,7 @@ public:
explicit blackbody_system(entity::registry& registry);
~blackbody_system();
virtual void update(float t, float dt);
void update(float t, float dt) override;
/**
* Sets the blackbody illuminant.
@ -48,16 +47,14 @@ public:
void set_illuminant(const math::vector2<double>& illuminant);
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_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
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_framebuffer(ctx.shadow_map_framebuffer);
ctx.sun_light->set_shadow_bias(0.005f);
@ -371,22 +370,14 @@ void create_sun(::game& ctx)
// Create sky ambient light scene object
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
ctx.surface_scene->add_object(*ctx.sun_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
ctx.astronomy_system->set_sun_light(ctx.sun_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");
@ -447,7 +438,6 @@ void create_moon(::game& ctx)
// Create moon directional light scene object
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
ctx.surface_scene->add_object(*ctx.moon_light);
@ -556,7 +546,6 @@ void enter_ecoregion(::game& ctx, const ecoregion& ecoregion)
return y;
}
);
ctx.astronomy_system->set_bounce_albedo(double3(ecoregion.terrain_albedo));
}
debug::log::trace("Entered ecoregion {}", ecoregion.name);

Loading…
Cancel
Save