From f26552c3ad3e87684bf01359799d724ba87f42f3 Mon Sep 17 00:00:00 2001 From: "C. J. Howard" Date: Thu, 27 May 2021 06:14:54 +0800 Subject: [PATCH] Improve sky pass, improve parameterization of atmospheric scattering, add more atmospheric scattering-related functions to the physics::atmosphere namespace --- src/ecs/components/atmosphere-component.hpp | 20 +- src/ecs/systems/astronomy-system.cpp | 116 +++++------- src/game/bootloader.cpp | 1 - src/game/states/play-state.cpp | 35 ++-- src/physics/atmosphere.hpp | 115 ++++++++++++ src/physics/light/phase.hpp | 19 ++ src/renderer/passes/sky-pass.cpp | 198 +++++++------------- src/renderer/passes/sky-pass.hpp | 60 +++--- 8 files changed, 307 insertions(+), 257 deletions(-) diff --git a/src/ecs/components/atmosphere-component.hpp b/src/ecs/components/atmosphere-component.hpp index af64a30..f839176 100644 --- a/src/ecs/components/atmosphere-component.hpp +++ b/src/ecs/components/atmosphere-component.hpp @@ -30,17 +30,29 @@ struct atmosphere_component /// Altitude of the outer atmosphere, in meters. double exosphere_altitude; + /// Atmospheric index of refraction at sea level. + double index_of_refraction; + + /// Molecular density of Rayleigh particles at sea level. + double rayleigh_density; + + /// Molecular density of Mie particles at sea level. + double mie_density; + /// Rayleigh scale height, in meters. double rayleigh_scale_height; /// Mie scale height, in meters. double mie_scale_height; - /// (Dependent) Rayleigh scattering coefficients - double3 rayleigh_scattering_coefficients; + /// Mie phase function asymmetry factor. + double mie_asymmetry; + + /// (Dependent) Rayleigh scattering coefficients at sea level. + double3 rayleigh_scattering; - /// (Dependent) Mie scattering coefficients - double3 mie_scattering_coefficients; + /// (Dependent) Mie scattering coefficients at sea level. + double3 mie_scattering; }; } // namespace ecs diff --git a/src/ecs/systems/astronomy-system.cpp b/src/ecs/systems/astronomy-system.cpp index 297dba8..0b6ba8a 100644 --- a/src/ecs/systems/astronomy-system.cpp +++ b/src/ecs/systems/astronomy-system.cpp @@ -30,45 +30,12 @@ #include "physics/light/blackbody.hpp" #include "physics/light/photometry.hpp" #include "physics/light/luminosity.hpp" +#include "physics/atmosphere.hpp" #include "geom/cartesian.hpp" #include namespace ecs { -/** - * Approximates the density of exponentially-distributed atmospheric particles between two points using the trapezoidal rule. - * - * @param a Start point. - * @param b End point. - * @param r Radius of the planet. - * @param sh Scale height of the atmospheric particles. - * @param n Number of samples. - */ -template -T optical_depth(const math::vector3& a, const math::vector3& b, T r, T sh, std::size_t n) -{ - T inverse_sh = T(-1) / sh; - - T h = math::length(b - a) / T(n); - - math::vector3 dy = (b - a) / T(n); - math::vector3 y = a + dy; - - T f_x = std::exp((length(a) - r) * inverse_sh); - T f_y = std::exp((length(y) - r) * inverse_sh); - T sum = (f_x + f_y); - - for (std::size_t i = 1; i < n; ++i) - { - f_x = f_y; - y += dy; - f_y = std::exp((length(y) - r) * inverse_sh); - sum += (f_x + f_y); - } - - return sum / T(2) * h; -} - template math::vector3 transmittance(T depth_r, T depth_m, T depth_o, const math::vector3& beta_r, const math::vector3& beta_m) { @@ -84,16 +51,6 @@ math::vector3 transmittance(T depth_r, T depth_m, T depth_o, const math::vect return t; } -double calc_beta_r(double wavelength, double ior, double density) -{ - double wavelength2 = wavelength * wavelength; - double ior2m1 = ior * ior - 1.0; - double num = 8.0 * (math::pi * math::pi * math::pi) * ior2m1 * ior2m1; - double den = 3.0 * density * (wavelength2 * wavelength2); - return num / den; -} - - astronomy_system::astronomy_system(ecs::registry& registry): entity_system(registry), universal_time(0.0), @@ -153,10 +110,12 @@ void astronomy_system::update(double t, double dt) transform.local.translation = math::type_cast(r_topocentric); }); + const double earth_radius = 6.3781e6; + // Update blackbody lighting registry.view().each( [&](ecs::entity entity, auto& blackbody, auto& orbit) - { + { // Calculate blackbody inertial basis double3 blackbody_forward_inertial = math::normalize(reference_orbit.state.r - orbit.state.r); double3 blackbody_up_inertial = {0, 0, 1}; @@ -167,8 +126,7 @@ void astronomy_system::update(double t, double dt) double3 blackbody_up_topocentric = inertial_to_topocentric.rotation * blackbody_up_inertial; // Calculate distance from observer to blackbody - const double meters_per_au = 1.496e+11; - double blackbody_distance = math::length(blackbody_position_topocentric) * meters_per_au; + double blackbody_distance = math::length(blackbody_position_topocentric); // Calculate blackbody illuminance according to distance double blackbody_illuminance = blackbody.luminous_intensity / (blackbody_distance * blackbody_distance); @@ -181,17 +139,14 @@ void astronomy_system::update(double t, double dt) { const ecs::atmosphere_component& atmosphere = this->registry.get(reference_body); - const double earth_radius_au = 4.26352e-5; - const double earth_radius_m = earth_radius_au * meters_per_au; - // Altitude of observer in meters geom::ray sample_ray; - sample_ray.origin = {0, observer_location[0] * meters_per_au, 0}; + sample_ray.origin = {0, observer_location[0], 0}; sample_ray.direction = math::normalize(blackbody_position_topocentric); geom::sphere exosphere; exosphere.center = {0, 0, 0}; - exosphere.radius = earth_radius_m + atmosphere.exosphere_altitude; + exosphere.radius = earth_radius + atmosphere.exosphere_altitude; auto intersection_result = geom::ray_sphere_intersection(sample_ray, exosphere); @@ -200,11 +155,11 @@ void astronomy_system::update(double t, double dt) double3 sample_start = sample_ray.origin; double3 sample_end = sample_ray.extrapolate(std::get<2>(intersection_result)); - double optical_depth_r = optical_depth(sample_start, sample_end, earth_radius_m, atmosphere.rayleigh_scale_height, 32); - double optical_depth_k = optical_depth(sample_start, sample_end, earth_radius_m, atmosphere.mie_scale_height, 32); + double optical_depth_r = physics::atmosphere::optical_depth(sample_start, sample_end, earth_radius, atmosphere.rayleigh_scale_height, 32); + double optical_depth_k = physics::atmosphere::optical_depth(sample_start, sample_end, earth_radius, atmosphere.mie_scale_height, 32); double optical_depth_o = 0.0; - double3 attenuation = transmittance(optical_depth_r, optical_depth_k, optical_depth_o, atmosphere.rayleigh_scattering_coefficients, atmosphere.mie_scattering_coefficients); + double3 attenuation = transmittance(optical_depth_r, optical_depth_k, optical_depth_o, atmosphere.rayleigh_scattering, atmosphere.mie_scattering); // Attenuate blackbody color blackbody_color *= attenuation; @@ -214,7 +169,7 @@ void astronomy_system::update(double t, double dt) if (sun_light != nullptr) { // Update blackbody light transform - sun_light->set_translation(math::type_cast(blackbody_position_topocentric)); + sun_light->set_translation(math::normalize(math::type_cast(blackbody_position_topocentric))); sun_light->set_rotation ( math::look_rotation @@ -228,11 +183,14 @@ void astronomy_system::update(double t, double dt) sun_light->set_color(math::type_cast(blackbody_color)); sun_light->set_intensity(static_cast(blackbody_illuminance)); - // Pass blackbody params to sky pas + // Upload blackbody params to sky pass if (this->sky_pass) { - this->sky_pass->set_sun_object(sun_light); + this->sky_pass->set_sun_position(math::type_cast(blackbody_position_topocentric)); this->sky_pass->set_sun_color(math::type_cast(blackbody.color * blackbody_illuminance)); + + float angular_radius = 2.0 * std::atan2(2.0 * blackbody.radius, 2.0 * blackbody_distance); + this->sky_pass->set_sun_angular_radius(angular_radius); } } }); @@ -240,6 +198,7 @@ void astronomy_system::update(double t, double dt) // Update sky pass topocentric frame if (sky_pass != nullptr) { + // Upload topocentric frame to sky pass sky_pass->set_topocentric_frame ( physics::frame @@ -248,6 +207,21 @@ void astronomy_system::update(double t, double dt) math::type_cast(inertial_to_topocentric.rotation) } ); + + // Upload observer altitude to sky pass + float observer_altitude = observer_location[0] - earth_radius; + sky_pass->set_observer_altitude(observer_altitude); + + // Upload atmosphere params to sky pass + if (this->registry.has(reference_body)) + { + const ecs::atmosphere_component& atmosphere = this->registry.get(reference_body); + + sky_pass->set_scale_heights(atmosphere.rayleigh_scale_height, atmosphere.mie_scale_height); + sky_pass->set_scattering_coefficients(math::type_cast(atmosphere.rayleigh_scattering), math::type_cast(atmosphere.mie_scattering)); + sky_pass->set_mie_asymmetry(atmosphere.mie_asymmetry); + sky_pass->set_atmosphere_radii(earth_radius, earth_radius + atmosphere.exosphere_altitude); + } } } @@ -361,23 +335,29 @@ void astronomy_system::on_atmosphere_construct(ecs::registry& registry, ecs::ent void astronomy_system::on_atmosphere_replace(ecs::registry& registry, ecs::entity entity, ecs::atmosphere_component& atmosphere) { + // Calculate polarization factors + const double rayleigh_polarization = physics::atmosphere::polarization(atmosphere.index_of_refraction, atmosphere.rayleigh_density); + const double mie_polarization = physics::atmosphere::polarization(atmosphere.index_of_refraction, atmosphere.mie_density); + // ACEScg wavelengths determined by matching wavelengths to XYZ, transforming XYZ to ACEScg, then selecting the max wavelengths for R, G, and B. - const double3 acescg_wavelengths_nm = {600.0, 540.0, 450.0}; - const double3 acescg_wavelengths_m = acescg_wavelengths_nm * 1.0e-9; + const double3 acescg_wavelengths = {600.0e-9, 540.0e-9, 450.0e-9}; // Calculate Rayleigh scattering coefficients - const double air_ior = 1.0003; - const double molecular_density = 2.545e25; - double3 beta_r; - atmosphere.rayleigh_scattering_coefficients = + atmosphere.rayleigh_scattering = { - calc_beta_r(acescg_wavelengths_m.x, air_ior, molecular_density), - calc_beta_r(acescg_wavelengths_m.y, air_ior, molecular_density), - calc_beta_r(acescg_wavelengths_m.z, air_ior, molecular_density) + physics::atmosphere::scatter_rayleigh(acescg_wavelengths.x, atmosphere.rayleigh_density, rayleigh_polarization), + physics::atmosphere::scatter_rayleigh(acescg_wavelengths.y, atmosphere.rayleigh_density, rayleigh_polarization), + physics::atmosphere::scatter_rayleigh(acescg_wavelengths.z, atmosphere.rayleigh_density, rayleigh_polarization) }; // Calculate Mie scattering coefficients - atmosphere.mie_scattering_coefficients = {2.0e-6, 2.0e-6, 2.0e-6}; + const double mie_scattering = physics::atmosphere::scatter_mie(atmosphere.mie_density, mie_polarization); + atmosphere.mie_scattering = + { + mie_scattering, + mie_scattering, + mie_scattering + }; } } // namespace ecs diff --git a/src/game/bootloader.cpp b/src/game/bootloader.cpp index 209cdf6..aafc153 100644 --- a/src/game/bootloader.cpp +++ b/src/game/bootloader.cpp @@ -503,7 +503,6 @@ void setup_rendering(game_context* ctx) ctx->overworld_sky_pass = new sky_pass(ctx->rasterizer, ctx->framebuffer_hdr, ctx->resource_manager); ctx->app->get_event_dispatcher()->subscribe(ctx->overworld_sky_pass); ctx->overworld_sky_pass->set_enabled(false); - ctx->overworld_sky_pass->set_blue_noise_map(blue_noise_map); ctx->overworld_material_pass = new material_pass(ctx->rasterizer, ctx->framebuffer_hdr, ctx->resource_manager); ctx->overworld_material_pass->set_fallback_material(ctx->fallback_material); ctx->overworld_material_pass->shadow_map_pass = ctx->overworld_shadow_map_pass; diff --git a/src/game/states/play-state.cpp b/src/game/states/play-state.cpp index 6627871..387bc2a 100644 --- a/src/game/states/play-state.cpp +++ b/src/game/states/play-state.cpp @@ -93,15 +93,6 @@ void play_state_enter(game_context* ctx) sky_pass->set_sky_model(ctx->resource_manager->load("sky-dome.mdl")); sky_pass->set_moon_model(ctx->resource_manager->load("moon.mdl")); - sky_pass->set_horizon_color({1.1f, 1.1f, 1.1f}); - sky_pass->set_zenith_color({0.0f, 0.0f, 0.0f}); - sky_pass->set_time_of_day(0.0f); - sky_pass->set_julian_day(0.0f); - sky_pass->set_observer_location(4.26352e-5, ctx->biome->location[0], ctx->biome->location[1]); - sky_pass->set_moon_angular_radius(math::radians(1.0f)); - sky_pass->set_sun_angular_radius(math::radians(1.0f)); - sky_pass->set_sky_gradient(resource_manager->load("sky-gradient.tex"), resource_manager->load("sky-gradient2.tex")); - // Create sun auto sun_entity = ecs_registry.create(); { @@ -130,7 +121,7 @@ void play_state_enter(game_context* ctx) auto earth_entity = ecs_registry.create(); { ecs::orbit_component orbit; - orbit.elements.a = 1.00000261; + orbit.elements.a = 1.496e+11; orbit.elements.e = 0.01671123; orbit.elements.i = math::radians(-0.00001531); orbit.elements.raan = math::radians(0.0); @@ -138,11 +129,16 @@ void play_state_enter(game_context* ctx) orbit.elements.w = longitude_periapsis - orbit.elements.raan; orbit.elements.ta = math::radians(100.46457166) - longitude_periapsis; - const double earth_radius_m = 6378e3; ecs::atmosphere_component atmosphere; - atmosphere.exosphere_altitude = 80e3; + atmosphere.exosphere_altitude = 100e3; + + atmosphere.index_of_refraction = 1.0003; + atmosphere.rayleigh_density = 2.545e25; + atmosphere.mie_density = 14.8875; + atmosphere.rayleigh_scale_height = 8000.0; atmosphere.mie_scale_height = 1200.0; + atmosphere.mie_asymmetry = 0.8; ecs::transform_component transform; transform.local = math::identity_transform; @@ -160,12 +156,12 @@ void play_state_enter(game_context* ctx) ctx->overworld_scene->add_object(ambient); scene::directional_light* sun = new scene::directional_light(); - sun->set_intensity(1000.0f); - sun->set_light_texture(resource_manager->load("forest-gobo.tex")); - sun->set_light_texture_scale({2000, 2000}); - sun->set_light_texture_opacity(0.925f); - sun->look_at({2, 1, 0}, {0, 0, 0}, {0, 0, 1}); - sun->update_tweens(); + //sun->set_intensity(1000.0f); + //sun->set_light_texture(resource_manager->load("forest-gobo.tex")); + //sun->set_light_texture_scale({2000, 2000}); + //sun->set_light_texture_opacity(0.925f); + //sun->look_at({2, 1, 0}, {0, 0, 0}, {0, 0, 1}); + //sun->update_tweens(); ctx->overworld_scene->add_object(sun); ctx->overworld_shadow_map_pass->set_light(sun); @@ -175,10 +171,9 @@ void play_state_enter(game_context* ctx) ctx->orbit_system->set_universal_time(universal_time); // Set astronomy system observation parameters - const double earth_radius_au = 4.2635e-5; ctx->astronomy_system->set_reference_body(earth_entity); ctx->astronomy_system->set_reference_body_axial_tilt(math::radians(23.4393)); - ctx->astronomy_system->set_observer_location(double3{4.26352e-5, math::radians(0.0f), math::radians(0.0f)}); + ctx->astronomy_system->set_observer_location(double3{6.3781e6, math::radians(0.0f), math::radians(0.0f)}); ctx->astronomy_system->set_sun_light(sun); ctx->astronomy_system->set_sky_pass(ctx->overworld_sky_pass); diff --git a/src/physics/atmosphere.hpp b/src/physics/atmosphere.hpp index 37f1b7a..d433622 100644 --- a/src/physics/atmosphere.hpp +++ b/src/physics/atmosphere.hpp @@ -37,12 +37,127 @@ namespace atmosphere { * @return Particle density at altitude. * * @see https://en.wikipedia.org/wiki/Scale_height + * @see https://en.wikipedia.org/wiki/Barometric_formula */ +template T density(T d0, T z, T sh) { return d0 * std::exp(-z / sh); } +/** + * Calculates a particle polarization factor used in computing scattering coefficients. + * + * @param ior Atmospheric index of refraction at sea level. + * @param density Molecular density at sea level. + * @return Polarization factor. + * + * @see Elek, Oskar. (2009). Rendering Parametrizable Planetary Atmospheres with Multiple Scattering in Real-Time. + */ +template +T polarization(T ior, T density) +{ + const T ior2 = ior * ior; + const T num = T(2) * math::pi * math::pi * ((ior2 - T(1.0)) * (ior2 - T(1.0))); + const T den = T(3) * density * density; + return num / den; +} + +/** + * Calculates a Rayleigh scattering coefficient at sea level (wavelength-dependent). + * + * @param wavelength Wavelength of light, in meters. + * @param density Molecular density of Rayleigh particles at sea level. + * @param polarization Rayleigh particle polarization factor. + * + * @see atmosphere::polarization + * + * @see Elek, Oskar. (2009). Rendering Parametrizable Planetary Atmospheres with Multiple Scattering in Real-Time. + */ +template +T scatter_rayleigh(T wavelength, T density, T polarization) +{ + const T wavelength2 = wavelength * wavelength; + return T(4) * math::pi * density / (wavelength2 * wavelength2) * polarization; +} + +/** + * Calculates a Mie scattering coefficient at sea level (wavelength-independent). + * + * @param density Molecular density of Mie particles at sea level. + * @param polarization Mie particle polarization factor. + * + * @see atmosphere::polarization + * + * @see Elek, Oskar. (2009). Rendering Parametrizable Planetary Atmospheres with Multiple Scattering in Real-Time. + */ +template +T scatter_mie(T density, T polarization) +{ + return T(4) * math::pi * density * polarization; +} + +/** + * Calculates an extinction coefficient given a scattering coefficient and an absorbtion coefficient. + * + * @param s Scattering coefficient. + * @param a Absorbtion coefficient. + * @return Extinction coefficient. + */ +template +T extinction(T s, T a) +{ + return s + a; +} + +/** + * Calculates the single-scattering albedo (SSA) given a scattering coefficient and an extinction coefficient. + * + * @param s Scattering coefficient. + * @param e Extinction coefficient. + * @return Single-scattering albedo. + */ +template +T albedo(T s, T e) +{ + return s / t; +} + +/** + * Approximates the optical depth of exponentially-distributed atmospheric particles between two points using the trapezoidal rule. + * + * @param a Start point. + * @param b End point. + * @param r Radius of the planet. + * @param sh Scale height of the atmospheric particles. + * @param n Number of samples. + * @return Optical depth between @p a and @p b. + */ +template +T optical_depth(const math::vector3& a, const math::vector3& b, T r, T sh, std::size_t n) +{ + sh = T(-1) / sh; + + const T h = math::length(b - a) / T(n); + + math::vector3 dy = (b - a) / T(n); + math::vector3 y = a + dy; + + T f_x = std::exp((math::length(a) - r) * sh); + T f_y = std::exp((math::length(y) - r) * sh); + T sum = (f_x + f_y); + + for (std::size_t i = 1; i < n; ++i) + { + f_x = f_y; + y += dy; + f_y = std::exp((math::length(y) - r) * sh); + sum += (f_x + f_y); + } + + return sum / T(2) * h; +} + } // namespace atmosphere } // namespace physics diff --git a/src/physics/light/phase.hpp b/src/physics/light/phase.hpp index 6b1c833..3109147 100644 --- a/src/physics/light/phase.hpp +++ b/src/physics/light/phase.hpp @@ -29,6 +29,15 @@ namespace light { /// Light-scattering phase functions. namespace phase { +/** + * Cornette-Shanks phase function. + * + * @param mu Cosine of the angle between the light and view directions. + * @param g Asymmetry factor, on [-1, 1]. Positive values cause forward scattering, negative values cause back scattering. + */ +template +T cornette_shanks(T mu, T g); + /** * Henyey–Greenstein phase function. * @@ -57,6 +66,16 @@ constexpr T isotropic() template T rayleigh(T mu); +template +T cornette_shanks(T mu, T g) +{ + const T k = T(3) / (T(8) * math::pi); + const T gg = g * g; + const T num = (T(1) - gg) * (T(1) + mu * mu); + const T den = (T(2) + gg) * std::pow(T(1) + gg - T(2) * g * mu, T(1.5)); + return k * num / den; +} + template T henyey_greenstein(T mu, T g) { diff --git a/src/renderer/passes/sky-pass.cpp b/src/renderer/passes/sky-pass.cpp index 9dcef53..881dadb 100644 --- a/src/renderer/passes/sky-pass.cpp +++ b/src/renderer/passes/sky-pass.cpp @@ -60,19 +60,12 @@ sky_pass::sky_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffe moon_material(nullptr), moon_model_vao(nullptr), moon_shader_program(nullptr), - blue_noise_map(nullptr), - sky_gradient(nullptr), - sky_gradient2(nullptr), - observer_location{0.0f, 0.0f, 0.0f}, time_tween(nullptr), - time_of_day_tween(0.0, math::lerp), - julian_day_tween(0.0, math::lerp), - horizon_color_tween(float3{0.0f, 0.0f, 0.0f}, math::lerp), - zenith_color_tween(float3{1.0f, 1.0f, 1.0f}, math::lerp), + observer_altitude_tween(0.0f, math::lerp), + sun_position_tween(float3{1.0f, 0.0f, 0.0f}, math::lerp), sun_color_tween(float3{1.0f, 1.0f, 1.0f}, math::lerp), topocentric_frame_translation({0, 0, 0}, math::lerp), - topocentric_frame_rotation(math::quaternion::identity(), math::nlerp), - sun_object(nullptr) + topocentric_frame_rotation(math::quaternion::identity(), math::nlerp) { // Load star catalog string_table* star_catalog = resource_manager->load("stars.csv"); @@ -105,7 +98,9 @@ sky_pass::sky_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffe bv_color = std::stod(catalog_row[4]); } catch (const std::exception& e) - {} + { + continue; + } // Convert right ascension and declination from degrees to radians ra = math::wrap_radians(math::radians(ra)); @@ -202,12 +197,8 @@ void sky_pass::render(render_context* context) const float4x4 model_view_projection = projection * model_view; float exposure = std::exp2(camera.get_exposure_tween().interpolate(context->alpha)); - float time_of_day = time_of_day_tween.interpolate(context->alpha); - float julian_day = julian_day_tween.interpolate(context->alpha); - float3 horizon_color = horizon_color_tween.interpolate(context->alpha); - float3 zenith_color = zenith_color_tween.interpolate(context->alpha); - float3 sun_color = sun_color_tween.interpolate(context->alpha); - + // Interpolate observer altitude + float observer_altitude = observer_altitude_tween.interpolate(context->alpha); // Construct tweened inertial to topocentric frame physics::frame topocentric_frame = @@ -216,15 +207,12 @@ void sky_pass::render(render_context* context) const topocentric_frame_rotation.interpolate(context->alpha) }; - // Get topocentric space sun position - float3 sun_position = {0, 0, 0}; - if (sun_object != nullptr) - { - sun_position = math::normalize(sun_object->get_transform_tween().interpolate(context->alpha).translation); - } + // Get topocentric space direction to sun + float3 sun_position = sun_position_tween.interpolate(context->alpha); + float3 sun_direction = math::normalize(sun_position); - // Get topocentric space moon position - float3 moon_position = {0, 0, 0}; + // Interpolate sun color + float3 sun_color = sun_color_tween.interpolate(context->alpha); // Draw sky model { @@ -233,41 +221,34 @@ void sky_pass::render(render_context* context) const // Upload shader parameters if (model_view_projection_input) model_view_projection_input->upload(model_view_projection); - if (horizon_color_input) - horizon_color_input->upload(horizon_color); - if (zenith_color_input) - zenith_color_input->upload(zenith_color); - if (sun_color_input) - sun_color_input->upload(sun_color); if (mouse_input) mouse_input->upload(mouse_position); if (resolution_input) resolution_input->upload(resolution); if (time_input) time_input->upload(time); - if (time_of_day_input) - time_of_day_input->upload(time_of_day); - if (blue_noise_map_input) - blue_noise_map_input->upload(blue_noise_map); - if (sky_gradient_input && sky_gradient) - sky_gradient_input->upload(sky_gradient); - if (sky_gradient2_input && sky_gradient2) - sky_gradient2_input->upload(sky_gradient2); - if (observer_location_input) - observer_location_input->upload(observer_location); - if (sun_position_input) - sun_position_input->upload(sun_position); - if (moon_position_input) - moon_position_input->upload(moon_position); - if (julian_day_input) - julian_day_input->upload(julian_day); - if (cos_moon_angular_radius_input) - cos_moon_angular_radius_input->upload(cos_moon_angular_radius); - if (cos_sun_angular_radius_input) - cos_sun_angular_radius_input->upload(cos_sun_angular_radius); if (exposure_input) exposure_input->upload(exposure); + if (observer_altitude_input) + observer_altitude_input->upload(observer_altitude); + if (sun_direction_input) + sun_direction_input->upload(sun_direction); + if (cos_sun_angular_radius_input) + cos_sun_angular_radius_input->upload(cos_sun_angular_radius); + if (sun_color_input) + sun_color_input->upload(sun_color); + if (scale_height_rm_input) + scale_height_rm_input->upload(scale_height_rm); + if (rayleigh_scattering_input) + rayleigh_scattering_input->upload(rayleigh_scattering); + if (mie_scattering_input) + mie_scattering_input->upload(mie_scattering); + if (mie_asymmetry_input) + mie_asymmetry_input->upload(mie_asymmetry); + if (atmosphere_radii_input) + atmosphere_radii_input->upload(atmosphere_radii); + sky_material->upload(context->alpha); rasterizer->draw_arrays(*sky_model_vao, sky_model_drawing_mode, sky_model_start_index, sky_model_index_count); @@ -278,6 +259,8 @@ void sky_pass::render(render_context* context) const glBlendFunc(GL_ONE, GL_ONE); // Draw moon model + /* + float3 moon_position = {0, 0, 0}; if (moon_position.y >= -moon_angular_radius) { @@ -307,34 +290,13 @@ void sky_pass::render(render_context* context) const moon_material->upload(context->alpha); rasterizer->draw_arrays(*moon_model_vao, moon_model_drawing_mode, moon_model_start_index, moon_model_index_count); } + */ // Draw stars { float star_distance = (clip_near + clip_far) * 0.5f; - double lat = math::radians(1.0); - double lst = time_of_day / 24.0f * math::two_pi; - //std::cout << "lst: " << lst << std::endl; - - /* - double3x3 equatorial_to_horizontal = coordinates::rectangular::equatorial::to_horizontal(lat, lst); - - const double3x3 horizontal_to_local = coordinates::rectangular::rotate_x(-math::half_pi) * coordinates::rectangular::rotate_z(-math::half_pi); - - double3x3 rotation = horizontal_to_local * equatorial_to_horizontal; - - model = math::type_cast(math::scale(math::resize<4, 4>(rotation), double3{star_distance, star_distance, star_distance}));; - */ - - //math::transform star_transform; - //star_transform.translation = {0.0, 0.0, 0.0}; - //star_transform.rotation = math::normalize(rotation_x * rotation_y); - //star_transform.rotation = math::normalize(math::type_cast(math::quaternion_cast(rotation))); - //star_transform.rotation = math::identity_quaternion; - //star_transform.scale = {star_distance, star_distance, star_distance}; - //model = math::matrix_cast(star_transform); - - model = topocentric_frame.matrix(); + model = math::resize<4, 4>(math::matrix_cast(topocentric_frame.rotation)); model = math::scale(model, {star_distance, star_distance, star_distance}); model_view = view * model; @@ -377,23 +339,20 @@ void sky_pass::set_sky_model(const model* model) if (sky_shader_program) { model_view_projection_input = sky_shader_program->get_input("model_view_projection"); - horizon_color_input = sky_shader_program->get_input("horizon_color"); - zenith_color_input = sky_shader_program->get_input("zenith_color"); - sun_color_input = sky_shader_program->get_input("sun_color"); mouse_input = sky_shader_program->get_input("mouse"); resolution_input = sky_shader_program->get_input("resolution"); time_input = sky_shader_program->get_input("time"); - time_of_day_input = sky_shader_program->get_input("time_of_day"); - blue_noise_map_input = sky_shader_program->get_input("blue_noise_map"); - sky_gradient_input = sky_shader_program->get_input("sky_gradient"); - sky_gradient2_input = sky_shader_program->get_input("sky_gradient2"); - observer_location_input = sky_shader_program->get_input("observer_location"); - sun_position_input = sky_shader_program->get_input("sun_position"); - moon_position_input = sky_shader_program->get_input("moon_position"); - julian_day_input = sky_shader_program->get_input("julian_day"); - cos_moon_angular_radius_input = sky_shader_program->get_input("cos_moon_angular_radius"); - cos_sun_angular_radius_input = sky_shader_program->get_input("cos_sun_angular_radius"); exposure_input = sky_shader_program->get_input("camera.exposure"); + + observer_altitude_input = sky_shader_program->get_input("observer_altitude"); + sun_direction_input = sky_shader_program->get_input("sun_direction"); + sun_color_input = sky_shader_program->get_input("sun_color"); + cos_sun_angular_radius_input = sky_shader_program->get_input("cos_sun_angular_radius"); + scale_height_rm_input = sky_shader_program->get_input("scale_height_rm"); + rayleigh_scattering_input = sky_shader_program->get_input("rayleigh_scattering"); + mie_scattering_input = sky_shader_program->get_input("mie_scattering"); + mie_asymmetry_input = sky_shader_program->get_input("mie_asymmetry"); + atmosphere_radii_input = sky_shader_program->get_input("atmosphere_radii"); } } } @@ -441,18 +400,11 @@ void sky_pass::set_moon_model(const model* model) void sky_pass::update_tweens() { - julian_day_tween.update(); - time_of_day_tween.update(); - horizon_color_tween.update(); - zenith_color_tween.update(); + observer_altitude_tween.update(); + sun_position_tween.update(); + sun_color_tween.update(); topocentric_frame_translation.update(); topocentric_frame_rotation.update(); - sun_color_tween.update(); -} - -void sky_pass::set_time_of_day(float time) -{ - time_of_day_tween[1] = time; } void sky_pass::set_time_tween(const tween* time) @@ -460,63 +412,53 @@ void sky_pass::set_time_tween(const tween* time) this->time_tween = time; } -void sky_pass::set_blue_noise_map(const gl::texture_2d* texture) -{ - blue_noise_map = texture; -} - -void sky_pass::set_sky_gradient(const gl::texture_2d* texture, const gl::texture_2d* texture2) -{ - sky_gradient = texture; - sky_gradient2 = texture2; -} - -void sky_pass::set_julian_day(float jd) +void sky_pass::set_topocentric_frame(const physics::frame& frame) { - julian_day_tween[1] = jd; + topocentric_frame_translation[1] = frame.translation; + topocentric_frame_rotation[1] = frame.rotation; } -void sky_pass::set_observer_location(float altitude, float latitude, float longitude) +void sky_pass::set_sun_position(const float3& position) { - observer_location = {altitude, latitude, longitude}; + sun_position_tween[1] = position; } -void sky_pass::set_moon_angular_radius(float radius) +void sky_pass::set_sun_color(const float3& color) { - moon_angular_radius = radius; - cos_moon_angular_radius = std::cos(moon_angular_radius); + sun_color_tween[1] = color; } void sky_pass::set_sun_angular_radius(float radius) { - sun_angular_radius = radius; - cos_sun_angular_radius = std::cos(sun_angular_radius); + cos_sun_angular_radius = std::cos(radius); } -void sky_pass::set_topocentric_frame(const physics::frame& frame) +void sky_pass::set_observer_altitude(float altitude) { - topocentric_frame_translation[1] = frame.translation; - topocentric_frame_rotation[1] = frame.rotation; + observer_altitude_tween[1] = altitude; } -void sky_pass::set_sun_object(const scene::object_base* object) +void sky_pass::set_scale_heights(float rayleigh, float mie) { - sun_object = object; + scale_height_rm = {rayleigh, mie}; } -void sky_pass::set_horizon_color(const float3& color) +void sky_pass::set_scattering_coefficients(const float3& r, const float3& m) { - horizon_color_tween[1] = color; + rayleigh_scattering = r; + mie_scattering = m; } -void sky_pass::set_zenith_color(const float3& color) +void sky_pass::set_mie_asymmetry(float g) { - zenith_color_tween[1] = color; + mie_asymmetry = {g, g * g}; } -void sky_pass::set_sun_color(const float3& color) +void sky_pass::set_atmosphere_radii(float inner, float outer) { - sun_color_tween[1] = color; + atmosphere_radii.x = inner; + atmosphere_radii.y = outer; + atmosphere_radii.z = outer * outer; } void sky_pass::handle_event(const mouse_moved_event& event) diff --git a/src/renderer/passes/sky-pass.hpp b/src/renderer/passes/sky-pass.hpp index cd7b724..ce58dee 100644 --- a/src/renderer/passes/sky-pass.hpp +++ b/src/renderer/passes/sky-pass.hpp @@ -53,46 +53,39 @@ public: void update_tweens(); void set_sky_model(const model* model); - void set_horizon_color(const float3& color); - void set_zenith_color(const float3& color); - void set_sun_color(const float3& color); - void set_time_of_day(float time); - void set_blue_noise_map(const gl::texture_2d* texture); - void set_sky_gradient(const gl::texture_2d* texture, const gl::texture_2d* texture2); void set_time_tween(const tween* time); void set_moon_model(const model* model); - void set_julian_day(float jd); - void set_observer_location(float altitude, float latitude, float longitude); + void set_topocentric_frame(const physics::frame& frame); - void set_moon_angular_radius(float radius); + void set_sun_position(const float3& position); + void set_sun_color(const float3& color); void set_sun_angular_radius(float radius); - - void set_topocentric_frame(const physics::frame& frame); - void set_sun_object(const scene::object_base* object); + void set_observer_altitude(float altitude); + void set_scale_heights(float rayleigh, float mie); + void set_scattering_coefficients(const float3& r, const float3& m); + void set_mie_asymmetry(float g); + void set_atmosphere_radii(float inner, float outer); private: virtual void handle_event(const mouse_moved_event& event); gl::shader_program* sky_shader_program; const gl::shader_input* model_view_projection_input; - const gl::shader_input* horizon_color_input; - const gl::shader_input* zenith_color_input; const gl::shader_input* mouse_input; const gl::shader_input* resolution_input; const gl::shader_input* time_input; - const gl::shader_input* time_of_day_input; - const gl::shader_input* observer_location_input; - const gl::shader_input* sun_position_input; - const gl::shader_input* moon_position_input; - const gl::shader_input* blue_noise_map_input; - const gl::shader_input* julian_day_input; - const gl::shader_input* cos_sun_angular_radius_input; - const gl::shader_input* cos_moon_angular_radius_input; - const gl::shader_input* sky_gradient_input; - const gl::shader_input* sky_gradient2_input; const gl::shader_input* exposure_input; + + const gl::shader_input* observer_altitude_input; + const gl::shader_input* sun_direction_input; const gl::shader_input* sun_color_input; + const gl::shader_input* cos_sun_angular_radius_input; + const gl::shader_input* scale_height_rm_input; + const gl::shader_input* rayleigh_scattering_input; + const gl::shader_input* mie_scattering_input; + const gl::shader_input* mie_asymmetry_input; + const gl::shader_input* atmosphere_radii_input; gl::shader_program* moon_shader_program; const gl::shader_input* moon_model_view_projection_input; @@ -127,25 +120,20 @@ private: const gl::texture_2d* sky_gradient; const gl::texture_2d* sky_gradient2; float2 mouse_position; - - float3 observer_location; const tween* time_tween; - tween time_of_day_tween; - tween julian_day_tween; - tween horizon_color_tween; - tween zenith_color_tween; + tween observer_altitude_tween; + tween sun_position_tween; tween sun_color_tween; - tween topocentric_frame_translation; tween> topocentric_frame_rotation; - float moon_angular_radius; - float cos_moon_angular_radius; - float sun_angular_radius; float cos_sun_angular_radius; - - const scene::object_base* sun_object; + float2 scale_height_rm; + float3 rayleigh_scattering; + float3 mie_scattering; + float2 mie_asymmetry; + float3 atmosphere_radii; }; #endif // ANTKEEPER_SKY_PASS_HPP