1 #include <msp/geometry/hypersphere.h>
2 #include <msp/geometry/ray.h>
3 #include "directionallight.h"
16 Sky::Sky(Renderable &r, DirectionalLight &s):
19 transmittance_lookup(128, 64, (COLOR_ATTACHMENT,RGB16F)),
20 transmittance_shprog(Resources::get_global().get<Program>("_sky_transmittance.glsl.shader")),
21 transmittance_lookup_dirty(true),
22 distant(256, 128, (COLOR_ATTACHMENT,RGB16F)),
23 distant_shprog(Resources::get_global().get<Program>("_sky_distant.glsl.shader")),
24 fullscreen_mesh(Resources::get_global().get<Mesh>("_fullscreen_quad.mesh")),
25 backdrop_shprog(Resources::get_global().get<Program>("_sky_backdrop.glsl.shader")),
26 sampler(Resources::get_global().get<Sampler>("_linear_clamp.samp")),
27 wrap_sampler(Resources::get_global().get<Sampler>("_linear_clamp_v.samp")),
30 shdata.uniform("n_steps", 50);
32 set_planet(Planet::earth());
33 set_view_height(5.0f);
36 void Sky::set_planet(const Planet &p)
39 shdata.uniform("events.rayleigh_scatter", planet.rayleigh_scatter.r, planet.rayleigh_scatter.g, planet.rayleigh_scatter.b);
40 shdata.uniform("events.mie_scatter", planet.mie_scatter.r, planet.mie_scatter.g, planet.mie_scatter.b);
41 shdata.uniform("events.mie_absorb", planet.mie_absorb.r, planet.mie_absorb.g, planet.mie_absorb.b);
42 shdata.uniform("events.ozone_absorb", planet.ozone_absorb.r, planet.ozone_absorb.g, planet.ozone_absorb.b);
43 shdata.uniform("rayleigh_density_decay", planet.rayleigh_density_decay);
44 shdata.uniform("mie_density_decay", planet.mie_density_decay);
45 shdata.uniform("ozone_band_center", planet.ozone_band_center);
46 shdata.uniform("ozone_band_extent", planet.ozone_band_extent);
47 shdata.uniform("atmosphere_thickness", planet.atmosphere_thickness);
48 shdata.uniform("planet_radius", planet.planet_radius);
49 shdata.uniform("ground_albedo", planet.ground_albedo.r, planet.ground_albedo.g, planet.ground_albedo.b);
52 void Sky::set_view_height(float h)
55 shdata.uniform("view_height", h);
58 Color Sky::get_transmittance(const Vector3 &look_dir)
60 Vector3 pos(0.0f, 0.0f, view_height);
61 Vector3 planet_center(0.0f, 0.0f, -planet.planet_radius);
63 Geometry::Ray<float, 3> ray(pos-planet_center, look_dir);
64 Geometry::HyperSphere<float, 3> surface(planet.planet_radius);
65 Geometry::SurfacePoint<float, 3> intersection;
66 if(surface.get_intersections(ray, &intersection, 1))
69 Geometry::HyperSphere<float, 3> space(planet.planet_radius+planet.atmosphere_thickness);
70 if(!space.get_intersections(ray, &intersection, 1))
73 float step_size = intersection.distance/50;
75 Color path_extinction(0.0f);
76 for(unsigned i=0; i<50; ++i)
78 Vector3 from_center = pos-planet_center;
79 float height = from_center.norm()-planet.planet_radius;
81 Color rayleigh_scatter = planet.rayleigh_scatter*exp(height/planet.rayleigh_density_decay);
82 Color mie_scatter = planet.mie_scatter*exp(height/planet.mie_density_decay);
83 Color mie_absorb = planet.mie_absorb*exp(height/planet.mie_density_decay);
84 Color ozone_absorb = planet.ozone_absorb*max(1.0f-abs(height-planet.ozone_band_center)/planet.ozone_band_extent, 0.0f);
86 path_extinction = path_extinction+(rayleigh_scatter+mie_scatter+mie_absorb+ozone_absorb)*step_size;
87 pos += look_dir*step_size;
90 return Color(exp(-path_extinction.r), exp(-path_extinction.g), exp(-path_extinction.b));
93 void Sky::setup_frame(Renderer &renderer)
100 shdata.uniform("light_color", sun.get_color());
101 shdata.uniform("light_dir", -sun.get_direction());
102 sun.set_transmittance(get_transmittance(-sun.get_direction()));
104 Renderer::Push push(renderer);
106 if(transmittance_lookup_dirty)
108 transmittance_lookup_dirty = false;
109 renderer.set_framebuffer(&transmittance_lookup.get_framebuffer());
110 renderer.set_shader_program(&transmittance_shprog, &shdata);
111 fullscreen_mesh.draw(renderer);
114 renderer.set_framebuffer(&distant.get_framebuffer());
115 renderer.set_shader_program(&distant_shprog, &shdata);
116 renderer.set_texture("transmittance_lookup", &transmittance_lookup.get_target_texture(0), &sampler);
117 fullscreen_mesh.draw(renderer);
119 renderable.setup_frame(renderer);
122 void Sky::finish_frame()
127 renderable.finish_frame();
131 void Sky::render(Renderer &renderer, Tag tag) const
133 renderable.render(renderer, tag);
135 if(!enabled_methods.count(tag))
138 Renderer::Push push(renderer);
140 renderer.set_shader_program(&backdrop_shprog, &shdata);
141 renderer.set_texture("distant", &distant.get_target_texture(0), &wrap_sampler);
142 fullscreen_mesh.draw(renderer);
145 void Sky::set_debug_name(const string &name)
148 transmittance_lookup.set_debug_name(name+" [RT:transmittance]");
149 distant.set_debug_name(name+" [RT:distant]");
150 shdata.set_debug_name(name+" [UBO]");
157 Sky::Planet::Planet():
158 rayleigh_scatter(0.0f),
162 rayleigh_density_decay(1e3f),
163 mie_density_decay(1e3f),
164 ozone_band_center(1e4f),
165 ozone_band_extent(1e2f),
166 atmosphere_thickness(2e4f),
171 Sky::Planet Sky::Planet::earth()
174 planet.rayleigh_scatter = Color(5.802e-6f, 13.558e-6f, 33.1e-6f);
175 planet.mie_scatter = Color(3.996e-6f, 3.996e-6f, 3.996e-6f);
176 planet.mie_absorb = Color(4.4e-6f, 4.4e-6f, 4.4e-6f);
177 planet.ozone_absorb = Color(0.65e-6f, 1.881e-6f, 0.085e-6f);
178 planet.rayleigh_density_decay = -8e3f;
179 planet.mie_density_decay = -1.2e3f;
180 planet.ozone_band_center = 25e3f;
181 planet.ozone_band_extent = 15e3f;
182 planet.atmosphere_thickness = 1e5f;
183 planet.planet_radius = 6.36e6f;
188 Sky *Sky::Template::create(const map<string, Renderable *> &renderables) const
190 Renderable *content = get_item(renderables, content_name);
192 throw invalid_operation("Sky::Template::create");
193 return new Sky(*content, *sun);
197 DataFile::Loader::ActionMap Sky::Template::Loader::shared_actions;
199 Sky::Template::Loader::Loader(Template &t, Collection &c):
200 DerivedObjectLoader<Template, Effect::Template::Loader>(t, c)
202 set_actions(shared_actions);
205 void Sky::Template::Loader::init_actions()
207 Effect::Template::Loader::init_actions();
208 add("sun", &Template::sun);