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 dagon.core.libs;
44 import dagon.core.interfaces;
45 import dagon.core.ownership;
46 import dagon.logics.entity;
47 import dagon.logics.behaviour;
48 import dagon.graphics.shapes;
49 import dagon.graphics.texture;
50 import dagon.graphics.view;
51 import dagon.graphics.rc;
52 import dagon.graphics.environment;
53 import dagon.graphics.material;
54 import dagon.graphics.shaders.shadowpass;
55 import dagon.resource.scene;
56 
57 class ShadowArea: Owner
58 {
59     Matrix4x4f biasMatrix;
60     Matrix4x4f projectionMatrix;
61     Matrix4x4f viewMatrix;
62     Matrix4x4f invViewMatrix;
63     Matrix4x4f shadowMatrix;
64     float width;
65     float height;
66     float depth;
67     float start;
68     float end;
69     float scale = 1.0f;
70     Vector3f position;
71 
72     this(float w, float h, float start, float end, Owner o)
73     {
74         super(o);
75         this.width = w;
76         this.height = h;
77         this.start = start;
78         this.end = end;
79 
80         depth = abs(start) + abs(end);
81 
82         this.position = Vector3f(0, 0, 0);
83 
84         this.biasMatrix = matrixf(
85             0.5f, 0.0f, 0.0f, 0.5f,
86             0.0f, 0.5f, 0.0f, 0.5f,
87             0.0f, 0.0f, 0.5f, 0.5f,
88             0.0f, 0.0f, 0.0f, 1.0f,
89         );
90 
91         float hw = w * 0.5f;
92         float hh = h * 0.5f;
93         this.projectionMatrix = orthoMatrix(-hw, hw, -hh, hh, start, end);
94 
95         this.shadowMatrix = Matrix4x4f.identity;
96         this.viewMatrix = Matrix4x4f.identity;
97         this.invViewMatrix = Matrix4x4f.identity;
98     }
99 
100     void update(RenderingContext* rc, double dt)
101     {
102         auto t = translationMatrix(position);
103         auto r = rc.environment.sunRotation.toMatrix4x4;
104         invViewMatrix = t * r;
105         viewMatrix = invViewMatrix.inverse;
106         shadowMatrix = scaleMatrix(Vector3f(scale, scale, 1.0f)) * biasMatrix * projectionMatrix * viewMatrix * rc.invViewMatrix;
107     }
108 }
109 
110 class CascadedShadowMap: Owner
111 {
112     uint size;
113     ShadowArea area1;
114     ShadowArea area2;
115     ShadowArea area3;
116 
117     GLuint depthTexture;
118     GLuint framebuffer1;
119     GLuint framebuffer2;
120     GLuint framebuffer3;
121 
122     ShadowPassShader ss;
123 
124     float projSize1 = 5.0f;
125     float projSize2 = 15.0f;
126     float projSize3 = 400.0f;
127 
128     float zStart = -300.0f;
129     float zEnd = 300.0f;
130 
131     Color4f shadowColor = Color4f(1.0f, 1.0f, 1.0f, 1.0f);
132     float shadowBrightness = 0.1f;
133     bool useHeightCorrectedShadows = false;
134 
135     this(uint size, float projSizeNear, float projSizeMid, float projSizeFar, float zStart, float zEnd, Owner o)
136     {
137         super(o);
138         this.size = size;
139 
140         projSize1 = projSizeNear;
141         projSize2 = projSizeMid;
142         projSize3 = projSizeFar;
143 
144         this.zStart = zStart;
145         this.zEnd = zEnd;
146 
147         this.area1 = New!ShadowArea(projSize1, projSize1, zStart, zEnd, this);
148         this.area2 = New!ShadowArea(projSize2, projSize2, zStart, zEnd, this);
149         this.area3 = New!ShadowArea(projSize3, projSize3, zStart, zEnd, this);
150 
151         this.ss = New!ShadowPassShader(this);
152 
153         glGenTextures(1, &depthTexture);
154         glActiveTexture(GL_TEXTURE0);
155         glBindTexture(GL_TEXTURE_2D_ARRAY, depthTexture);
156         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
157         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
158         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
159         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
160 
161         Color4f borderColor = Color4f(1, 1, 1, 1);
162 
163         glTexParameterfv(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BORDER_COLOR, borderColor.arrayof.ptr);
164         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
165 	    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
166 
167         glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT24, size, size, 3, 0, GL_DEPTH_COMPONENT, GL_FLOAT, null);
168 
169         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BASE_LEVEL, 0);
170         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, 0);
171 
172         glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
173 
174         glGenFramebuffers(1, &framebuffer1);
175 	    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer1);
176         glDrawBuffer(GL_NONE);
177 	    glReadBuffer(GL_NONE);
178         glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexture, 0, 0);
179         glBindFramebuffer(GL_FRAMEBUFFER, 0);
180 
181         glGenFramebuffers(1, &framebuffer2);
182 	    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer2);
183         glDrawBuffer(GL_NONE);
184 	    glReadBuffer(GL_NONE);
185         glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexture, 0, 1);
186         glBindFramebuffer(GL_FRAMEBUFFER, 0);
187 
188         glGenFramebuffers(1, &framebuffer3);
189 	    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer3);
190         glDrawBuffer(GL_NONE);
191 	    glReadBuffer(GL_NONE);
192         glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexture, 0, 2);
193         glBindFramebuffer(GL_FRAMEBUFFER, 0);
194     }
195 
196     Vector3f position()
197     {
198         return area1.position;
199     }
200 
201     void position(Vector3f pos)
202     {
203         area1.position = pos;
204         area2.position = pos;
205         area3.position = pos;
206     }
207 
208     ~this()
209     {
210         glBindFramebuffer(GL_FRAMEBUFFER, 0);
211         glDeleteFramebuffers(1, &framebuffer1);
212         glDeleteFramebuffers(1, &framebuffer2);
213         glDeleteFramebuffers(1, &framebuffer3);
214 
215         if (glIsTexture(depthTexture))
216             glDeleteTextures(1, &depthTexture);
217     }
218 
219     void update(RenderingContext* rc, double dt)
220     {
221         area1.update(rc, dt);
222         area2.update(rc, dt);
223         area3.update(rc, dt);
224     }
225 
226     void render(Scene scene, RenderingContext* rc)
227     {
228         glBindFramebuffer(GL_FRAMEBUFFER, framebuffer1);
229 
230         glViewport(0, 0, size, size);
231         glScissor(0, 0, size, size);
232         glClear(GL_DEPTH_BUFFER_BIT);
233 
234         glEnable(GL_DEPTH_TEST);
235 
236         auto rcLocal = *rc;
237         rcLocal.projectionMatrix = area1.projectionMatrix;
238         rcLocal.viewMatrix = area1.viewMatrix;
239         rcLocal.invViewMatrix = area1.invViewMatrix;
240         rcLocal.normalMatrix = rcLocal.invViewMatrix.transposed;
241         rcLocal.viewRotationMatrix = matrix3x3to4x4(matrix4x4to3x3(rcLocal.viewMatrix));
242         rcLocal.invViewRotationMatrix = matrix3x3to4x4(matrix4x4to3x3(rcLocal.invViewMatrix));
243 
244         rcLocal.overrideShader = ss;
245         rcLocal.shadowPass = true;
246 
247         glPolygonOffset(3.0, 0.0);
248         glDisable(GL_CULL_FACE);
249         glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
250 
251         foreach(e; scene.entities3D)
252             if (e.castShadow)
253                 e.render(&rcLocal);
254         scene.particleSystem.render(&rcLocal);
255 
256         glBindFramebuffer(GL_FRAMEBUFFER, framebuffer2);
257 
258         glViewport(0, 0, size, size);
259         glScissor(0, 0, size, size);
260         glClear(GL_DEPTH_BUFFER_BIT);
261 
262         rcLocal.projectionMatrix = area2.projectionMatrix;
263         rcLocal.viewMatrix = area2.viewMatrix;
264         rcLocal.invViewMatrix = area2.invViewMatrix;
265         rcLocal.normalMatrix = rcLocal.invViewMatrix.transposed;
266         rcLocal.viewRotationMatrix = matrix3x3to4x4(matrix4x4to3x3(rcLocal.viewMatrix));
267         rcLocal.invViewRotationMatrix = matrix3x3to4x4(matrix4x4to3x3(rcLocal.invViewMatrix));
268 
269         foreach(e; scene.entities3D)
270             if (e.castShadow)
271                 e.render(&rcLocal);
272         scene.particleSystem.render(&rcLocal);
273 
274         glBindFramebuffer(GL_FRAMEBUFFER, framebuffer3);
275 
276         glViewport(0, 0, size, size);
277         glScissor(0, 0, size, size);
278         glClear(GL_DEPTH_BUFFER_BIT);
279 
280         rcLocal.projectionMatrix = area3.projectionMatrix;
281         rcLocal.viewMatrix = area3.viewMatrix;
282         rcLocal.invViewMatrix = area3.invViewMatrix;
283         rcLocal.normalMatrix = rcLocal.invViewMatrix.transposed;
284         rcLocal.viewRotationMatrix = matrix3x3to4x4(matrix4x4to3x3(rcLocal.viewMatrix));
285         rcLocal.invViewRotationMatrix = matrix3x3to4x4(matrix4x4to3x3(rcLocal.invViewMatrix));
286 
287         foreach(e; scene.entities3D)
288             if (e.castShadow)
289                 e.render(&rcLocal);
290         scene.particleSystem.render(&rcLocal);
291 
292         glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
293         glEnable(GL_CULL_FACE);
294         glPolygonOffset(0.0, 0.0);
295 
296         glBindFramebuffer(GL_FRAMEBUFFER, 0);
297     }
298 }