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 }