X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Feffects%2Fsky.cpp;h=eef6a58c4ccdedb622541fb828e2f925a3c17145;hb=7515dea78777a7184f207d353d23f9ad9917675e;hp=8fa00cfbd4d44e884cdfadfd6268226705e039d2;hpb=06d83c11e10208478487dea864ddd7822630c391;p=libs%2Fgl.git diff --git a/source/effects/sky.cpp b/source/effects/sky.cpp index 8fa00cfb..eef6a58c 100644 --- a/source/effects/sky.cpp +++ b/source/effects/sky.cpp @@ -1,7 +1,11 @@ -#include "light.h" +#include +#include +#include "directionallight.h" +#include "error.h" #include "mesh.h" #include "renderer.h" #include "resources.h" +#include "texture2d.h" #include "sky.h" using namespace std; @@ -9,32 +13,29 @@ using namespace std; namespace Msp { namespace GL { -Sky::Sky(Resources &resources, Renderable &r, const Light &s): - Effect(r), +Sky::Sky(Renderable &c, DirectionalLight &s): + Effect(c), sun(s), - transmittance_shprog(resources.get("_sky_transmittance.glsl.shader")), + transmittance_lookup(128, 64, (COLOR_ATTACHMENT,RGBA16F)), + transmittance_shprog(Resources::get_global().get("_sky_transmittance.glsl.shader")), transmittance_lookup_dirty(true), - distant_shprog(resources.get("_sky_distant.glsl.shader")), - fullscreen_mesh(resources.get("_fullscreen_quad.mesh")), - backdrop_shprog(resources.get("_sky_backdrop.glsl.shader")), - sampler(resources.get("_linear_clamp.samp")), - wrap_sampler(resources.get("_linear_clamp_v.samp")), + distant(256, 128, (COLOR_ATTACHMENT,RGBA16F)), + distant_shprog(Resources::get_global().get("_sky_distant.glsl.shader")), + fullscreen_mesh(Resources::get_global().get("_fullscreen_quad.mesh")), + backdrop_shprog(Resources::get_global().get("_sky_backdrop.glsl.shader")), + sampler(Resources::get_global().get("_linear_clamp.samp")), + wrap_sampler(Resources::get_global().get("_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) +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); @@ -50,9 +51,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) @@ -61,24 +98,31 @@ void Sky::setup_frame(Renderer &renderer) rendered = true; shdata.uniform("light_color", sun.get_color()); - shdata.uniform("light_dir", sun.get_position().slice<3>(0)); + shdata.uniform("light_dir", -sun.get_direction()); + sun.set_transmittance(get_transmittance(-sun.get_direction())); - Renderer::Push push(renderer); - - if(transmittance_lookup_dirty) { - transmittance_lookup_dirty = false; - Bind bind_fbo(transmittance_fbo); - renderer.set_shader_program(&transmittance_shprog, &shdata); + Renderer::Push push(renderer); + + renderer.add_shader_data(shdata); + + if(transmittance_lookup_dirty) + { + transmittance_lookup_dirty = false; + renderer.set_pipeline_key(this); + renderer.set_framebuffer(&transmittance_lookup.get_framebuffer()); + renderer.set_shader_program(&transmittance_shprog); + fullscreen_mesh.draw(renderer); + } + + renderer.set_pipeline_key(this, 1); + renderer.set_framebuffer(&distant.get_framebuffer()); + renderer.set_shader_program(&distant_shprog); + renderer.set_texture("transmittance_lookup", &transmittance_lookup.get_target_texture(0), &sampler); 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); + content.setup_frame(renderer); } void Sky::finish_frame() @@ -86,21 +130,36 @@ void Sky::finish_frame() if(rendered) { rendered = false; - renderable.finish_frame(); + content.finish_frame(); } } void Sky::render(Renderer &renderer, Tag tag) const { - renderable.render(renderer, tag); + content.render(renderer, tag); + + if(!is_enabled_for_method(tag)) + return; Renderer::Push push(renderer); + renderer.set_pipeline_key(this, 2); renderer.set_shader_program(&backdrop_shprog, &shdata); - renderer.set_texture("distant", &distant, &wrap_sampler); + renderer.set_texture("distant", &distant.get_target_texture(0), &wrap_sampler); fullscreen_mesh.draw(renderer); } +void Sky::set_debug_name(const string &name) +{ +#ifdef DEBUG + transmittance_lookup.set_debug_name(name+" [RT:transmittance]"); + distant.set_debug_name(name+" [RT:distant]"); + shdata.set_debug_name(name+" [UBO]"); +#else + (void)name; +#endif +} + Sky::Planet::Planet(): rayleigh_scatter(0.0f), @@ -112,7 +171,8 @@ Sky::Planet::Planet(): ozone_band_center(1e4f), ozone_band_extent(1e2f), atmosphere_thickness(2e4f), - planet_radius(1e6f) + planet_radius(1e6f), + ground_albedo(0.2f) { } Sky::Planet Sky::Planet::earth() @@ -131,5 +191,29 @@ Sky::Planet Sky::Planet::earth() return planet; } + +Sky *Sky::Template::create(const map &renderables) const +{ + Renderable *content = get_item(renderables, content_name); + if(!content || !sun) + throw invalid_operation("Sky::Template::create"); + return new Sky(*content, *sun); +} + + +DataFile::Loader::ActionMap Sky::Template::Loader::shared_actions; + +Sky::Template::Loader::Loader(Template &t, Collection &c): + DerivedObjectLoader(t, c) +{ + set_actions(shared_actions); +} + +void Sky::Template::Loader::init_actions() +{ + Effect::Template::Loader::init_actions(); + add("sun", &Template::sun); +} + } // namespace GL } // namespace Msp