From 1a6cfa65ff0eb78aa7c636a03bbf2e5f5abe2d3e Mon Sep 17 00:00:00 2001 From: "C. J. Howard" Date: Thu, 25 May 2023 02:25:26 +0800 Subject: [PATCH] Add rectangle area light. Replace sphere light with point light. Improve interface of all light classes --- CMakeLists.txt | 1 - src/engine/color/cat.hpp | 12 +- src/engine/color/rgb.hpp | 10 +- src/engine/color/srgb.hpp | 30 ++-- src/engine/physics/light/blackbody.hpp | 19 +-- src/engine/render/passes/final-pass.cpp | 6 + src/engine/render/passes/material-pass.cpp | 122 ++++++++++------- src/engine/render/passes/material-pass.hpp | 17 ++- src/engine/render/passes/sky-pass.cpp | 21 ++- .../{sphere-light.cpp => ambient-light.cpp} | 11 +- src/engine/scene/ambient-light.hpp | 41 +++++- src/engine/scene/collection.hpp | 26 ++++ src/engine/scene/directional-light.cpp | 16 ++- src/engine/scene/directional-light.hpp | 67 ++++++--- src/engine/scene/light-type.hpp | 7 +- src/engine/scene/object.hpp | 45 +++--- src/engine/scene/point-light.cpp | 34 +++++ src/engine/scene/point-light.hpp | 91 ++++++++++++ src/engine/scene/rectangle-light.cpp | 80 +++++++++++ src/engine/scene/rectangle-light.hpp | 129 ++++++++++++++++++ src/engine/scene/sphere-light.hpp | 116 ---------------- src/engine/scene/spot-light.hpp | 16 +-- src/game/components/blackbody-component.hpp | 11 +- src/game/game.cpp | 9 +- src/game/game.hpp | 5 +- src/game/states/nest-selection-state.cpp | 2 +- src/game/states/nest-view-state.cpp | 77 ++++++----- src/game/states/nest-view-state.hpp | 2 + src/game/systems/astronomy-system.cpp | 51 ++----- src/game/systems/astronomy-system.hpp | 4 - src/game/systems/blackbody-system.cpp | 70 ++++------ src/game/systems/blackbody-system.hpp | 19 ++- src/game/world.cpp | 11 -- 33 files changed, 749 insertions(+), 429 deletions(-) rename src/engine/scene/{sphere-light.cpp => ambient-light.cpp} (72%) create mode 100644 src/engine/scene/point-light.cpp create mode 100644 src/engine/scene/point-light.hpp create mode 100644 src/engine/scene/rectangle-light.cpp create mode 100644 src/engine/scene/rectangle-light.hpp delete mode 100644 src/engine/scene/sphere-light.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 73e1a79..21ca183 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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") diff --git a/src/engine/color/cat.hpp b/src/engine/color/cat.hpp index 989ac90..731f8e5 100644 --- a/src/engine/color/cat.hpp +++ b/src/engine/color/cat.hpp @@ -37,9 +37,9 @@ namespace cat { template constexpr math::matrix 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 constexpr math::matrix 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} }; /** diff --git a/src/engine/color/rgb.hpp b/src/engine/color/rgb.hpp index 0874cf4..db601da 100644 --- a/src/engine/color/rgb.hpp +++ b/src/engine/color/rgb.hpp @@ -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 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& r, const math::vector2& g, const math::vector2& b, const math::vector2& w, transfer_function_type eotf, transfer_function_type inverse_eotf); + constexpr color_space(const math::vector2& r, const math::vector2& g, const math::vector2& b, const math::vector2& 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 -constexpr color_space::color_space(const math::vector2& r, const math::vector2& g, const math::vector2& b, const math::vector2& w, transfer_function_type eotf, transfer_function_type inverse_eotf): +constexpr color_space::color_space(const math::vector2& r, const math::vector2& g, const math::vector2& b, const math::vector2& 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(r, g, b, w)), from_xyz(math::inverse(to_xyz)), to_y{to_xyz[0][1], to_xyz[1][1], to_xyz[2][1]} diff --git a/src/engine/color/srgb.hpp b/src/engine/color/srgb.hpp index 806bff7..d10b8ff 100644 --- a/src/engine/color/srgb.hpp +++ b/src/engine/color/srgb.hpp @@ -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 -math::vector3 srgb_eotf(const math::vector3& v) +math::vector3 srgb_eotf(const math::vector3& x) { auto f = [](T x) -> T { @@ -44,21 +44,21 @@ math::vector3 srgb_eotf(const math::vector3& v) return math::vector3 { - 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 -math::vector3 srgb_inverse_eotf(const math::vector3& l) +math::vector3 srgb_oetf(const math::vector3& x) { auto f = [](T x) -> T { @@ -67,9 +67,9 @@ math::vector3 srgb_inverse_eotf(const math::vector3& l) return math::vector3 { - 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, &srgb_eotf, - &srgb_inverse_eotf + &srgb_oetf ); } // namespace color diff --git a/src/engine/physics/light/blackbody.hpp b/src/engine/physics/light/blackbody.hpp index cdf7596..318873f 100644 --- a/src/engine/physics/light/blackbody.hpp +++ b/src/engine/physics/light/blackbody.hpp @@ -63,17 +63,6 @@ T radiant_flux(T t, T a); template 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 -T spectral_exitance(T t, T lambda, T c = constants::speed_of_light); - /** * 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 -T spectral_flux(T t, T a, T lambda, T c = constants::speed_of_light); +T spectral_flux(T t, T a, T lambda, T c = constants::speed_of_light); /** * 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 -T spectral_intensity(T t, T a, T lambda, T omega, T c = constants::speed_of_light); +T spectral_intensity(T t, T a, T lambda, T omega, T c = constants::speed_of_light); /** * 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 * hc * c; + const T c1 = math::two_pi * hc * c; // Second radiation constant (c2) const T c2 = hc / constants::boltzmann; @@ -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; diff --git a/src/engine/render/passes/final-pass.cpp b/src/engine/render/passes/final-pass.cpp index 432904d..7ea52ca 100644 --- a/src/engine/render/passes/final-pass.cpp +++ b/src/engine/render/passes/final-pass.cpp @@ -35,6 +35,7 @@ #include #include #include +#include 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("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[] = { diff --git a/src/engine/render/passes/material-pass.cpp b/src/engine/render/passes/material-pass.cpp index 8d23dbb..29dd418 100644 --- a/src/engine/render/passes/material-pass.cpp +++ b/src/engine/render/passes/material-pass.cpp @@ -41,7 +41,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -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("ltc-lut-1.tex"); + ltc_lut_2 = resource_manager->load("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(light).get_illuminance() * ctx.camera->get_exposure_normalization(); + ambient_light_colors[index] = static_cast(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(light); + const scene::point_light& point_light = static_cast(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(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{}(directional_shadow_count)); lighting_state_hash = hash::combine(lighting_state_hash, std::hash{}(point_light_count)); lighting_state_hash = hash::combine(lighting_state_hash, std::hash{}(spot_light_count)); - lighting_state_hash = hash::combine(lighting_state_hash, std::hash{}(sphere_light_count)); + lighting_state_hash = hash::combine(lighting_state_hash, std::hash{}(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::vectorupdate(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::vectorupdate(std::span{sphere_light_colors.data(), sphere_light_count}); - sphere_light_positions_radii_var->update(std::span{sphere_light_positions_radii.data(), sphere_light_count}); + rectangle_light_colors_var->update(std::span{rectangle_light_colors.data(), rectangle_light_count}); + rectangle_light_corners_var->update(std::span{rectangle_light_corners.data(), rectangle_light_count * 4}); } ); } diff --git a/src/engine/render/passes/material-pass.hpp b/src/engine/render/passes/material-pass.hpp index cdeeda0..877d264 100644 --- a/src/engine/render/passes/material-pass.hpp +++ b/src/engine/render/passes/material-pass.hpp @@ -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 fallback); + inline void set_mouse_position(const float2& position) + { + mouse_position = position; + } + private: struct shader_cache_entry { @@ -120,10 +125,14 @@ private: std::vector spot_light_cutoffs; std::size_t spot_light_count; - // Sphere lights - std::vector sphere_light_colors; - std::vector sphere_light_positions_radii; - std::size_t sphere_light_count; + // Rectangle lights + std::vector rectangle_light_colors; + std::vector rectangle_light_corners; + std::size_t rectangle_light_count; + + // LTC + std::shared_ptr ltc_lut_1; + std::shared_ptr ltc_lut_2; // Misc float time; diff --git a/src/engine/render/passes/sky-pass.cpp b/src/engine/render/passes/sky-pass.cpp index 73144b1..c20dd12 100644 --- a/src/engine/render/passes/sky-pass.cpp +++ b/src/engine/render/passes/sky-pass.cpp @@ -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 diff --git a/src/engine/scene/sphere-light.cpp b/src/engine/scene/ambient-light.cpp similarity index 72% rename from src/engine/scene/sphere-light.cpp rename to src/engine/scene/ambient-light.cpp index c588a44..9ed076a 100644 --- a/src/engine/scene/sphere-light.cpp +++ b/src/engine/scene/ambient-light.cpp @@ -17,19 +17,18 @@ * along with Antkeeper source code. If not, see . */ -#include -#include +#include 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); + m_colored_illuminance = m_color * m_illuminance; } -math::vector 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 diff --git a/src/engine/scene/ambient-light.hpp b/src/engine/scene/ambient-light.hpp index b196475..ce944c4 100644 --- a/src/engine/scene/ambient-light.hpp +++ b/src/engine/scene/ambient-light.hpp @@ -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& illuminance) noexcept + inline void set_color(const math::vector3& 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& get_illuminance() const noexcept + /// Returns the color of the light. + [[nodiscard]] inline const math::vector3& 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& get_colored_illuminance() const noexcept + { + return m_colored_illuminance; + } + private: - math::vector m_illuminance{0.0f, 0.0f, 0.0f}; + void color_updated(); + void illuminance_updated(); + + math::vector3 m_color{1.0f, 1.0f, 1.0f}; + float m_illuminance{}; + math::vector3 m_colored_illuminance{}; }; } // namespace scene diff --git a/src/engine/scene/collection.hpp b/src/engine/scene/collection.hpp index 612b78f..301e83a 100644 --- a/src/engine/scene/collection.hpp +++ b/src/engine/scene/collection.hpp @@ -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 m_objects; mutable std::unordered_map> m_object_map; + float m_scale{1.0f}; }; } // namespace scene diff --git a/src/engine/scene/directional-light.cpp b/src/engine/scene/directional-light.cpp index 62e69d4..388add7 100644 --- a/src/engine/scene/directional-light.cpp +++ b/src/engine/scene/directional-light.cpp @@ -26,9 +26,9 @@ directional_light::directional_light(): m_shadow_cascade_matrices(m_shadow_cascade_count) {} -void directional_light::set_direction(const math::vector& direction) +void directional_light::set_direction(const math::vector3& direction) { - set_rotation(math::rotation(math::vector{0.0f, 0.0f, -1.0f}, direction)); + set_rotation(math::rotation(math::vector3{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{0.0f, 0.0f, -1.0f}; + m_direction = get_rotation() * math::vector3{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 diff --git a/src/engine/scene/directional-light.hpp b/src/engine/scene/directional-light.hpp index 00d322a..7ed9556 100644 --- a/src/engine/scene/directional-light.hpp +++ b/src/engine/scene/directional-light.hpp @@ -43,37 +43,61 @@ public: return light_type::directional; } - /// Returns a unit vector pointing in the light direction. - [[nodiscard]] inline const math::vector& 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& direction); + + /** + * Sets the color of the light. + * + * @param color Light color. + */ + inline void set_color(const math::vector3& 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& 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& get_illuminance() const noexcept + /// Returns a unit vector pointing in the light direction. + [[nodiscard]] inline const math::vector3& get_direction() const noexcept + { + return m_direction; + } + + /// Returns the color of the light. + [[nodiscard]] inline const math::vector3& 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& direction); + /// Returns the color-modulated illuminance of the light on a surface perpendicular to the light direction. + [[nodiscard]] inline const math::vector3& 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 m_direction{0.0f, 0.0f, -1.0f}; + math::vector3 m_color{1.0f, 1.0f, 1.0f}; + float m_illuminance{}; + math::vector3 m_colored_illuminance{}; - math::vector m_illuminance{0.0f, 0.0f, 0.0f}; - math::vector m_direction{0.0f, 0.0f, -1.0f}; bool m_shadow_caster{false}; std::shared_ptr m_shadow_framebuffer{nullptr}; float m_shadow_bias{0.005f}; diff --git a/src/engine/scene/light-type.hpp b/src/engine/scene/light-type.hpp index 732c5ca..1d117eb 100644 --- a/src/engine/scene/light-type.hpp +++ b/src/engine/scene/light-type.hpp @@ -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 diff --git a/src/engine/scene/object.hpp b/src/engine/scene/object.hpp index 1dade30..850d67d 100644 --- a/src/engine/scene/object.hpp +++ b/src/engine/scene/object.hpp @@ -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: diff --git a/src/engine/scene/point-light.cpp b/src/engine/scene/point-light.cpp new file mode 100644 index 0000000..f216a5c --- /dev/null +++ b/src/engine/scene/point-light.cpp @@ -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 . + */ + +#include + +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 diff --git a/src/engine/scene/point-light.hpp b/src/engine/scene/point-light.hpp new file mode 100644 index 0000000..e90738c --- /dev/null +++ b/src/engine/scene/point-light.hpp @@ -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 . + */ + +#ifndef ANTKEEPER_SCENE_POINT_LIGHT_HPP +#define ANTKEEPER_SCENE_POINT_LIGHT_HPP + +#include +#include + +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& 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& 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& get_colored_luminous_flux() const noexcept + { + return m_colored_luminous_flux; + } + +private: + void color_updated(); + void luminous_flux_updated(); + + math::vector3 m_color{1.0f, 1.0f, 1.0f}; + float m_luminous_flux{}; + math::vector3 m_colored_luminous_flux{}; +}; + +} // namespace scene + +#endif // ANTKEEPER_SCENE_POINT_LIGHT_HPP diff --git a/src/engine/scene/rectangle-light.cpp b/src/engine/scene/rectangle-light.cpp new file mode 100644 index 0000000..0f2acbe --- /dev/null +++ b/src/engine/scene/rectangle-light.cpp @@ -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 . + */ + +#include +#include + +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{-0.5f, 0.0f, -0.5f}; + // m_corners[1] = transform * math::vector3{ 0.5f, 0.0f, -0.5f}; + // m_corners[2] = transform * math::vector3{ 0.5f, 0.0f, 0.5f}; + // m_corners[3] = transform * math::vector3{-0.5f, 0.0f, 0.5f}; + m_corners[0] = transform * math::vector3{-0.5f, -0.5f, 0.0f}; + m_corners[1] = transform * math::vector3{-0.5f, 0.5f, 0.0f}; + m_corners[2] = transform * math::vector3{ 0.5f, 0.5f, 0.0f}; + m_corners[3] = transform * math::vector3{ 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); + 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); + 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); + m_colored_luminous_flux = m_color * m_luminous_flux; +} + +} // namespace scene diff --git a/src/engine/scene/rectangle-light.hpp b/src/engine/scene/rectangle-light.hpp new file mode 100644 index 0000000..5dcf292 --- /dev/null +++ b/src/engine/scene/rectangle-light.hpp @@ -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 . + */ + +#ifndef ANTKEEPER_SCENE_RECTANGLE_LIGHT_HPP +#define ANTKEEPER_SCENE_RECTANGLE_LIGHT_HPP + +#include +#include + +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& 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& 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& 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& get_colored_luminance() const noexcept + { + return m_colored_luminance; + } + + /// Returns the positions of the light corners. + [[nodiscard]] inline std::span, 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 m_corners[4]; + math::vector3 m_color{1.0f, 1.0f, 1.0f}; + float m_luminous_flux{}; + math::vector3 m_colored_luminous_flux{}; + float m_luminance{}; + math::vector3 m_colored_luminance; +}; + +} // namespace scene + +#endif // ANTKEEPER_SCENE_RECTANGLE_LIGHT_HPP diff --git a/src/engine/scene/sphere-light.hpp b/src/engine/scene/sphere-light.hpp deleted file mode 100644 index 1f8ac17..0000000 --- a/src/engine/scene/sphere-light.hpp +++ /dev/null @@ -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 . - */ - -#ifndef ANTKEEPER_SCENE_SPHERE_LIGHT_HPP -#define ANTKEEPER_SCENE_SPHERE_LIGHT_HPP - -#include -#include - -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& 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& 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& 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 get_spectral_luminance() const noexcept; - -private: - inline void update_spectral_luminous_power() noexcept - { - m_spectral_luminous_power = m_color * m_luminous_power; - } - - math::vector m_color{1.0f, 1.0f, 1.0f}; - float m_luminous_power{}; - math::vector m_spectral_luminous_power{}; - float m_radius{}; -}; - -} // namespace scene - -#endif // ANTKEEPER_SCENE_SPHERE_LIGHT_HPP diff --git a/src/engine/scene/spot-light.hpp b/src/engine/scene/spot-light.hpp index 74ba663..c787d65 100644 --- a/src/engine/scene/spot-light.hpp +++ b/src/engine/scene/spot-light.hpp @@ -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& luminous_power) noexcept + inline void set_luminous_flux(const math::vector& 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& get_luminous_power() const noexcept + /// Returns the luminous flux of the spot light, in *lm*. + [[nodiscard]] inline const math::vector& get_luminous_flux() const noexcept { - return m_luminous_power; + return m_luminous_flux; } /** @@ -82,7 +82,7 @@ public: private: void transformed() override; - math::vector m_luminous_power{0.0f, 0.0f, 0.0f}; + math::vector m_luminous_flux{0.0f, 0.0f, 0.0f}; math::vector m_direction{0.0f, 0.0f, -1.0f}; math::vector m_cutoff{math::pi, math::pi}; math::vector m_cosine_cutoff{-1.0f, -1.0f}; diff --git a/src/game/components/blackbody-component.hpp b/src/game/components/blackbody-component.hpp index 2d07325..e4a83b0 100644 --- a/src/game/components/blackbody-component.hpp +++ b/src/game/components/blackbody-component.hpp @@ -20,16 +20,19 @@ #ifndef ANTKEEPER_GAME_BLACKBODY_COMPONENT_HPP #define ANTKEEPER_GAME_BLACKBODY_COMPONENT_HPP +#include /// 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 color{}; }; - #endif // ANTKEEPER_GAME_BLACKBODY_COMPONENT_HPP diff --git a/src/game/game.cpp b/src/game/game.cpp index 77d9416..52f32f9 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -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(viewport_size[0]) / static_cast(viewport_size[1]); - // Allocate surface scene + // Allocate and init surface scene surface_scene = std::make_unique(); + surface_scene->set_scale(scene_scale); // Allocate and init surface camera surface_camera = std::make_shared(); @@ -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(); + underground_scene->set_scale(scene_scale); // Allocate and init underground camera underground_camera = std::make_shared(); diff --git a/src/game/game.hpp b/src/game/game.hpp index 6874b8e..b27add4 100644 --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -49,7 +49,7 @@ #include #include #include -#include +#include #include #include #include @@ -333,12 +333,11 @@ public: std::unique_ptr sun_light; std::unique_ptr moon_light; std::unique_ptr sky_light; - std::unique_ptr bounce_light; std::unique_ptr underground_scene; std::shared_ptr underground_camera; std::unique_ptr underground_directional_light; std::unique_ptr underground_ambient_light; - std::unique_ptr underground_sphere_light; + std::unique_ptr underground_rectangle_light; scene::collection* active_scene; // Animation diff --git a/src/game/states/nest-selection-state.cpp b/src/game/states/nest-selection-state.cpp index 1ae5ea0..90638b7 100644 --- a/src/game/states/nest-selection-state.cpp +++ b/src/game/states/nest-selection-state.cpp @@ -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; diff --git a/src/game/states/nest-view-state.cpp b/src/game/states/nest-view-state.cpp index 7804c93..61493ca 100644 --- a/src/game/states/nest-view-state.cpp +++ b/src/game/states/nest-view-state.cpp @@ -71,13 +71,16 @@ #include #include #include +#include #include #include #include #include -#include +#include +#include #include #include +#include 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(); - 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{1, -1, 0})); + // ctx.underground_directional_light = std::make_unique(); + // 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{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(); - 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(); - 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 light_color = color::aces::ap1.from_xyz * color::cat::matrix(color::illuminant::deg2::d50, color::aces::white_point) * color::cct::to_xyz(color_temperature); + const math::vector3 light_color{1.0f, 1.0f, 1.0f}; + + // Create rectangle light + ctx.underground_rectangle_light = std::make_unique(); + 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::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("light-rectangle.mdl"); + auto light_rectangle_material = std::make_shared(*light_rectangle_model->get_groups().front().material); + light_rectangle_emissive = std::static_pointer_cast(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(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(light_rectangle_eid, std::move(light_rectangle_static_mesh), std::uint8_t{2}); + ctx.entity_registry->patch + ( + 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("light-sphere.mdl"); - auto light_sphere_material = std::make_shared(*light_sphere_model->get_groups().front().material); - - static_cast(*light_sphere_material->get_variable("emissive")).set(ctx.underground_sphere_light->get_spectral_luminance()); - auto light_sphere_static_mesh = std::make_shared(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(light_sphere_eid, std::move(light_sphere_static_mesh), std::uint8_t{2}); - ctx.entity_registry->patch - ( - light_sphere_eid, - [&](auto& component) - { - component.object->set_translation(ctx.underground_sphere_light->get_translation()); - component.object->set_scale(math::vector{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; diff --git a/src/game/states/nest-view-state.hpp b/src/game/states/nest-view-state.hpp index d13bf97..3d34e49 100644 --- a/src/game/states/nest-view-state.hpp +++ b/src/game/states/nest-view-state.hpp @@ -103,6 +103,8 @@ private: }; std::vector> camera_presets{10}; + + std::shared_ptr light_rectangle_emissive; }; #endif // ANTKEEPER_NEST_VIEW_STATE_HPP diff --git a/src/game/systems/astronomy-system.cpp b/src/game/systems/astronomy-system.cpp index 90ff52d..221dc03 100644 --- a/src/game/systems/astronomy-system.cpp +++ b/src/game/systems/astronomy-system.cpp @@ -37,7 +37,7 @@ #include #include #include - +#include 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().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(math::max(observer_blackbody_transmitted_illuminance))); + sun_light->set_color(math::vector3(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(math::max(sky_light_illuminance))); + sky_light->set_color(math::vector3(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(observer_blackbody_angular_radius)); } // Update diffuse reflectors this->registry.view().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(math::max(observer_reflector_illuminance))); + this->moon_light->set_color(math::vector3(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; diff --git a/src/game/systems/astronomy-system.hpp b/src/game/systems/astronomy-system.hpp index 3c19cd6..bcba74b 100644 --- a/src/game/systems/astronomy-system.hpp +++ b/src/game/systems/astronomy-system.hpp @@ -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; }; diff --git a/src/game/systems/blackbody-system.cpp b/src/game/systems/blackbody-system.cpp index be10605..67c4383 100644 --- a/src/game/systems/blackbody-system.cpp +++ b/src/game/systems/blackbody-system.cpp @@ -24,27 +24,24 @@ #include #include - blackbody_system::blackbody_system(entity::registry& registry): - updatable_system(registry), - illuminant(color::illuminant::deg2::d50) + 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); 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& illuminant) { - this->illuminant = illuminant; + m_illuminant = illuminant; + m_xyz_to_rgb = color::aces::ap1.from_xyz * color::cat::matrix(m_illuminant, color::aces::white_point); } -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(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); + // Get blackbody component + auto& blackbody = registry.get(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 { // 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(temperature, wavelength_m); + // Calculate the spectral radiance of the wavelength + const double spectral_radiance = physics::light::blackbody::spectral_radiance(blackbody.temperature, wavelength_m); + // Convert spectral radiance to spectral luminance + const double spectral_luminance = spectral_radiance * 1e-9 * physics::light::max_luminous_efficacy; - // Calculate the ACEScg color of the wavelength using CIE color matching functions - double3 spectral_color = color::aces::ap1.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 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; + // 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 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); } - diff --git a/src/game/systems/blackbody-system.hpp b/src/game/systems/blackbody-system.hpp index 59578c7..391a242 100644 --- a/src/game/systems/blackbody-system.hpp +++ b/src/game/systems/blackbody-system.hpp @@ -22,14 +22,13 @@ #include "game/systems/updatable-system.hpp" #include -#include +#include +#include #include "game/components/blackbody-component.hpp" -#include "game/components/celestial-body-component.hpp" #include - /** - * 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& 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 illuminant; - std::vector visible_wavelengths_nm; + std::vector m_visible_wavelengths_nm; + math::vector2 m_illuminant; + math::matrix3x3 m_xyz_to_rgb; }; diff --git a/src/game/world.cpp b/src/game/world.cpp index 5c6ad87..11913b9 100644 --- a/src/game/world.cpp +++ b/src/game/world.cpp @@ -361,7 +361,6 @@ void create_sun(::game& ctx) // Create sun directional light scene object ctx.sun_light = std::make_unique(); - 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(); - ctx.sky_light->set_illuminance({0, 0, 0}); - - // Create bounce directional light scene object - ctx.bounce_light = std::make_unique(); - 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(); - 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);