]> git.tdb.fi Git - libs/gl.git/blob - source/shadowmap.cpp
Add multiplication operators between Matrix and float
[libs/gl.git] / source / shadowmap.cpp
1 #include <cmath>
2 #include <cstdlib>
3 #include "camera.h"
4 #include "light.h"
5 #include "renderer.h"
6 #include "scene.h"
7 #include "shadowmap.h"
8 #include "tests.h"
9
10 using namespace std;
11
12 namespace Msp {
13 namespace GL {
14
15 ShadowMap::ShadowMap(unsigned s, Renderable &r, const Light &l):
16         Effect(r),
17         size(s),
18         light(l),
19         radius(1),
20         depth_bias(4),
21         rendered(false)
22 {
23         depth_buf.set_min_filter(LINEAR);
24         depth_buf.set_compare_enabled(true);
25         depth_buf.set_compare_func(LEQUAL);
26         depth_buf.set_wrap(CLAMP_TO_EDGE);
27         depth_buf.storage(DEPTH_COMPONENT, size, size, 1);
28         fbo.attach(DEPTH_ATTACHMENT, depth_buf, 0);
29         fbo.require_complete();
30
31         set_darkness(0.7);
32 }
33
34 void ShadowMap::set_target(const Vector3 &t, float r)
35 {
36         target = t;
37         radius = r;
38 }
39
40 void ShadowMap::set_darkness(float d)
41 {
42         if(d<0.0f || d>1.0f)
43                 throw invalid_argument("ShadowMap::set_darkness");
44
45         shdata.uniform("shadow_darkness", d);
46 }
47
48 void ShadowMap::set_depth_bias(float b)
49 {
50         if(b<0.0f)
51                 throw invalid_argument("ShadowMap::set_depth_bias");
52
53         depth_bias = b;
54 }
55
56 void ShadowMap::setup_frame(Renderer &renderer)
57 {
58         if(rendered)
59                 return;
60
61         rendered = true;
62         renderable.setup_frame(renderer);
63
64         Camera camera;
65         camera.set_object_matrix(*light.get_matrix());
66         camera.set_position(target);
67         // TODO support point and spot lights with a frustum projection.
68         // Omnidirectional lights also need a cube shadow map.
69         camera.set_orthographic(radius*2, radius*2);
70         camera.set_depth_clip(-radius, radius);
71
72         shadow_matrix = camera.get_object_matrix();
73         shadow_matrix.scale(radius*2, radius*2, -radius*2);
74         shadow_matrix.translate(-0.5, -0.5, depth_bias/size-0.5);
75         shadow_matrix.invert();
76
77         BindRestore bind_fbo(fbo);
78         Bind bind_depth(DepthTest::lequal());
79         fbo.clear(DEPTH_BUFFER_BIT);
80
81         Renderer::Push push(renderer);
82         renderer.set_camera(camera);
83
84         renderer.render(renderable, "shadow");
85 }
86
87 void ShadowMap::finish_frame()
88 {
89         renderable.finish_frame();
90         rendered = false;
91 }
92
93 void ShadowMap::render(Renderer &renderer, const Tag &tag) const
94 {
95         if(!enabled_passes.count(tag))
96                 return renderer.render(renderable, tag);
97
98         Renderer::Push _push_rend(renderer);
99
100         unsigned unit = renderer.allocate_effect_texunit();
101         int iunit = unit;
102         shdata.uniform("shadow_map", iunit);
103
104         Bind _bind_depth(depth_buf, unit);
105
106         if(const Camera *camera = renderer.get_camera())
107                 /* Multiply by camera's object matrix to form a matrix that transforms
108                 from eye space to shadow space. */
109                 shdata.uniform("shd_eye_matrix", shadow_matrix*camera->get_object_matrix());
110         else
111                 shdata.uniform("shd_eye_matrix", shadow_matrix);
112
113         renderer.add_shader_data(shdata);
114         renderer.render(renderable, tag);
115 }
116
117 } // namespace GL
118 } // namespace Msp