From a266f0f915827b20591f6244ccc36129e844f408 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Wed, 5 May 2021 18:35:34 +0300 Subject: [PATCH] Modify sunlight color based on transmittance of the atmosphere --- demos/desertpillars/source/desertpillars.cpp | 2 +- source/effects/sky.cpp | 44 +++++++++++++++++++- source/effects/sky.h | 8 +++- source/materials/light.cpp | 8 +++- source/materials/light.h | 6 +++ 5 files changed, 62 insertions(+), 6 deletions(-) diff --git a/demos/desertpillars/source/desertpillars.cpp b/demos/desertpillars/source/desertpillars.cpp index 5f3b29b1..bdbc069e 100644 --- a/demos/desertpillars/source/desertpillars.cpp +++ b/demos/desertpillars/source/desertpillars.cpp @@ -34,7 +34,7 @@ DesertPillars::DesertPillars(int, char **): window.signal_close.connect(sigc::bind(sigc::mem_fun(this, &DesertPillars::exit), 0)); keyboard.signal_button_press.connect(sigc::bind_return(sigc::mem_fun(this, &DesertPillars::key_press), false)); - const GL::Light &sun = resources.get("Sun.light"); + GL::Light &sun = resources.get("Sun.light"); sky = make_unique(content, sun); unsigned shadow_size = 8192; diff --git a/source/effects/sky.cpp b/source/effects/sky.cpp index baf4864a..9a5f73bc 100644 --- a/source/effects/sky.cpp +++ b/source/effects/sky.cpp @@ -1,3 +1,5 @@ +#include +#include #include "light.h" #include "mesh.h" #include "renderer.h" @@ -9,7 +11,7 @@ using namespace std; namespace Msp { namespace GL { -Sky::Sky(Renderable &r, const Light &s): +Sky::Sky(Renderable &r, Light &s): Effect(r), sun(s), transmittance_lookup(128, 64, (RENDER_COLOR, RGB16F)), @@ -29,8 +31,9 @@ Sky::Sky(Renderable &r, const Light &s): set_view_height(5.0f); } -void Sky::set_planet(const Planet &planet) +void Sky::set_planet(const Planet &p) { + planet = p; shdata.uniform("events.rayleigh_scatter", planet.rayleigh_scatter.r, planet.rayleigh_scatter.g, planet.rayleigh_scatter.b); shdata.uniform("events.mie_scatter", planet.mie_scatter.r, planet.mie_scatter.g, planet.mie_scatter.b); shdata.uniform("events.mie_absorb", planet.mie_absorb.r, planet.mie_absorb.g, planet.mie_absorb.b); @@ -46,9 +49,45 @@ void Sky::set_planet(const Planet &planet) void Sky::set_view_height(float h) { + view_height = h; shdata.uniform("view_height", h); } +Color Sky::get_transmittance(const Vector3 &look_dir) +{ + Vector3 pos(0.0f, 0.0f, view_height); + Vector3 planet_center(0.0f, 0.0f, -planet.planet_radius); + + Geometry::Ray ray(pos-planet_center, look_dir); + Geometry::HyperSphere surface(planet.planet_radius); + Geometry::SurfacePoint intersection; + if(surface.get_intersections(ray, &intersection, 1)) + return Color(0.0f); + + Geometry::HyperSphere space(planet.planet_radius+planet.atmosphere_thickness); + if(!space.get_intersections(ray, &intersection, 1)) + return Color(1.0f); + + float step_size = intersection.distance/50; + + Color path_extinction(0.0f); + for(unsigned i=0; i<50; ++i) + { + Vector3 from_center = pos-planet_center; + float height = from_center.norm()-planet.planet_radius; + + Color rayleigh_scatter = planet.rayleigh_scatter*exp(height/planet.rayleigh_density_decay); + Color mie_scatter = planet.mie_scatter*exp(height/planet.mie_density_decay); + Color mie_absorb = planet.mie_absorb*exp(height/planet.mie_density_decay); + Color ozone_absorb = planet.ozone_absorb*max(1.0f-abs(height-planet.ozone_band_center)/planet.ozone_band_extent, 0.0f); + + path_extinction = path_extinction+(rayleigh_scatter+mie_scatter+mie_absorb+ozone_absorb)*step_size; + pos += look_dir*step_size; + } + + return Color(exp(-path_extinction.r), exp(-path_extinction.g), exp(-path_extinction.b)); +} + void Sky::setup_frame(Renderer &renderer) { if(rendered) @@ -58,6 +97,7 @@ void Sky::setup_frame(Renderer &renderer) shdata.uniform("light_color", sun.get_color()); shdata.uniform("light_dir", sun.get_position().slice<3>(0)); + sun.set_transmittance(get_transmittance(normalize(sun.get_position().slice<3>(0)))); Renderer::Push push(renderer); diff --git a/source/effects/sky.h b/source/effects/sky.h index faa3eb03..5f84c861 100644 --- a/source/effects/sky.h +++ b/source/effects/sky.h @@ -41,7 +41,8 @@ public: }; private: - const Light &sun; + Planet planet; + Light &sun; RenderTarget transmittance_lookup; const Program &transmittance_shprog; bool transmittance_lookup_dirty; @@ -52,14 +53,17 @@ private: const Sampler &sampler; const Sampler &wrap_sampler; mutable ProgramData shdata; + float view_height; bool rendered; public: - Sky(Renderable &, const Light &); + Sky(Renderable &, Light &); void set_planet(const Planet &); void set_view_height(float); + Color get_transmittance(const Vector3 &); + virtual void setup_frame(Renderer &); virtual void finish_frame(); virtual void render(Renderer &, Tag = Tag()) const; diff --git a/source/materials/light.cpp b/source/materials/light.cpp index d84be2ac..2825b81e 100644 --- a/source/materials/light.cpp +++ b/source/materials/light.cpp @@ -12,6 +12,7 @@ namespace GL { Light::Light(): color(1), + transmittance(1), position(0, 0, 1, 0), spot_dir(0, 0, -1), spot_exp(0), @@ -44,6 +45,11 @@ void Light::set_color(const Color &c) color = c; } +void Light::set_transmittance(const Color &t) +{ + transmittance = t; +} + void Light::set_matrix(const Matrix &m) { Placeable::set_matrix(m); @@ -101,7 +107,7 @@ void Light::update_shader_data(ProgramData &shdata, const Matrix &view_matrix, u { string base = format("light_sources[%d]", i); shdata.uniform(base+".position", view_matrix*position); - shdata.uniform(base+".color", color.r, color.g, color.b); + shdata.uniform(base+".color", color.r*transmittance.r, color.g*transmittance.g, color.b*transmittance.b); } diff --git a/source/materials/light.h b/source/materials/light.h index d097d04a..d4b66077 100644 --- a/source/materials/light.h +++ b/source/materials/light.h @@ -44,6 +44,7 @@ public: private: Color color; + Color transmittance; Vector4 position; Vector3 spot_dir; Vector3 direction; @@ -62,7 +63,12 @@ public: to shaders as light_sources[i].color. */ void set_color(const Color &); + /** Sets a multiplier on how much light actually reaches the target. Used + when modeling an atmosphere. */ + void set_transmittance(const Color &); + const Color &get_color() const { return color; } + const Color &get_transmittance() const { return transmittance; } DEPRECATED void set_diffuse(const Color &c) { set_color(c); } DEPRECATED void set_specular(const Color &) { } -- 2.43.0