]> git.tdb.fi Git - libs/gl.git/blob - source/effects/sky.cpp
Add an effect for rendering a procedurally generated sky
[libs/gl.git] / source / effects / sky.cpp
1 #include "light.h"
2 #include "mesh.h"
3 #include "renderer.h"
4 #include "resources.h"
5 #include "sky.h"
6
7 using namespace std;
8
9 namespace Msp {
10 namespace GL {
11
12 Sky::Sky(Resources &resources, Renderable &r, const Light &s):
13         Effect(r),
14         sun(s),
15         transmittance_shprog(resources.get<Program>("_sky_transmittance.glsl.shader")),
16         transmittance_lookup_dirty(true),
17         distant_shprog(resources.get<Program>("_sky_distant.glsl.shader")),
18         fullscreen_mesh(resources.get<Mesh>("_fullscreen_quad.mesh")),
19         backdrop_shprog(resources.get<Program>("_sky_backdrop.glsl.shader")),
20         sampler(resources.get<Sampler>("_linear_clamp.samp")),
21         wrap_sampler(resources.get<Sampler>("_linear_clamp_v.samp")),
22         rendered(false)
23 {
24         transmittance_lookup.storage(RGB16F, 128, 64, 1);
25         transmittance_fbo.attach(COLOR_ATTACHMENT0, transmittance_lookup);
26
27         distant.storage(RGB16F, 256, 128, 1);
28         distant_fbo.attach(COLOR_ATTACHMENT0, distant);
29
30         shdata.uniform("n_steps", 50);
31
32         set_planet(Planet::earth());
33         set_view_height(5.0f);
34 }
35
36 void Sky::set_planet(const Planet &planet)
37 {
38         shdata.uniform("events.rayleigh_scatter", planet.rayleigh_scatter.r, planet.rayleigh_scatter.g, planet.rayleigh_scatter.b);
39         shdata.uniform("events.mie_scatter", planet.mie_scatter.r, planet.mie_scatter.g, planet.mie_scatter.b);
40         shdata.uniform("events.mie_absorb", planet.mie_absorb.r, planet.mie_absorb.g, planet.mie_absorb.b);
41         shdata.uniform("events.ozone_absorb", planet.ozone_absorb.r, planet.ozone_absorb.g, planet.ozone_absorb.b);
42         shdata.uniform("rayleigh_density_decay", planet.rayleigh_density_decay);
43         shdata.uniform("mie_density_decay", planet.mie_density_decay);
44         shdata.uniform("ozone_band_center", planet.ozone_band_center);
45         shdata.uniform("ozone_band_extent", planet.ozone_band_extent);
46         shdata.uniform("atmosphere_thickness", planet.atmosphere_thickness);
47         shdata.uniform("planet_radius", planet.planet_radius);
48         shdata.uniform("ground_albedo", planet.ground_albedo.r, planet.ground_albedo.g, planet.ground_albedo.b);
49 }
50
51 void Sky::set_view_height(float h)
52 {
53         shdata.uniform("view_height", h);
54 }
55
56 void Sky::setup_frame(Renderer &renderer)
57 {
58         if(rendered)
59                 return;
60
61         rendered = true;
62
63         shdata.uniform("light_color", sun.get_color());
64         shdata.uniform("light_dir", sun.get_position().slice<3>(0));
65
66         Renderer::Push push(renderer);
67
68         if(transmittance_lookup_dirty)
69         {
70                 transmittance_lookup_dirty = false;
71                 Bind bind_fbo(transmittance_fbo);
72                 renderer.set_shader_program(&transmittance_shprog, &shdata);
73                 fullscreen_mesh.draw(renderer);
74         }
75
76         Bind bind_fbo(distant_fbo);
77         renderer.set_shader_program(&distant_shprog, &shdata);
78         renderer.set_texture("transmittance_lookup", &transmittance_lookup, &sampler);
79         fullscreen_mesh.draw(renderer);
80
81         renderable.setup_frame(renderer);
82 }
83
84 void Sky::finish_frame()
85 {
86         if(rendered)
87         {
88                 rendered = false;
89                 renderable.finish_frame();
90         }
91 }
92
93 void Sky::render(Renderer &renderer, Tag tag) const
94 {
95         renderable.render(renderer, tag);
96
97         Renderer::Push push(renderer);
98
99         renderer.set_shader_program(&backdrop_shprog, &shdata);
100         renderer.set_texture("distant", &distant, &wrap_sampler);
101         fullscreen_mesh.draw(renderer);
102 }
103
104
105 Sky::Planet::Planet():
106         rayleigh_scatter(0.0f),
107         mie_scatter(0.0f),
108         mie_absorb(0.0f),
109         ozone_absorb(0.0f),
110         rayleigh_density_decay(1e3f),
111         mie_density_decay(1e3f),
112         ozone_band_center(1e4f),
113         ozone_band_extent(1e2f),
114         atmosphere_thickness(2e4f),
115         planet_radius(1e6f)
116 { }
117
118 Sky::Planet Sky::Planet::earth()
119 {
120         Planet planet;
121         planet.rayleigh_scatter = Color(5.802e-6f, 13.558e-6f, 33.1e-6f);
122         planet.mie_scatter = Color(3.996e-6f, 3.996e-6f, 3.996e-6f);
123         planet.mie_absorb = Color(4.4e-6f, 4.4e-6f, 4.4e-6f);
124         planet.ozone_absorb = Color(0.65e-6f, 1.881e-6f, 0.085e-6f);
125         planet.rayleigh_density_decay = -8e3f;
126         planet.mie_density_decay = -1.2e3f;
127         planet.ozone_band_center = 25e3f;
128         planet.ozone_band_extent = 15e3f;
129         planet.atmosphere_thickness = 1e5f;
130         planet.planet_radius = 6.36e6f;
131         return planet;
132 }
133
134 } // namespace GL
135 } // namespace Msp