1 #include <msp/geometry/hypersphere.h>
2 #include <msp/geometry/ray.h>
3 #include "directionallight.h"
16 Sky::Sky(Renderable &c, DirectionalLight &s):
19 transmittance_lookup(128, 64, (COLOR_ATTACHMENT,RGBA16F)),
20 transmittance_shprog(Resources::get_global().get<Program>("_sky_transmittance.glsl.shader")),
21 transmittance_lookup_dirty(true),
22 distant(256, 128, (COLOR_ATTACHMENT,RGBA16F)),
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")),
28 dummy_texture(Resources::get_global().get<Texture>("_placeholder.png")),
31 shdata.uniform("n_steps", 50);
33 set_planet(Planet::earth());
34 set_view_height(5.0f);
37 void Sky::set_planet(const Planet &p)
40 shdata.uniform("events.rayleigh_scatter", planet.rayleigh_scatter.r, planet.rayleigh_scatter.g, planet.rayleigh_scatter.b);
41 shdata.uniform("events.mie_scatter", planet.mie_scatter.r, planet.mie_scatter.g, planet.mie_scatter.b);
42 shdata.uniform("events.mie_absorb", planet.mie_absorb.r, planet.mie_absorb.g, planet.mie_absorb.b);
43 shdata.uniform("events.ozone_absorb", planet.ozone_absorb.r, planet.ozone_absorb.g, planet.ozone_absorb.b);
44 shdata.uniform("rayleigh_density_decay", planet.rayleigh_density_decay);
45 shdata.uniform("mie_density_decay", planet.mie_density_decay);
46 shdata.uniform("ozone_band_center", planet.ozone_band_center);
47 shdata.uniform("ozone_band_extent", planet.ozone_band_extent);
48 shdata.uniform("atmosphere_thickness", planet.atmosphere_thickness);
49 shdata.uniform("planet_radius", planet.planet_radius);
50 shdata.uniform("ground_albedo", planet.ground_albedo.r, planet.ground_albedo.g, planet.ground_albedo.b);
53 void Sky::set_view_height(float h)
56 shdata.uniform("view_height", h);
59 Color Sky::get_transmittance(const Vector3 &look_dir)
61 Vector3 pos(0.0f, 0.0f, view_height);
62 Vector3 planet_center(0.0f, 0.0f, -planet.planet_radius);
64 Geometry::Ray<float, 3> ray(pos-planet_center, look_dir);
65 Geometry::HyperSphere<float, 3> surface(planet.planet_radius);
66 Geometry::SurfacePoint<float, 3> intersection;
67 if(surface.get_intersections(ray, &intersection, 1))
70 Geometry::HyperSphere<float, 3> space(planet.planet_radius+planet.atmosphere_thickness);
71 if(!space.get_intersections(ray, &intersection, 1))
74 float step_size = intersection.distance/50;
76 Color path_extinction(0.0f);
77 for(unsigned i=0; i<50; ++i)
79 Vector3 from_center = pos-planet_center;
80 float height = from_center.norm()-planet.planet_radius;
82 Color rayleigh_scatter = planet.rayleigh_scatter*exp(height/planet.rayleigh_density_decay);
83 Color mie_scatter = planet.mie_scatter*exp(height/planet.mie_density_decay);
84 Color mie_absorb = planet.mie_absorb*exp(height/planet.mie_density_decay);
85 Color ozone_absorb = planet.ozone_absorb*max(1.0f-abs(height-planet.ozone_band_center)/planet.ozone_band_extent, 0.0f);
87 path_extinction = path_extinction+(rayleigh_scatter+mie_scatter+mie_absorb+ozone_absorb)*step_size;
88 pos += look_dir*step_size;
91 return Color(exp(-path_extinction.r), exp(-path_extinction.g), exp(-path_extinction.b));
94 void Sky::setup_frame(Renderer &renderer)
101 shdata.uniform("light_color", sun.get_color());
102 shdata.uniform("light_dir", -sun.get_direction());
103 sun.set_transmittance(get_transmittance(-sun.get_direction()));
106 Renderer::Push push(renderer);
108 renderer.add_shader_data(shdata);
110 if(transmittance_lookup_dirty)
112 transmittance_lookup_dirty = false;
113 renderer.set_pipeline_key(this);
114 renderer.set_framebuffer(&transmittance_lookup.get_framebuffer());
115 renderer.set_shader_program(&transmittance_shprog);
116 renderer.set_texture("transmittance_lookup", &dummy_texture, &sampler);
117 fullscreen_mesh.draw(renderer);
120 renderer.set_pipeline_key(this, 1);
121 renderer.set_framebuffer(&distant.get_framebuffer());
122 renderer.set_shader_program(&distant_shprog);
123 renderer.set_texture("transmittance_lookup", &transmittance_lookup.get_target_texture(0), &sampler);
124 fullscreen_mesh.draw(renderer);
127 content.setup_frame(renderer);
130 void Sky::finish_frame()
135 content.finish_frame();
139 void Sky::render(Renderer &renderer, Tag tag) const
141 content.render(renderer, tag);
143 if(!is_enabled_for_method(tag))
146 Renderer::Push push(renderer);
148 renderer.set_pipeline_key(this, 2);
149 renderer.set_shader_program(&backdrop_shprog, &shdata);
150 renderer.set_texture("distant", &distant.get_target_texture(0), &wrap_sampler);
151 fullscreen_mesh.draw(renderer);
154 void Sky::set_debug_name(const string &name)
157 transmittance_lookup.set_debug_name(name+" [RT:transmittance]");
158 distant.set_debug_name(name+" [RT:distant]");
159 shdata.set_debug_name(name+" [UBO]");
166 Sky::Planet::Planet():
167 rayleigh_scatter(0.0f),
171 rayleigh_density_decay(1e3f),
172 mie_density_decay(1e3f),
173 ozone_band_center(1e4f),
174 ozone_band_extent(1e2f),
175 atmosphere_thickness(2e4f),
180 Sky::Planet Sky::Planet::earth()
183 planet.rayleigh_scatter = Color(5.802e-6f, 13.558e-6f, 33.1e-6f);
184 planet.mie_scatter = Color(3.996e-6f, 3.996e-6f, 3.996e-6f);
185 planet.mie_absorb = Color(4.4e-6f, 4.4e-6f, 4.4e-6f);
186 planet.ozone_absorb = Color(0.65e-6f, 1.881e-6f, 0.085e-6f);
187 planet.rayleigh_density_decay = -8e3f;
188 planet.mie_density_decay = -1.2e3f;
189 planet.ozone_band_center = 25e3f;
190 planet.ozone_band_extent = 15e3f;
191 planet.atmosphere_thickness = 1e5f;
192 planet.planet_radius = 6.36e6f;
197 Sky *Sky::Template::create(const map<string, Renderable *> &renderables) const
199 Renderable *content = get_item(renderables, content_name);
201 throw invalid_operation("Sky::Template::create");
202 return new Sky(*content, *sun);
206 DataFile::Loader::ActionMap Sky::Template::Loader::shared_actions;
208 Sky::Template::Loader::Loader(Template &t, Collection &c):
209 DerivedObjectLoader<Template, Effect::Template::Loader>(t, c)
211 set_actions(shared_actions);
214 void Sky::Template::Loader::init_actions()
216 Effect::Template::Loader::init_actions();
217 add("sun", &Template::sun);