PeriDyno 1.0.0
Loading...
Searching...
No Matches
ShadowMap.cpp
Go to the documentation of this file.
1#include "ShadowMap.h"
2#include "GLVisualModule.h"
3
4#include <SceneGraph.h>
5#include <Action.h>
6
7#include <glad/glad.h>
8#include <glm/gtc/matrix_transform.hpp>
9#include <glm/gtc/type_ptr.hpp>
10
11#include <array>
12
13#include "screen.vert.h"
14#include "blur.frag.h"
15
16namespace dyno
17{
18
20 {
21 this->setSize(size);
22 }
23
25 {
26
27 }
28
30 {
31 const glm::vec4 border = glm::vec4(1);
32
33 mShadowTex.format = GL_RG;
34 mShadowTex.internalFormat = GL_RG32F;
35 mShadowTex.maxFilter = GL_LINEAR;
36 mShadowTex.minFilter = GL_LINEAR;
37 mShadowTex.create();
38
39 // setup border
40 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
41 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
42 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, glm::value_ptr(border));
43
44 mShadowBlur.format = GL_RG;
45 mShadowBlur.internalFormat = GL_RG32F;
46 mShadowBlur.maxFilter = GL_LINEAR;
47 mShadowBlur.minFilter = GL_LINEAR;
48 mShadowBlur.create();
49
50 // setup border
51 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
52 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
53 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, glm::value_ptr(border));
54
55 mShadowDepth.internalFormat = GL_DEPTH_COMPONENT32;
56 mShadowDepth.format = GL_DEPTH_COMPONENT;
57 mShadowDepth.create();
58
59 mShadowTex.resize(size, size);
60 mShadowBlur.resize(size, size);
61 mShadowDepth.resize(size, size);
62 sizeUpdated = false;
63
64 mFramebuffer.create();
65
66 mFramebuffer.bind();
67 mFramebuffer.setTexture(GL_DEPTH_ATTACHMENT, &mShadowDepth);
68 mFramebuffer.checkStatus();
69
70 mFramebuffer.unbind();
71
72 // uniform buffers
73 mShadowUniform.create(GL_UNIFORM_BUFFER, GL_DYNAMIC_DRAW);
74
75 // for blur depth textures
78 SCREEN_VERT, sizeof(SCREEN_VERT),
79 BLUR_FRAG, sizeof(BLUR_FRAG));
80 }
81
83 {
84 mFramebuffer.release();
85 mShadowTex.release();
86 mShadowDepth.release();
87 mShadowBlur.release();
88
89 mShadowUniform.release();
90
91 mQuad->release();
92 delete mQuad;
93
94 mBlurProgram->release();
95 delete mBlurProgram;
96 }
97
98
99 // extract frustum corners from camera projection matrix
100 std::array<glm::vec4, 8> getFrustumCorners(const glm::mat4& proj)
101 {
102 const glm::vec4 p[8] = {
103 glm::vec4(-1.0f, -1.0f, -1.0f, 1.0f),
104 glm::vec4(-1.0f, -1.0f, 1.0f, 1.0f),
105
106 glm::vec4(-1.0f, 1.0f, -1.0f, 1.0f),
107 glm::vec4(-1.0f, 1.0f, 1.0f, 1.0f),
108
109 glm::vec4(1.0f, -1.0f, -1.0f, 1.0f),
110 glm::vec4(1.0f, -1.0f, 1.0f, 1.0f),
111
112 glm::vec4(1.0f, 1.0f, -1.0f, 1.0f),
113 glm::vec4(1.0f, 1.0f, 1.0f, 1.0f),
114 };
115
116 const glm::mat4 invProj = glm::inverse(proj);
117
118 std::array<glm::vec4, 8> corners;
119 for (int i = 0; i < 8; i++)
120 {
121 // camera space corners
122 corners[i] = invProj * p[i];
123 corners[i] /= corners[i].w;
124 }
125
126 return corners;
127 }
128
129 glm::mat4 getLightViewMatrix(glm::vec3 lightDir)
130 {
131 glm::vec3 lightUp = glm::vec3(0, 1, 0);
132 if (glm::length(glm::cross(lightUp, lightDir)) == 0.f)
133 {
134 lightUp = glm::vec3(0, 0, 1);
135 }
136 glm::mat4 lightView = glm::lookAt(glm::vec3(0), -lightDir, lightUp);
137 return lightView;
138 }
139
140 glm::mat4 getLightProjMatrix(glm::mat4 lightView,
141 Vec3f lowerBound,
142 Vec3f upperBound,
143 glm::mat4 cameraView,
144 glm::mat4 cameraProj)
145 {
146 glm::vec4 p[8] = {
147 lightView * glm::vec4{lowerBound[0], lowerBound[1], lowerBound[2], 1},
148 lightView * glm::vec4{lowerBound[0], lowerBound[1], upperBound[2], 1},
149 lightView * glm::vec4{lowerBound[0], upperBound[1], lowerBound[2], 1},
150 lightView * glm::vec4{lowerBound[0], upperBound[1], upperBound[2], 1},
151 lightView * glm::vec4{upperBound[0], lowerBound[1], lowerBound[2], 1},
152 lightView * glm::vec4{upperBound[0], lowerBound[1], upperBound[2], 1},
153 lightView * glm::vec4{upperBound[0], upperBound[1], lowerBound[2], 1},
154 lightView * glm::vec4{upperBound[0], upperBound[1], upperBound[2], 1},
155 };
156
157 glm::vec4 bmin = p[0];
158 glm::vec4 bmax = p[0];
159 for (int i = 1; i < 8; i++)
160 {
161 bmin = glm::min(bmin, p[i]);
162 bmax = glm::max(bmax, p[i]);
163 }
164
165 // frustrum clamp
166 std::array<glm::vec4, 8> corners = getFrustumCorners(cameraProj);
167 glm::mat4 tm = lightView * glm::inverse(cameraView);
168
169 glm::vec4 fbmin = tm * corners[0];
170 glm::vec4 fbmax = tm * corners[0];
171 for (int i = 1; i < 8; i++)
172 {
173 glm::vec4 c = tm * corners[i];
174 fbmin = glm::min(fbmin, c);
175 fbmax = glm::max(fbmax, c);
176 }
177
178 bmin.x = glm::max(bmin.x, fbmin.x);
179 bmin.y = glm::max(bmin.y, fbmin.y);
180 bmax.x = glm::min(bmax.x, fbmax.x);
181 bmax.y = glm::min(bmax.y, fbmax.y);
182
183 float cx = (bmin.x + bmax.x) * 0.5;
184 float cy = (bmin.y + bmax.y) * 0.5;
185 float d = glm::max(bmax.y - bmin.y, bmax.x - bmin.x) * 0.5f;
186
187 glm::mat4 lightProj = glm::ortho(cx - d, cx + d, cy - d, cy + d, -bmax.z, -bmin.z);
188 return lightProj;
189 }
190
192 {
193 if (sizeUpdated)
194 {
195 mShadowTex.resize(size, size);
196 mShadowBlur.resize(size, size);
197 mShadowDepth.resize(size, size);
198 sizeUpdated = false;
199 }
200
201 // initialization
202 mFramebuffer.bind();
203 mFramebuffer.setTexture(GL_COLOR_ATTACHMENT0, &mShadowTex);
204 mFramebuffer.clearDepth(1.0);
205 mFramebuffer.clearColor(1.0, 1.0, 1.0, 1.0);
206
207 if (rparams.light.mainLightShadow > 0.f &&
208 scene != nullptr && !scene->isEmpty())
209 {
210 glViewport(0, 0, size, size);
211
212 glm::mat4 lightView = getLightViewMatrix(rparams.light.mainLightDirection);
213 glm::mat4 lightProj = getLightProjMatrix(lightView,
214 scene->getLowerBound(),
215 scene->getUpperBound(),
216 rparams.transforms.view,
217 rparams.transforms.proj);
218
219 // draw objects to shadow texture
220 class DrawShadow : public Action
221 {
222 public:
223 void process(Node* node) override
224 {
225 if (!node->isVisible()) return;
226
227 for (auto iter : node->graphicsPipeline()->activeModules()) {
228 auto m = dynamic_cast<GLVisualModule*>(iter.get());
229 if (m && m->isVisible()) {
230 m->draw(params);
231 }
232 }
233 }
234 RenderParams params;
235 } action;
236
237 action.params.transforms.model = glm::mat4(1);
238 action.params.transforms.view = lightView;
239 action.params.transforms.proj = lightProj;
240 action.params.mode = GLRenderMode::SHADOW;
241 action.params.width = this->size;
242 action.params.height = this->size;
243
244 scene->traverseForward(&action);
245
246 // blur shadow map
247 glDisable(GL_DEPTH_TEST);
248 mBlurProgram->use();
249 for (int i = 0; i < blurIters; i++)
250 {
251 mBlurProgram->setVec2("uScale", { 1.f / size, 0.f / size });
252 mShadowTex.bind(GL_TEXTURE5);
253 mFramebuffer.setTexture(GL_COLOR_ATTACHMENT0, &mShadowBlur);
254 mQuad->draw();
255
256 mBlurProgram->setVec2("uScale", { 0.f / size, 1.f / size });
257 mShadowBlur.bind(GL_TEXTURE5);
258 mFramebuffer.setTexture(GL_COLOR_ATTACHMENT0, &mShadowTex);
259 mQuad->draw();
260 }
261 glEnable(GL_DEPTH_TEST);
262
263 // update shadow map uniform
264 struct {
265 glm::mat4 transform;
266 float minValue;
267 } shadow;
268
269 shadow.transform = lightProj * lightView * glm::inverse(rparams.transforms.view);
270 shadow.minValue = minValue;
271 mShadowUniform.load(&shadow, sizeof(shadow));
272 }
273
274 }
275
276 void ShadowMap::bind(int shadowUniformLoc, int shadowTexSlot)
277 {
278 // bind the shadow texture to the slot
279 mShadowUniform.bindBufferBase(shadowUniformLoc);
280
281 if (shadowTexSlot >= GL_TEXTURE0)
282 mShadowTex.bind(shadowTexSlot);
283 else
284 mShadowTex.bind(GL_TEXTURE0 + shadowTexSlot);
285
286 }
287
289 {
290 return this->size;
291 }
292
294 {
295 if (this->size == size)
296 return;
297
298 this->size = size;
299 this->sizeUpdated = true;
300 }
301
303 {
304 return this->blurIters;
305 }
306
308 {
309 this->blurIters = iter;
310 }
311
312}
313
static Mesh * ScreenQuad()
Definition Mesh.cpp:134
std::shared_ptr< GraphicsPipeline > graphicsPipeline()
Definition Node.cpp:320
virtual bool isVisible()
Check the visibility of context.
Definition Node.cpp:83
static Program * createProgramSPIRV(const void *vs, size_t vs_len, const void *fs, size_t fs_len, const void *gs=0, size_t gs_len=0)
Definition Shader.cpp:202
void setNumBlurIterations(int iter)
void update(dyno::SceneGraph *scene, const dyno::RenderParams &rparams)
Framebuffer mFramebuffer
Definition ShadowMap.h:55
Texture2D mShadowDepth
Definition ShadowMap.h:57
void bind(int shadowUniformLoc=3, int shadowTexSlot=5)
int getNumBlurIterations() const
int getSize() const
ShadowMap(int size=1024)
Definition ShadowMap.cpp:19
Texture2D mShadowTex
Definition ShadowMap.h:56
Texture2D mShadowBlur
Definition ShadowMap.h:58
Buffer mShadowUniform
Definition ShadowMap.h:64
void setSize(int size)
Program * mBlurProgram
Definition ShadowMap.h:60
This is an implementation of AdditiveCCD based on peridyno.
Definition Array.h:25
glm::mat4 getLightViewMatrix(glm::vec3 lightDir)
int scene
Definition GltfFunc.h:20
std::array< glm::vec4, 8 > getFrustumCorners(const glm::mat4 &proj)
glm::mat4 getLightProjMatrix(glm::mat4 lightView, Vec3f lowerBound, Vec3f upperBound, glm::mat4 cameraView, glm::mat4 cameraProj)
Vector< float, 3 > Vec3f
Definition Vector3D.h:93
static const int SHADOW
struct dyno::RenderParams::Light light
struct dyno::RenderParams::Transform transforms