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 }