From 3172042ac5f29ab1185ddbf1cd653d160f7997a8 Mon Sep 17 00:00:00 2001 From: "C. J. Howard" Date: Thu, 24 Sep 2020 21:09:57 -0700 Subject: [PATCH] Load sky gradient from sky palette texture, make sun position more physically accurate, revise linear<->srgb functions --- src/game/biome.hpp | 3 ++ src/game/states/play-state.cpp | 9 +---- src/game/systems/weather-system.cpp | 61 +++++++++++++++++++++++++++-- src/game/systems/weather-system.hpp | 7 ++++ src/renderer/passes/sky-pass.cpp | 32 +++++---------- src/renderer/passes/sky-pass.hpp | 13 +++--- src/resources/biome-loader.cpp | 12 ++++++ src/utility/gamma.hpp | 34 +++++----------- 8 files changed, 107 insertions(+), 64 deletions(-) diff --git a/src/game/biome.hpp b/src/game/biome.hpp index d3d0f52..d280bb4 100644 --- a/src/game/biome.hpp +++ b/src/game/biome.hpp @@ -23,6 +23,7 @@ #include #include "utility/fundamental-types.hpp" class material; +class image; struct biome { @@ -43,6 +44,8 @@ struct biome float3 zenith_color; float wind_speed; float wind_direction; + image* sky_palette; + image* shadow_palette; // Traits }; diff --git a/src/game/states/play-state.cpp b/src/game/states/play-state.cpp index 80ecf40..0226c0b 100644 --- a/src/game/states/play-state.cpp +++ b/src/game/states/play-state.cpp @@ -90,14 +90,9 @@ void play_state_enter(game_context* ctx) sky_pass->set_enabled(true); sky_pass->set_sun_angular_radius(ctx->biome->sun_angular_radius); sky_pass->set_sun_color(ctx->biome->sun_color * ctx->biome->sun_intensity); - sky_pass->set_horizon_color(ctx->biome->horizon_color); - sky_pass->set_zenith_color(ctx->biome->zenith_color); - - texture_2d* sky_palette = ctx->resource_manager->load("sky-palette.png"); - sky_palette->set_wrapping(texture_wrapping::clamp, texture_wrapping::clamp); - sky_palette->set_filters(texture_min_filter::nearest, texture_mag_filter::nearest); - sky_pass->set_sky_palette(sky_palette); + ctx->weather_system->set_sky_palette(ctx->biome->sky_palette); + ctx->weather_system->set_shadow_palette(ctx->biome->shadow_palette); ctx->weather_system->set_time_of_day(6.0f * 60.0f * 60.0f); resource_manager* resource_manager = ctx->resource_manager; diff --git a/src/game/systems/weather-system.cpp b/src/game/systems/weather-system.cpp index 2b9c1b7..1833d6d 100644 --- a/src/game/systems/weather-system.cpp +++ b/src/game/systems/weather-system.cpp @@ -22,7 +22,12 @@ #include "renderer/passes/sky-pass.hpp" #include "renderer/passes/shadow-map-pass.hpp" #include "renderer/passes/material-pass.hpp" +#include "utility/gamma.hpp" +#include "resources/image.hpp" #include +#include + +static constexpr float seconds_per_day = 24.0f * 60.0f * 60.0f; weather_system::weather_system(entt::registry& registry): entity_system(registry), @@ -35,6 +40,8 @@ weather_system::weather_system(entt::registry& registry): material_pass(nullptr), time_of_day(0.0f), time_scale(1.0f), + sky_palette(nullptr), + shadow_palette(nullptr), sun_direction{0.0f, -1.0f, 0.0f} {} @@ -95,11 +102,24 @@ void weather_system::set_material_pass(::material_pass* pass) void weather_system::set_time_of_day(float t) { - static constexpr float seconds_per_day = 24.0f * 60.0f * 60.0f; time_of_day = std::fmod(t, seconds_per_day); - sun_azimuth = 0.0f; - sun_elevation = (time_of_day / seconds_per_day) * math::two_pi - math::half_pi; + //sun_azimuth = 0.0f; + //sun_elevation = (time_of_day / seconds_per_day) * math::two_pi - math::half_pi; + + float hour_angle = math::wrap_radians(time_of_day * (math::two_pi / seconds_per_day) - math::pi); + float declination = math::radians(0.0f); + float latitude = math::radians(0.0f); + + + sun_elevation = std::asin(std::sin(declination) * std::sin(latitude) + std::cos(declination) * std::cos(hour_angle) * std::cos(latitude)); + sun_azimuth = std::acos((std::sin(declination) * std::cos(latitude) - std::cos(declination) * std::cos(hour_angle) * std::sin(latitude)) / std::cos(sun_elevation)); + if (hour_angle < 0.0f) + sun_azimuth = math::two_pi - sun_azimuth; + + //std::cout << "hour angle: " << math::degrees(hour_angle) << std::endl; + //std::cout << "azimuth: " << math::degrees(sun_azimuth) << std::endl; + //std::cout << "time: " << (time_of_day / 60.0f / 60.0f) << std::endl; math::quaternion sun_azimuth_rotation = math::angle_axis(sun_azimuth, float3{0, 1, 0}); math::quaternion sun_elevation_rotation = math::angle_axis(sun_elevation, float3{-1, 0, 0}); @@ -111,6 +131,11 @@ void weather_system::set_time_of_day(float t) sun_light->set_rotation(sun_rotation); } + if (sky_pass) + { + sky_pass->set_sky_gradient(sky_gradient); + } + shadow_light = sun_light; if (shadow_map_pass) { @@ -122,3 +147,33 @@ void weather_system::set_time_scale(float scale) { time_scale = scale; } + +void weather_system::set_sky_palette(const ::image* image) +{ + sky_palette = image; + if (sky_palette) + { + unsigned int w = image->get_width(); + unsigned int h = image->get_height(); + unsigned int c = image->get_channels(); + const unsigned char* pixels = static_cast(image->get_pixels()); + + for (unsigned int x = 0; x < w; ++x) + { + for (unsigned int y = 0; y < std::min(4, h); ++y) + { + unsigned int i = y * w * c + x * c; + float r = srgb_to_linear(static_cast(pixels[i]) / 255.0f); + float g = srgb_to_linear(static_cast(pixels[i + 1]) / 255.0f); + float b = srgb_to_linear(static_cast(pixels[i + 2]) / 255.0f); + + sky_gradient[y] = {r, g, b, static_cast(y) * (1.0f / 3.0f)}; + } + } + } +} + +void weather_system::set_shadow_palette(const ::image* image) +{ + shadow_palette = image; +} diff --git a/src/game/systems/weather-system.hpp b/src/game/systems/weather-system.hpp index 4924eda..d49d4fc 100644 --- a/src/game/systems/weather-system.hpp +++ b/src/game/systems/weather-system.hpp @@ -28,6 +28,7 @@ class shadow_map_pass; class material_pass; class ambient_light; class directional_light; +class image; class weather_system: public entity_system @@ -46,6 +47,9 @@ public: void set_time_of_day(float t); void set_time_scale(float scale); + void set_sky_palette(const ::image* image); + void set_shadow_palette(const ::image* image); + private: float time_of_day; float time_scale; @@ -59,6 +63,9 @@ private: sky_pass* sky_pass; shadow_map_pass* shadow_map_pass; material_pass* material_pass; + const image* sky_palette; + const image* shadow_palette; + std::array sky_gradient; }; #endif // ANTKEEPER_WEATHER_SYSTEM_HPP diff --git a/src/renderer/passes/sky-pass.cpp b/src/renderer/passes/sky-pass.cpp index db69438..860057e 100644 --- a/src/renderer/passes/sky-pass.cpp +++ b/src/renderer/passes/sky-pass.cpp @@ -43,7 +43,6 @@ sky_pass::sky_pass(::rasterizer* rasterizer, const ::framebuffer* framebuffer, resource_manager* resource_manager): render_pass(rasterizer, framebuffer), - sky_palette(nullptr), mouse_position({0.0f, 0.0f}), sun_light(nullptr) { @@ -51,11 +50,9 @@ sky_pass::sky_pass(::rasterizer* rasterizer, const ::framebuffer* framebuffer, r matrix_input = shader_program->get_input("matrix"); sun_direction_input = shader_program->get_input("sun_direction"); sun_angular_radius_input = shader_program->get_input("sun_angular_radius"); - horizon_color_input = shader_program->get_input("horizon_color"); - zenith_color_input = shader_program->get_input("zenith_color"); sun_angular_radius_input = shader_program->get_input("sun_angular_radius"); sun_color_input = shader_program->get_input("sun_color"); - sky_palette_input = shader_program->get_input("sky_palette"); + sky_gradient_input = shader_program->get_input("sky_gradient"); mouse_input = shader_program->get_input("mouse"); resolution_input = shader_program->get_input("resolution"); time_input = shader_program->get_input("time"); @@ -77,6 +74,11 @@ sky_pass::sky_pass(::rasterizer* rasterizer, const ::framebuffer* framebuffer, r quad_vbo = new vertex_buffer(sizeof(float) * vertex_size * vertex_count, vertex_data); quad_vao = new vertex_array(); quad_vao->bind_attribute(VERTEX_POSITION_LOCATION, *quad_vbo, 3, vertex_attribute_type::float_32, vertex_stride, 0); + + sky_gradient[0] = {1.0, 0.0f, 0.0f, 0.0f}; + sky_gradient[1] = {0.0, 1.0f, 0.0f, 0.333f}; + sky_gradient[2] = {0.0, 0.0f, 1.0f, 0.667f}; + sky_gradient[3] = {1.0, 1.0f, 0.0f, 1.0f}; } sky_pass::~sky_pass() @@ -123,12 +125,8 @@ void sky_pass::render(render_context* context) const sun_angular_radius_input->upload(sun_angular_radius); if (sun_color_input) sun_color_input->upload(sun_color); - if (horizon_color_input) - horizon_color_input->upload(horizon_color); - if (zenith_color_input) - zenith_color_input->upload(zenith_color); - if (sky_palette_input && sky_palette) - sky_palette_input->upload(sky_palette); + if (sky_gradient_input) + sky_gradient_input->upload(0, &sky_gradient[0], 4); if (mouse_input) mouse_input->upload(mouse_position); if (resolution_input) @@ -150,24 +148,14 @@ void sky_pass::set_sun_color(const float3& color) sun_color = color; } -void sky_pass::set_horizon_color(const float3& color) -{ - horizon_color = color; -} - -void sky_pass::set_zenith_color(const float3& color) -{ - zenith_color = color; -} - void sky_pass::set_sun_light(const directional_light* light) { sun_light = light; } -void sky_pass::set_sky_palette(const texture_2d* texture) +void sky_pass::set_sky_gradient(const std::array& gradient) { - sky_palette = texture; + sky_gradient = gradient; } void sky_pass::set_time_tween(const tween* time) diff --git a/src/renderer/passes/sky-pass.hpp b/src/renderer/passes/sky-pass.hpp index e610b93..6586dd4 100644 --- a/src/renderer/passes/sky-pass.hpp +++ b/src/renderer/passes/sky-pass.hpp @@ -47,10 +47,10 @@ public: void set_sun_angular_radius(float angle); void set_sun_color(const float3& color); - void set_horizon_color(const float3& color); - void set_zenith_color(const float3& color); void set_sun_light(const directional_light* direction); - void set_sky_palette(const texture_2d* texture); + void set_sky_gradient(const std::array& gradient); + + void set_time_tween(const tween* time); private: @@ -61,9 +61,7 @@ private: const shader_input* sun_direction_input; const shader_input* sun_angular_radius_input; const shader_input* sun_color_input; - const shader_input* horizon_color_input; - const shader_input* zenith_color_input; - const shader_input* sky_palette_input; + const shader_input* sky_gradient_input; const shader_input* mouse_input; const shader_input* resolution_input; const shader_input* time_input; @@ -73,11 +71,10 @@ private: float sun_angular_radius; float3 sun_color; - float3 horizon_color; - float3 zenith_color; const directional_light* sun_light; const texture_2d* sky_palette; float2 mouse_position; + std::array sky_gradient; const tween* time_tween; }; diff --git a/src/resources/biome-loader.cpp b/src/resources/biome-loader.cpp index 58168c7..f869898 100644 --- a/src/resources/biome-loader.cpp +++ b/src/resources/biome-loader.cpp @@ -100,6 +100,18 @@ biome* resource_loader::load(resource_manager* resource_manager, PHYSFS_F load_value(&biome->wind_speed, weather.value(), "wind_speed"); load_value(&biome->wind_direction, weather.value(), "wind_direction"); biome->wind_direction = math::radians(biome->wind_direction); + + std::string sky_palette_filename; + if (load_value(&sky_palette_filename, weather.value(), "sky_palette")) + { + biome->sky_palette = resource_manager->load(sky_palette_filename); + } + + std::string shadow_palette_filename; + if (load_value(&shadow_palette_filename, weather.value(), "shadow_palette")) + { + biome->shadow_palette = resource_manager->load(shadow_palette_filename); + } } return biome; diff --git a/src/utility/gamma.hpp b/src/utility/gamma.hpp index 429fe0b..ad51bb2 100644 --- a/src/utility/gamma.hpp +++ b/src/utility/gamma.hpp @@ -23,40 +23,26 @@ #include "math/vector-type.hpp" #include -template -math::vector to_linear(math::vector v) +template +T srgb_to_linear(const T& x) { - for (std::size_t i = 0; i < N; ++i) + if (x <= T(0.04045)) { - if (v[i] <= T(0.04045)) - { - v[i] /= T(12.92); - } - else - { - v[i] = std::pow((v[i] + T(0.055)) / T(1.055), T(2.4)); - } + return x / T(12.92); } - return v; + return std::pow((x + T(0.055)) / T(1.055), T(2.4)); } -template -math::vector to_srgb(math::vector v) +template +T linear_to_srgb(const T& x) { - for (std::size_t i = 0; i < N; ++i) + if (x <= T(0.0031308)) { - if (v[i] <= T(0.0031308)) - { - v[i] *= T(12.92); - } - else - { - v[i] = std::pow(v[i], T(1.0 / 2.4)) * T(1.055) - T(0.055); - } + return x * T(12.92); } - return v; + return std::pow(x, T(1.0 / 2.4)) * T(1.055) - T(0.055); } #endif // ANTKEEPER_GAMMA_HPP