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