]> git.tdb.fi Git - libs/gl.git/blob - source/effects/shadowmap.cpp
f688a6e3a7d4e858c23cf5126908475545bbe712
[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.clear(DEPTH_BUFFER_BIT);
84         renderer.set_camera(shadow_camera);
85         renderer.set_depth_test(&depth_test);
86
87         renderer.render(shadow_caster);
88 }
89
90 void ShadowMap::finish_frame()
91 {
92         if(rendered)
93         {
94                 rendered = false;
95                 renderable.finish_frame();
96         }
97 }
98
99 void ShadowMap::render(Renderer &renderer, Tag tag) const
100 {
101         if(!enabled_passes.count(tag))
102                 return renderer.render(renderable, tag);
103
104         Renderer::Push _push_rend(renderer);
105
106         renderer.set_texture("shadow_map", &depth_buf, &sampler);
107         renderer.add_shader_data(shdata);
108         renderer.render(renderable, tag);
109 }
110
111 void ShadowMap::set_debug_name(const std::string &name)
112 {
113 #ifdef DEBUG
114         fbo.set_debug_name(name+" [FBO]");
115         shadow_camera.set_debug_name(name+".camera");
116         depth_buf.set_debug_name(name+"/depth.tex2d");
117         shdata.set_debug_name(name+" [UBO]");
118 #else
119         (void)name;
120 #endif
121 }
122
123 } // namespace GL
124 } // namespace Msp