]> git.tdb.fi Git - libs/gl.git/blob - source/shadowmap.cpp
Header fixes
[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);
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         const Vector4 &lpos = light.get_position();
66         /* XXX Not really proper way to support positional lights, but good
67         enough when the light source is far away */
68         camera.set_look_direction(lpos.w*target-lpos.slice<3>(0));
69
70         camera.set_up_direction((abs(camera.get_look_direction().z)<0.99) ? Vector3(0, 0, 1) : Vector3(0, 1, 0));
71         camera.set_position(target);
72         camera.set_orthographic(radius*2, radius*2);
73         camera.set_depth_clip(-radius, radius);
74
75         shadow_matrix = camera.get_object_matrix();
76         shadow_matrix.scale(radius*2, radius*2, -radius*2);
77         shadow_matrix.translate(-0.5, -0.5, depth_bias/size-0.5);
78         shadow_matrix.invert();
79
80         BindRestore bind_fbo(fbo);
81         Bind bind_depth(DepthTest::lequal());
82         fbo.clear(DEPTH_BUFFER_BIT);
83
84         Renderer::Push push(renderer);
85         renderer.set_camera(camera);
86
87         renderer.render(renderable, "shadow");
88 }
89
90 void ShadowMap::finish_frame()
91 {
92         renderable.finish_frame();
93         rendered = false;
94 }
95
96 void ShadowMap::render(Renderer &renderer, const Tag &tag) const
97 {
98         if(!enabled_passes.count(tag))
99                 return renderer.render(renderable, tag);
100
101         Renderer::Push _push_rend(renderer);
102
103         unsigned unit = renderer.allocate_effect_texunit();
104         int iunit = unit;
105         shdata.uniform("shadow", iunit);
106
107         Bind _bind_depth(depth_buf, unit);
108
109         if(const Camera *camera = renderer.get_camera())
110                 /* Multiply by camera's object matrix to form a matrix that transforms
111                 from eye space to shadow space. */
112                 shdata.uniform("shd_eye_matrix", shadow_matrix*camera->get_object_matrix());
113         else
114                 shdata.uniform("shd_eye_matrix", shadow_matrix);
115
116         renderer.add_shader_data(shdata);
117         renderer.render(renderable, tag);
118 }
119
120 } // namespace GL
121 } // namespace Msp