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 }