]> git.tdb.fi Git - libs/gl.git/blobdiff - source/effects/sky.cpp
Add an effect for rendering a procedurally generated sky
[libs/gl.git] / source / effects / sky.cpp
diff --git a/source/effects/sky.cpp b/source/effects/sky.cpp
new file mode 100644 (file)
index 0000000..8fa00cf
--- /dev/null
@@ -0,0 +1,135 @@
+#include "light.h"
+#include "mesh.h"
+#include "renderer.h"
+#include "resources.h"
+#include "sky.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+Sky::Sky(Resources &resources, Renderable &r, const Light &s):
+       Effect(r),
+       sun(s),
+       transmittance_shprog(resources.get<Program>("_sky_transmittance.glsl.shader")),
+       transmittance_lookup_dirty(true),
+       distant_shprog(resources.get<Program>("_sky_distant.glsl.shader")),
+       fullscreen_mesh(resources.get<Mesh>("_fullscreen_quad.mesh")),
+       backdrop_shprog(resources.get<Program>("_sky_backdrop.glsl.shader")),
+       sampler(resources.get<Sampler>("_linear_clamp.samp")),
+       wrap_sampler(resources.get<Sampler>("_linear_clamp_v.samp")),
+       rendered(false)
+{
+       transmittance_lookup.storage(RGB16F, 128, 64, 1);
+       transmittance_fbo.attach(COLOR_ATTACHMENT0, transmittance_lookup);
+
+       distant.storage(RGB16F, 256, 128, 1);
+       distant_fbo.attach(COLOR_ATTACHMENT0, distant);
+
+       shdata.uniform("n_steps", 50);
+
+       set_planet(Planet::earth());
+       set_view_height(5.0f);
+}
+
+void Sky::set_planet(const Planet &planet)
+{
+       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);
+       shdata.uniform("events.ozone_absorb", planet.ozone_absorb.r, planet.ozone_absorb.g, planet.ozone_absorb.b);
+       shdata.uniform("rayleigh_density_decay", planet.rayleigh_density_decay);
+       shdata.uniform("mie_density_decay", planet.mie_density_decay);
+       shdata.uniform("ozone_band_center", planet.ozone_band_center);
+       shdata.uniform("ozone_band_extent", planet.ozone_band_extent);
+       shdata.uniform("atmosphere_thickness", planet.atmosphere_thickness);
+       shdata.uniform("planet_radius", planet.planet_radius);
+       shdata.uniform("ground_albedo", planet.ground_albedo.r, planet.ground_albedo.g, planet.ground_albedo.b);
+}
+
+void Sky::set_view_height(float h)
+{
+       shdata.uniform("view_height", h);
+}
+
+void Sky::setup_frame(Renderer &renderer)
+{
+       if(rendered)
+               return;
+
+       rendered = true;
+
+       shdata.uniform("light_color", sun.get_color());
+       shdata.uniform("light_dir", sun.get_position().slice<3>(0));
+
+       Renderer::Push push(renderer);
+
+       if(transmittance_lookup_dirty)
+       {
+               transmittance_lookup_dirty = false;
+               Bind bind_fbo(transmittance_fbo);
+               renderer.set_shader_program(&transmittance_shprog, &shdata);
+               fullscreen_mesh.draw(renderer);
+       }
+
+       Bind bind_fbo(distant_fbo);
+       renderer.set_shader_program(&distant_shprog, &shdata);
+       renderer.set_texture("transmittance_lookup", &transmittance_lookup, &sampler);
+       fullscreen_mesh.draw(renderer);
+
+       renderable.setup_frame(renderer);
+}
+
+void Sky::finish_frame()
+{
+       if(rendered)
+       {
+               rendered = false;
+               renderable.finish_frame();
+       }
+}
+
+void Sky::render(Renderer &renderer, Tag tag) const
+{
+       renderable.render(renderer, tag);
+
+       Renderer::Push push(renderer);
+
+       renderer.set_shader_program(&backdrop_shprog, &shdata);
+       renderer.set_texture("distant", &distant, &wrap_sampler);
+       fullscreen_mesh.draw(renderer);
+}
+
+
+Sky::Planet::Planet():
+       rayleigh_scatter(0.0f),
+       mie_scatter(0.0f),
+       mie_absorb(0.0f),
+       ozone_absorb(0.0f),
+       rayleigh_density_decay(1e3f),
+       mie_density_decay(1e3f),
+       ozone_band_center(1e4f),
+       ozone_band_extent(1e2f),
+       atmosphere_thickness(2e4f),
+       planet_radius(1e6f)
+{ }
+
+Sky::Planet Sky::Planet::earth()
+{
+       Planet planet;
+       planet.rayleigh_scatter = Color(5.802e-6f, 13.558e-6f, 33.1e-6f);
+       planet.mie_scatter = Color(3.996e-6f, 3.996e-6f, 3.996e-6f);
+       planet.mie_absorb = Color(4.4e-6f, 4.4e-6f, 4.4e-6f);
+       planet.ozone_absorb = Color(0.65e-6f, 1.881e-6f, 0.085e-6f);
+       planet.rayleigh_density_decay = -8e3f;
+       planet.mie_density_decay = -1.2e3f;
+       planet.ozone_band_center = 25e3f;
+       planet.ozone_band_extent = 15e3f;
+       planet.atmosphere_thickness = 1e5f;
+       planet.planet_radius = 6.36e6f;
+       return planet;
+}
+
+} // namespace GL
+} // namespace Msp