1 /*
2 Copyright (c) 2017-2018 Timur Gafarov
3 
4 Boost Software License - Version 1.0 - August 17th, 2003
5 Permission is hereby granted, free of charge, to any person or organization
6 obtaining a copy of the software and accompanying documentation covered by
7 this license (the "Software") to use, reproduce, display, distribute,
8 execute, and transmit the Software, and to prepare derivative works of the
9 Software, and to permit third-parties to whom the Software is furnished to
10 do so, all subject to the following:
11 
12 The copyright notices in the Software and this entire statement, including
13 the above license grant, this restriction and the following disclaimer,
14 must be included in all copies of the Software, in whole or in part, and
15 all derivative works of the Software, unless such copies or derivative
16 works are solely in the form of machine-executable object code generated by
17 a source language processor.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
22 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
23 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
24 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 DEALINGS IN THE SOFTWARE.
26 */
27 
28 module dagon.graphics.shadow;
29 
30 import std.stdio;
31 import std.math;
32 import std.conv;
33 
34 import dlib.core.memory;
35 import dlib.math.vector;
36 import dlib.math.matrix;
37 import dlib.math.transformation;
38 import dlib.math.quaternion;
39 import dlib.math.interpolation;
40 import dlib.image.color;
41 import dlib.image.unmanaged;
42 import dlib.image.render.shapes;
43 
44 import dagon.core.libs;
45 import dagon.core.interfaces;
46 import dagon.core.ownership;
47 import dagon.logics.entity;
48 import dagon.logics.behaviour;
49 import dagon.graphics.shapes;
50 import dagon.graphics.texture;
51 import dagon.graphics.view;
52 import dagon.graphics.rc;
53 import dagon.graphics.environment;
54 import dagon.graphics.material;
55 import dagon.graphics.shaders.shadowpass;
56 import dagon.graphics.light;
57 import dagon.resource.scene;
58 
59 class ShadowArea: Owner
60 {
61     Matrix4x4f biasMatrix;
62     Matrix4x4f projectionMatrix;
63     Matrix4x4f viewMatrix;
64     Matrix4x4f invViewMatrix;
65     Matrix4x4f shadowMatrix;
66     float width;
67     float height;
68     float depth;
69     float start;
70     float end;
71     float scale = 1.0f;
72     Vector3f position;
73 
74     this(float w, float h, float start, float end, Owner o)
75     {
76         super(o);
77         this.width = w;
78         this.height = h;
79         this.start = start;
80         this.end = end;
81 
82         depth = abs(start) + abs(end);
83 
84         this.position = Vector3f(0, 0, 0);
85 
86         this.biasMatrix = matrixf(
87             0.5f, 0.0f, 0.0f, 0.5f,
88             0.0f, 0.5f, 0.0f, 0.5f,
89             0.0f, 0.0f, 0.5f, 0.5f,
90             0.0f, 0.0f, 0.0f, 1.0f,
91         );
92 
93         float hw = w * 0.5f;
94         float hh = h * 0.5f;
95         this.projectionMatrix = orthoMatrix(-hw, hw, -hh, hh, start, end);
96 
97         this.shadowMatrix = Matrix4x4f.identity;
98         this.viewMatrix = Matrix4x4f.identity;
99         this.invViewMatrix = Matrix4x4f.identity;
100     }
101 
102     void update(Quaternionf lightRotation, RenderingContext* rc, double dt)
103     {
104         auto t = translationMatrix(position);
105         auto r = lightRotation.toMatrix4x4;
106         invViewMatrix = t * r;
107         viewMatrix = invViewMatrix.inverse;
108         shadowMatrix = scaleMatrix(Vector3f(scale, scale, 1.0f)) * biasMatrix * projectionMatrix * viewMatrix * rc.invViewMatrix;
109     }
110 }
111 
112 abstract class ShadowMap: Owner
113 {
114     uint size;
115     LightSource light;
116 
117     this(Owner o)
118     {
119         super(o);
120     }
121 
122     bool enabled() @property
123     {
124         return light.shadowEnabled;
125     }
126 
127     Vector3f position();
128     Vector3f position(Vector3f pos);
129 
130     void update(Vector3f cameraPosition, Vector3f cameraDirection, RenderingContext* rc, double dt);
131     void render(Scene scene, RenderingContext* rc);
132 }
133 
134 class CascadedShadowMap: ShadowMap
135 {
136     ShadowArea area1;
137     ShadowArea area2;
138     ShadowArea area3;
139 
140     GLuint depthTexture;
141     GLuint framebuffer1;
142     GLuint framebuffer2;
143     GLuint framebuffer3;
144 
145     ShadowPassShader ss;
146 
147     float projSize1 = 5.0f;
148     float projSize2 = 15.0f;
149     float projSize3 = 400.0f;
150 
151     float zStart = -300.0f;
152     float zEnd = 300.0f;
153 
154     float eyeSpaceNormalShift = 0.008f;
155 
156     this(LightSource light, uint size, float projSizeNear, float projSizeMid, float projSizeFar, float zStart, float zEnd, Owner o)
157     {
158         super(o);
159         this.light = light;
160 
161         this.size = size;
162 
163         projSize1 = projSizeNear;
164         projSize2 = projSizeMid;
165         projSize3 = projSizeFar;
166 
167         this.zStart = zStart;
168         this.zEnd = zEnd;
169 
170         this.area1 = New!ShadowArea(projSize1, projSize1, zStart, zEnd, this);
171         this.area2 = New!ShadowArea(projSize2, projSize2, zStart, zEnd, this);
172         this.area3 = New!ShadowArea(projSize3, projSize3, zStart, zEnd, this);
173 
174         this.ss = New!ShadowPassShader(this);
175 
176         glGenTextures(1, &depthTexture);
177         glActiveTexture(GL_TEXTURE0);
178         glBindTexture(GL_TEXTURE_2D_ARRAY, depthTexture);
179         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
180         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
181         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
182         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
183 
184         Color4f borderColor = Color4f(1, 1, 1, 1);
185 
186         glTexParameterfv(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BORDER_COLOR, borderColor.arrayof.ptr);
187         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
188 	    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
189 
190         glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT24, size, size, 3, 0, GL_DEPTH_COMPONENT, GL_FLOAT, null);
191 
192         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BASE_LEVEL, 0);
193         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, 0);
194 
195         glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
196 
197         glGenFramebuffers(1, &framebuffer1);
198 	    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer1);
199         glDrawBuffer(GL_NONE);
200 	    glReadBuffer(GL_NONE);
201         glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexture, 0, 0);
202         glBindFramebuffer(GL_FRAMEBUFFER, 0);
203 
204         glGenFramebuffers(1, &framebuffer2);
205 	    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer2);
206         glDrawBuffer(GL_NONE);
207 	    glReadBuffer(GL_NONE);
208         glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexture, 0, 1);
209         glBindFramebuffer(GL_FRAMEBUFFER, 0);
210 
211         glGenFramebuffers(1, &framebuffer3);
212 	    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer3);
213         glDrawBuffer(GL_NONE);
214 	    glReadBuffer(GL_NONE);
215         glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexture, 0, 2);
216         glBindFramebuffer(GL_FRAMEBUFFER, 0);
217     }
218 
219     override Vector3f position()
220     {
221         return area1.position;
222     }
223 
224     override Vector3f position(Vector3f pos)
225     {
226         area1.position = pos;
227         area2.position = pos;
228         area3.position = pos;
229         return pos;
230     }
231 
232     ~this()
233     {
234         glBindFramebuffer(GL_FRAMEBUFFER, 0);
235         glDeleteFramebuffers(1, &framebuffer1);
236         glDeleteFramebuffers(1, &framebuffer2);
237         glDeleteFramebuffers(1, &framebuffer3);
238 
239         if (glIsTexture(depthTexture))
240             glDeleteTextures(1, &depthTexture);
241     }
242 
243     override void update(Vector3f cameraPosition, Vector3f cameraDirection, RenderingContext* rc, double dt)
244     {
245         area1.position = cameraPosition + cameraDirection * (projSize1 * 0.5f - 1.0f);
246         area2.position = cameraPosition + cameraDirection * projSize2 * 0.5f;
247         area3.position = cameraPosition + cameraDirection * projSize3 * 0.5f;
248 
249         area1.update(light.rotation, rc, dt);
250         area2.update(light.rotation, rc, dt);
251         area3.update(light.rotation, rc, dt);
252     }
253 
254     override void render(Scene scene, RenderingContext* rc)
255     {
256         glBindFramebuffer(GL_FRAMEBUFFER, framebuffer1);
257 
258         glViewport(0, 0, size, size);
259         glScissor(0, 0, size, size);
260         glClear(GL_DEPTH_BUFFER_BIT);
261 
262         glEnable(GL_DEPTH_TEST);
263 
264         auto rcLocal = *rc;
265         rcLocal.projectionMatrix = area1.projectionMatrix;
266         rcLocal.viewMatrix = area1.viewMatrix;
267         rcLocal.invViewMatrix = area1.invViewMatrix;
268         rcLocal.normalMatrix = rcLocal.invViewMatrix.transposed;
269         rcLocal.viewRotationMatrix = matrix3x3to4x4(matrix4x4to3x3(rcLocal.viewMatrix));
270         rcLocal.invViewRotationMatrix = matrix3x3to4x4(matrix4x4to3x3(rcLocal.invViewMatrix));
271         rcLocal.shadowPass = true;
272 
273         glPolygonOffset(3.0, 0.0);
274         glDisable(GL_CULL_FACE);
275         glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
276 
277         ss.bindProgram();
278         rcLocal.overrideShader = ss;
279         rcLocal.rebindShaderProgram = false;
280         rcLocal.ignoreTransparentEntities = true;
281         rcLocal.ignoreOpaqueEntities = false;
282         foreach(e; scene.entities3Dflat)
283             if (e.castShadow)
284                 e.render(&rcLocal);
285         rcLocal.overrideShader = null;
286         rcLocal.rebindShaderProgram = true;
287         rcLocal.ignoreTransparentEntities = false;
288         rcLocal.ignoreOpaqueEntities = true;
289         foreach(e; scene.entities3Dflat)
290             if (e.castShadow)
291                 e.render(&rcLocal);
292         ss.unbindProgram();
293 
294         rcLocal.overrideShader = null;
295         rcLocal.rebindShaderProgram = true;
296         scene.particleSystem.render(&rcLocal);
297 
298         glBindFramebuffer(GL_FRAMEBUFFER, framebuffer2);
299 
300         glViewport(0, 0, size, size);
301         glScissor(0, 0, size, size);
302         glClear(GL_DEPTH_BUFFER_BIT);
303 
304         rcLocal.projectionMatrix = area2.projectionMatrix;
305         rcLocal.viewMatrix = area2.viewMatrix;
306         rcLocal.invViewMatrix = area2.invViewMatrix;
307         rcLocal.normalMatrix = rcLocal.invViewMatrix.transposed;
308         rcLocal.viewRotationMatrix = matrix3x3to4x4(matrix4x4to3x3(rcLocal.viewMatrix));
309         rcLocal.invViewRotationMatrix = matrix3x3to4x4(matrix4x4to3x3(rcLocal.invViewMatrix));
310 
311         ss.bindProgram();
312         rcLocal.overrideShader = ss;
313         rcLocal.rebindShaderProgram = false;
314         rcLocal.ignoreTransparentEntities = true;
315         rcLocal.ignoreOpaqueEntities = false;
316         foreach(e; scene.entities3Dflat)
317             if (e.castShadow)
318                 e.render(&rcLocal);
319         rcLocal.overrideShader = null;
320         rcLocal.rebindShaderProgram = true;
321         rcLocal.ignoreTransparentEntities = false;
322         rcLocal.ignoreOpaqueEntities = true;
323         foreach(e; scene.entities3Dflat)
324             if (e.castShadow)
325                 e.render(&rcLocal);
326         ss.unbindProgram();
327 
328         rcLocal.overrideShader = null;
329         rcLocal.rebindShaderProgram = true;
330         scene.particleSystem.render(&rcLocal);
331 
332         glBindFramebuffer(GL_FRAMEBUFFER, framebuffer3);
333 
334         glViewport(0, 0, size, size);
335         glScissor(0, 0, size, size);
336         glClear(GL_DEPTH_BUFFER_BIT);
337 
338         rcLocal.projectionMatrix = area3.projectionMatrix;
339         rcLocal.viewMatrix = area3.viewMatrix;
340         rcLocal.invViewMatrix = area3.invViewMatrix;
341         rcLocal.normalMatrix = rcLocal.invViewMatrix.transposed;
342         rcLocal.viewRotationMatrix = matrix3x3to4x4(matrix4x4to3x3(rcLocal.viewMatrix));
343         rcLocal.invViewRotationMatrix = matrix3x3to4x4(matrix4x4to3x3(rcLocal.invViewMatrix));
344 
345         ss.bindProgram();
346         rcLocal.overrideShader = ss;
347         rcLocal.rebindShaderProgram = false;
348         rcLocal.ignoreTransparentEntities = true;
349         rcLocal.ignoreOpaqueEntities = false;
350         foreach(e; scene.entities3Dflat)
351             if (e.castShadow)
352                 e.render(&rcLocal);
353         rcLocal.overrideShader = null;
354         rcLocal.rebindShaderProgram = true;
355         rcLocal.ignoreTransparentEntities = false;
356         rcLocal.ignoreOpaqueEntities = true;
357         foreach(e; scene.entities3Dflat)
358             if (e.castShadow)
359                 e.render(&rcLocal);
360         ss.unbindProgram();
361 
362         rcLocal.overrideShader = null;
363         rcLocal.rebindShaderProgram = true;
364         scene.particleSystem.render(&rcLocal);
365 
366         glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
367         glEnable(GL_CULL_FACE);
368         glPolygonOffset(0.0, 0.0);
369 
370         glBindFramebuffer(GL_FRAMEBUFFER, 0);
371     }
372 }