]> git.tdb.fi Git - libs/gl.git/blob - source/effects/shadowmap.cpp
Make clearing the render target a responsibility of Sequence
[libs/gl.git] / source / effects / shadowmap.cpp
1 #include <cmath>
2 #include <cstdlib>
3 #include "camera.h"
4 #include "light.h"
5 #include "renderer.h"
6 #include "resources.h"
7 #include "scene.h"
8 #include "shadowmap.h"
9
10 using namespace std;
11
12 namespace Msp {
13 namespace GL {
14
15 ShadowMap::ShadowMap(unsigned s, Renderable &r, const Light &l, Renderable &c):
16         Effect(r),
17         size(s),
18         light(l),
19         shadow_caster(c),
20         sampler(Resources::get_global().get<Sampler>("_linear_clamp_shadow.samp")),
21         radius(1),
22         depth_bias(4),
23         rendered(false)
24 {
25         depth_buf.storage(DEPTH_COMPONENT32F, size, size, 1);
26         fbo.set_format((DEPTH_ATTACHMENT,DEPTH_COMPONENT32F));
27         fbo.attach(DEPTH_ATTACHMENT, depth_buf, 0);
28
29         depth_test.enabled = true;
30         depth_test.compare = LEQUAL;
31
32         set_darkness(1.0f);
33         shdata.uniform("shd_world_matrix", Matrix());
34 }
35
36 void ShadowMap::set_target(const Vector3 &t, float r)
37 {
38         target = t;
39         radius = r;
40 }
41
42 void ShadowMap::set_darkness(float d)
43 {
44         if(d<0.0f || d>1.0f)
45                 throw invalid_argument("ShadowMap::set_darkness");
46
47         shdata.uniform("shadow_darkness", d);
48 }
49
50 void ShadowMap::set_depth_bias(float b)
51 {
52         if(b<0.0f)
53                 throw invalid_argument("ShadowMap::set_depth_bias");
54
55         depth_bias = b;
56 }
57
58 void ShadowMap::setup_frame(Renderer &renderer)
59 {
60         if(rendered)
61                 return;
62
63         rendered = true;
64         renderable.setup_frame(renderer);
65         shadow_caster.setup_frame(renderer);
66
67         shadow_camera.set_object_matrix(*light.get_matrix());
68         shadow_camera.set_position(target);
69         // TODO support point and spot lights with a frustum projection.
70         // Omnidirectional lights also need a cube shadow map.
71         shadow_camera.set_orthographic(radius*2, radius*2);
72         shadow_camera.set_depth_clip(-radius, radius);
73
74         shadow_matrix = shadow_camera.get_object_matrix();
75         shadow_matrix.scale(radius*2, radius*2, -radius*2);
76         shadow_matrix.translate(-0.5, -0.5, depth_bias/size-0.5);
77         shadow_matrix.invert();
78
79         shdata.uniform("shd_world_matrix", shadow_matrix);
80
81         Renderer::Push push(renderer);
82         renderer.set_framebuffer(&fbo);
83         renderer.set_camera(shadow_camera);
84         renderer.set_depth_test(&depth_test);
85
86         renderer.render(shadow_caster);
87 }
88
89 void ShadowMap::finish_frame()
90 {
91         if(rendered)
92         {
93                 rendered = false;
94                 renderable.finish_frame();
95         }
96 }
97
98 void ShadowMap::render(Renderer &renderer, Tag tag) const
99 {
100         if(!enabled_passes.count(tag))
101                 return renderer.render(renderable, tag);
102
103         Renderer::Push _push_rend(renderer);
104
105         renderer.set_texture("shadow_map", &depth_buf, &sampler);
106         renderer.add_shader_data(shdata);
107         renderer.render(renderable, tag);
108 }
109
110 void ShadowMap::set_debug_name(const string &name)
111 {
112 #ifdef DEBUG
113         fbo.set_debug_name(name+" [FBO]");
114         shadow_camera.set_debug_name(name+".camera");
115         depth_buf.set_debug_name(name+"/depth.tex2d");
116         shdata.set_debug_name(name+" [UBO]");
117 #else
118         (void)name;
119 #endif
120 }
121
122 } // namespace GL
123 } // namespace Msp