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.interpolation;
39 import dlib.image.color;
40 import dlib.image.unmanaged;
41 import dlib.image.render.shapes;
42 
43 import derelict.opengl;
44 
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.materials.generic;
56 import dagon.resource.scene;
57 
58 class ShadowArea: Owner
59 {
60     Environment environment;
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(Environment env, 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         this.environment = env;
82 
83         depth = abs(start) + abs(end);
84         
85         this.position = Vector3f(0, 0, 0);
86 
87         this.biasMatrix = matrixf(
88             0.5f, 0.0f, 0.0f, 0.5f,
89             0.0f, 0.5f, 0.0f, 0.5f,
90             0.0f, 0.0f, 0.5f, 0.5f,
91             0.0f, 0.0f, 0.0f, 1.0f,
92         );
93 
94         float hw = w * 0.5f;
95         float hh = h * 0.5f;
96         this.projectionMatrix = orthoMatrix(-hw, hw, -hh, hh, start, end);
97         
98         this.shadowMatrix = Matrix4x4f.identity;
99         this.viewMatrix = Matrix4x4f.identity;
100         this.invViewMatrix = Matrix4x4f.identity;
101     }
102 
103     void update(RenderingContext* rc, double dt)
104     {
105         auto t = translationMatrix(position);
106         auto r = environment.sunRotation.toMatrix4x4;
107         invViewMatrix = t * r;
108         viewMatrix = invViewMatrix.inverse;
109         shadowMatrix = scaleMatrix(Vector3f(scale, scale, 1.0f)) * biasMatrix * projectionMatrix * viewMatrix * rc.invViewMatrix; // view.invViewMatrix;
110     }
111 }
112 
113 class ShadowBackend: GLSLMaterialBackend
114 {
115     
116     string vsText = "
117         #version 330 core
118 
119         uniform mat4 modelViewMatrix;
120         uniform mat4 projectionMatrix;
121         
122         layout (location = 0) in vec3 va_Vertex;
123         
124         void main()
125         {
126             gl_Position = projectionMatrix * modelViewMatrix * vec4(va_Vertex, 1.0);
127         }
128     ";
129     
130     string fsText = "
131         #version 330 core
132 
133         out vec4 frag_color;
134         
135         void main()
136         {
137             frag_color = vec4(1.0, 1.0, 1.0, 1.0);
138         }
139     ";
140     
141     override string vertexShaderSrc() {return vsText;}
142     override string fragmentShaderSrc() {return fsText;}
143 
144     GLint modelViewMatrixLoc;
145     GLint projectionMatrixLoc;
146     
147     this(Owner o)
148     {
149         super(o);
150 
151         modelViewMatrixLoc = glGetUniformLocation(shaderProgram, "modelViewMatrix");
152         projectionMatrixLoc = glGetUniformLocation(shaderProgram, "projectionMatrix");
153     }
154     
155     override void bind(GenericMaterial mat, RenderingContext* rc)
156     {        
157         glDisable(GL_CULL_FACE);
158         
159         glUseProgram(shaderProgram);
160 
161         glUniformMatrix4fv(modelViewMatrixLoc, 1, GL_FALSE, rc.modelViewMatrix.arrayof.ptr);
162         glUniformMatrix4fv(projectionMatrixLoc, 1, GL_FALSE, rc.projectionMatrix.arrayof.ptr);
163     }
164     
165     override void unbind(GenericMaterial mat, RenderingContext* rc)
166     {        
167         glUseProgram(0);
168     }
169 }
170 
171 class CascadedShadowMap: Owner
172 {
173     uint size;
174     BaseScene3D scene;
175     ShadowArea area1;
176     ShadowArea area2;
177     ShadowArea area3;
178     
179     GLuint depthTexture;
180     GLuint framebuffer1;
181     GLuint framebuffer2;
182     GLuint framebuffer3;
183     
184     ShadowBackend sb;
185     Material sm;
186     
187     float projSize1 = 5.0f;
188     float projSize2 = 15.0f;
189     float projSize3 = 400.0f;
190     
191     float zStart = -300.0f;
192     float zEnd = 300.0f;
193     
194     Color4f shadowColor = Color4f(1.0f, 1.0f, 1.0f, 1.0f);
195     float shadowBrightness = 0.1f;
196     bool useHeightCorrectedShadows = false;
197 
198     this(uint size, BaseScene3D scene, float projSizeNear, float projSizeMid, float projSizeFar, float zStart, float zEnd, Owner o)
199     {
200         super(o);
201         this.size = size;
202         this.scene = scene;
203         
204         projSize1 = projSizeNear;
205         projSize2 = projSizeMid;
206         projSize3 = projSizeFar;
207         
208         this.zStart = zStart;
209         this.zEnd = zEnd;
210 
211         this.area1 = New!ShadowArea(scene.environment, projSize1, projSize1, zStart, zEnd, this);
212         this.area2 = New!ShadowArea(scene.environment, projSize2, projSize2, zStart, zEnd, this);
213         this.area3 = New!ShadowArea(scene.environment, projSize3, projSize3, zStart, zEnd, this);
214         
215         this.sb = New!ShadowBackend(this);
216         this.sm = New!GenericMaterial(sb, this);
217 
218         glGenTextures(1, &depthTexture);
219         glActiveTexture(GL_TEXTURE0);
220         glBindTexture(GL_TEXTURE_2D_ARRAY, depthTexture);
221         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
222         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
223         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
224         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
225 
226         Color4f borderColor = Color4f(1, 1, 1, 1);
227         
228         glTexParameterfv(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BORDER_COLOR, borderColor.arrayof.ptr);
229         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
230 	    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
231 
232         glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT24, size, size, 3, 0, GL_DEPTH_COMPONENT, GL_FLOAT, null);
233         
234         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BASE_LEVEL, 0);
235         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, 0);
236         
237         glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
238 
239         glGenFramebuffers(1, &framebuffer1);
240 	    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer1);
241         glDrawBuffer(GL_NONE);
242 	    glReadBuffer(GL_NONE);
243         glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexture, 0, 0);
244         glBindFramebuffer(GL_FRAMEBUFFER, 0);
245         
246         glGenFramebuffers(1, &framebuffer2);
247 	    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer2);
248         glDrawBuffer(GL_NONE);
249 	    glReadBuffer(GL_NONE);
250         glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexture, 0, 1);
251         glBindFramebuffer(GL_FRAMEBUFFER, 0);
252         
253         glGenFramebuffers(1, &framebuffer3);
254 	    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer3);
255         glDrawBuffer(GL_NONE);
256 	    glReadBuffer(GL_NONE);
257         glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexture, 0, 2);
258         glBindFramebuffer(GL_FRAMEBUFFER, 0);
259     }
260     
261     Vector3f position()
262     {
263         return area1.position;
264     }
265     
266     void position(Vector3f pos)
267     {
268         area1.position = pos;
269         area2.position = pos;
270         area3.position = pos;
271     }
272     
273     ~this()
274     {
275         glBindFramebuffer(GL_FRAMEBUFFER, 0);
276         glDeleteFramebuffers(1, &framebuffer1);
277         glDeleteFramebuffers(1, &framebuffer2);
278         glDeleteFramebuffers(1, &framebuffer3);
279         
280         if (glIsTexture(depthTexture))
281             glDeleteTextures(1, &depthTexture);
282     }
283     
284     void update(RenderingContext* rc, double dt)
285     {
286         area1.update(rc, dt);
287         area2.update(rc, dt);
288         area3.update(rc, dt);
289     }
290     
291     void render(RenderingContext* rc)
292     {        
293         glBindFramebuffer(GL_FRAMEBUFFER, framebuffer1);
294 
295         glViewport(0, 0, size, size);
296         glScissor(0, 0, size, size);
297         glClear(GL_DEPTH_BUFFER_BIT);
298         
299         glEnable(GL_DEPTH_TEST);
300 
301         auto rcLocal = *rc;
302         rcLocal.projectionMatrix = area1.projectionMatrix;
303         rcLocal.viewMatrix = area1.viewMatrix;
304         rcLocal.invViewMatrix = area1.invViewMatrix;
305         rcLocal.normalMatrix = rcLocal.invViewMatrix.transposed;
306         
307         rcLocal.overrideMaterial = sm;
308 
309         glPolygonOffset(3.0, 0.0);
310         glDisable(GL_CULL_FACE);
311         glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
312 
313         foreach(e; scene.entities3D)
314             if (e.castShadow)
315                 e.render(&rcLocal);
316          
317         glBindFramebuffer(GL_FRAMEBUFFER, framebuffer2);
318 
319         glViewport(0, 0, size, size);
320         glScissor(0, 0, size, size);
321         glClear(GL_DEPTH_BUFFER_BIT);
322 
323         rcLocal.projectionMatrix = area2.projectionMatrix;
324         rcLocal.viewMatrix = area2.viewMatrix;
325         rcLocal.invViewMatrix = area2.invViewMatrix;
326         rcLocal.normalMatrix = rcLocal.invViewMatrix.transposed;
327 
328         foreach(e; scene.entities3D)
329             if (e.castShadow)
330                 e.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 
343         foreach(e; scene.entities3D)
344             if (e.castShadow)
345                 e.render(&rcLocal);
346         
347         glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
348         glEnable(GL_CULL_FACE);
349         glPolygonOffset(0.0, 0.0);
350         
351         glBindFramebuffer(GL_FRAMEBUFFER, 0);
352     }
353 }