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