-#include "light.h"
+#include <msp/geometry/hypersphere.h>
+#include <msp/geometry/ray.h>
+#include "directionallight.h"
+#include "error.h"
#include "mesh.h"
#include "renderer.h"
#include "resources.h"
+#include "texture2d.h"
#include "sky.h"
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<Program>("_sky_transmittance.glsl.shader")),
+ transmittance_lookup(128, 64, (COLOR_ATTACHMENT,RGBA16F)),
+ transmittance_shprog(Resources::get_global().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")),
+ distant(256, 128, (COLOR_ATTACHMENT,RGBA16F)),
+ distant_shprog(Resources::get_global().get<Program>("_sky_distant.glsl.shader")),
+ fullscreen_mesh(Resources::get_global().get<Mesh>("_fullscreen_quad.mesh")),
+ backdrop_shprog(Resources::get_global().get<Program>("_sky_backdrop.glsl.shader")),
+ sampler(Resources::get_global().get<Sampler>("_linear_clamp.samp")),
+ wrap_sampler(Resources::get_global().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)
+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);
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<float, 3> ray(pos-planet_center, look_dir);
+ Geometry::HyperSphere<float, 3> surface(planet.planet_radius);
+ Geometry::SurfacePoint<float, 3> intersection;
+ if(surface.get_intersections(ray, &intersection, 1))
+ return Color(0.0f);
+
+ Geometry::HyperSphere<float, 3> 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)
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_framebuffer(&transmittance_lookup.get_framebuffer());
renderer.set_shader_program(&transmittance_shprog, &shdata);
fullscreen_mesh.draw(renderer);
}
- Bind bind_fbo(distant_fbo);
+ renderer.set_framebuffer(&distant.get_framebuffer());
renderer.set_shader_program(&distant_shprog, &shdata);
- renderer.set_texture("transmittance_lookup", &transmittance_lookup, &sampler);
+ renderer.set_texture("transmittance_lookup", &transmittance_lookup.get_target_texture(0), &sampler);
fullscreen_mesh.draw(renderer);
- renderable.setup_frame(renderer);
+ content.setup_frame(renderer);
}
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_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),
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()
return planet;
}
+
+Sky *Sky::Template::create(const map<string, Renderable *> &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<Template, Effect::Template::Loader>(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