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