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     q{
118         #version 330 core
119 
120         uniform mat4 modelViewMatrix;
121         uniform mat4 projectionMatrix;
122         
123         layout (location = 0) in vec3 va_Vertex;
124         
125         void main()
126         {
127             gl_Position = projectionMatrix * modelViewMatrix * vec4(va_Vertex, 1.0);
128         }
129     };
130     
131     string fsText =
132     q{
133         #version 330 core
134 
135         out vec4 frag_color;
136         
137         void main()
138         {
139             frag_color = vec4(1.0, 1.0, 1.0, 1.0);
140         }
141     };
142     
143     override string vertexShaderSrc() {return vsText;}
144     override string fragmentShaderSrc() {return fsText;}
145 
146     GLint modelViewMatrixLoc;
147     GLint projectionMatrixLoc;
148     
149     this(Owner o)
150     {
151         super(o);
152 
153         modelViewMatrixLoc = glGetUniformLocation(shaderProgram, "modelViewMatrix");
154         projectionMatrixLoc = glGetUniformLocation(shaderProgram, "projectionMatrix");
155     }
156     
157     override void bind(GenericMaterial mat, RenderingContext* rc)
158     {        
159         glDisable(GL_CULL_FACE);
160         
161         glUseProgram(shaderProgram);
162 
163         glUniformMatrix4fv(modelViewMatrixLoc, 1, GL_FALSE, rc.modelViewMatrix.arrayof.ptr);
164         glUniformMatrix4fv(projectionMatrixLoc, 1, GL_FALSE, rc.projectionMatrix.arrayof.ptr);
165     }
166     
167     override void unbind(GenericMaterial mat, RenderingContext* rc)
168     {        
169         glUseProgram(0);
170     }
171 }
172 
173 class CascadedShadowMap: Owner
174 {
175     uint size;
176     BaseScene3D scene;
177     ShadowArea area1;
178     ShadowArea area2;
179     ShadowArea area3;
180     
181     GLuint depthTexture;
182     GLuint framebuffer1;
183     GLuint framebuffer2;
184     GLuint framebuffer3;
185     
186     ShadowBackend sb;
187     Material sm;
188     
189     float projSize1 = 5.0f;
190     float projSize2 = 15.0f;
191     float projSize3 = 400.0f;
192     
193     float zStart = -300.0f;
194     float zEnd = 300.0f;
195     
196     Color4f shadowColor = Color4f(1.0f, 1.0f, 1.0f, 1.0f);
197     float shadowBrightness = 0.1f;
198     bool useHeightCorrectedShadows = false;
199 
200     this(uint size, BaseScene3D scene, float projSizeNear, float projSizeMid, float projSizeFar, float zStart, float zEnd, Owner o)
201     {
202         super(o);
203         this.size = size;
204         this.scene = scene;
205         
206         projSize1 = projSizeNear;
207         projSize2 = projSizeMid;
208         projSize3 = projSizeFar;
209         
210         this.zStart = zStart;
211         this.zEnd = zEnd;
212 
213         this.area1 = New!ShadowArea(scene.environment, projSize1, projSize1, zStart, zEnd, this);
214         this.area2 = New!ShadowArea(scene.environment, projSize2, projSize2, zStart, zEnd, this);
215         this.area3 = New!ShadowArea(scene.environment, projSize3, projSize3, zStart, zEnd, this);
216         
217         this.sb = New!ShadowBackend(this);
218         this.sm = New!GenericMaterial(sb, this);
219 
220         glGenTextures(1, &depthTexture);
221         glActiveTexture(GL_TEXTURE0);
222         glBindTexture(GL_TEXTURE_2D_ARRAY, depthTexture);
223         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
224         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
225         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
226         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
227 
228         Color4f borderColor = Color4f(1, 1, 1, 1);
229         
230         glTexParameterfv(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BORDER_COLOR, borderColor.arrayof.ptr);
231         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
232 	    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
233 
234         glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT24, size, size, 3, 0, GL_DEPTH_COMPONENT, GL_FLOAT, null);
235         
236         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BASE_LEVEL, 0);
237         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, 0);
238         
239         glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
240 
241         glGenFramebuffers(1, &framebuffer1);
242 	    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer1);
243         glDrawBuffer(GL_NONE);
244 	    glReadBuffer(GL_NONE);
245         glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexture, 0, 0);
246         glBindFramebuffer(GL_FRAMEBUFFER, 0);
247         
248         glGenFramebuffers(1, &framebuffer2);
249 	    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer2);
250         glDrawBuffer(GL_NONE);
251 	    glReadBuffer(GL_NONE);
252         glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexture, 0, 1);
253         glBindFramebuffer(GL_FRAMEBUFFER, 0);
254         
255         glGenFramebuffers(1, &framebuffer3);
256 	    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer3);
257         glDrawBuffer(GL_NONE);
258 	    glReadBuffer(GL_NONE);
259         glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexture, 0, 2);
260         glBindFramebuffer(GL_FRAMEBUFFER, 0);
261     }
262     
263     Vector3f position()
264     {
265         return area1.position;
266     }
267     
268     void position(Vector3f pos)
269     {
270         area1.position = pos;
271         area2.position = pos;
272         area3.position = pos;
273     }
274     
275     ~this()
276     {
277         glBindFramebuffer(GL_FRAMEBUFFER, 0);
278         glDeleteFramebuffers(1, &framebuffer1);
279         glDeleteFramebuffers(1, &framebuffer2);
280         glDeleteFramebuffers(1, &framebuffer3);
281         
282         if (glIsTexture(depthTexture))
283             glDeleteTextures(1, &depthTexture);
284     }
285     
286     void update(RenderingContext* rc, double dt)
287     {
288         area1.update(rc, dt);
289         area2.update(rc, dt);
290         area3.update(rc, dt);
291     }
292     
293     void render(RenderingContext* rc)
294     {        
295         glBindFramebuffer(GL_FRAMEBUFFER, framebuffer1);
296 
297         glViewport(0, 0, size, size);
298         glScissor(0, 0, size, size);
299         glClear(GL_DEPTH_BUFFER_BIT);
300         
301         glEnable(GL_DEPTH_TEST);
302 
303         auto rcLocal = *rc;
304         rcLocal.projectionMatrix = area1.projectionMatrix;
305         rcLocal.viewMatrix = area1.viewMatrix;
306         rcLocal.invViewMatrix = area1.invViewMatrix;
307         rcLocal.normalMatrix = rcLocal.invViewMatrix.transposed;
308         
309         rcLocal.overrideMaterial = sm;
310 
311         glPolygonOffset(3.0, 0.0);
312         glDisable(GL_CULL_FACE);
313         glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
314 
315         foreach(e; scene.entities3D)
316             if (e.castShadow)
317                 e.render(&rcLocal);
318          
319         glBindFramebuffer(GL_FRAMEBUFFER, framebuffer2);
320 
321         glViewport(0, 0, size, size);
322         glScissor(0, 0, size, size);
323         glClear(GL_DEPTH_BUFFER_BIT);
324 
325         rcLocal.projectionMatrix = area2.projectionMatrix;
326         rcLocal.viewMatrix = area2.viewMatrix;
327         rcLocal.invViewMatrix = area2.invViewMatrix;
328         rcLocal.normalMatrix = rcLocal.invViewMatrix.transposed;
329 
330         foreach(e; scene.entities3D)
331             if (e.castShadow)
332                 e.render(&rcLocal);
333         
334         glBindFramebuffer(GL_FRAMEBUFFER, framebuffer3);
335 
336         glViewport(0, 0, size, size);
337         glScissor(0, 0, size, size);
338         glClear(GL_DEPTH_BUFFER_BIT);
339 
340         rcLocal.projectionMatrix = area3.projectionMatrix;
341         rcLocal.viewMatrix = area3.viewMatrix;
342         rcLocal.invViewMatrix = area3.invViewMatrix;
343         rcLocal.normalMatrix = rcLocal.invViewMatrix.transposed;
344 
345         foreach(e; scene.entities3D)
346             if (e.castShadow)
347                 e.render(&rcLocal);
348         
349         glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
350         glEnable(GL_CULL_FACE);
351         glPolygonOffset(0.0, 0.0);
352         
353         glBindFramebuffer(GL_FRAMEBUFFER, 0);
354     }
355 }