1 /* 2 Copyright (c) 2015 Timur Gafarov 3 4 Boost Software License - Version 1.0 - August 17th, 2003 5 6 Permission is hereby granted, free of charge, to any person or organization 7 obtaining a copy of the software and accompanying documentation covered by 8 this license (the "Software") to use, reproduce, display, distribute, 9 execute, and transmit the Software, and to prepare derivative works of the 10 Software, and to permit third-parties to whom the Software is furnished to 11 do so, all subject to the following: 12 13 The copyright notices in the Software and this entire statement, including 14 the above license grant, this restriction and the following disclaimer, 15 must be included in all copies of the Software, in whole or in part, and 16 all derivative works of the Software, unless such copies or derivative 17 works are solely in the form of machine-executable object code generated by 18 a source language processor. 19 20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 23 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 24 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 25 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 DEALINGS IN THE SOFTWARE. 27 */ 28 29 module dgl.graphics.shadow; 30 31 import derelict.opengl.gl; 32 import derelict.opengl.glu; 33 import derelict.opengl.glext; 34 35 import dlib.core.memory; 36 import dlib.container.array; 37 import dlib.math.vector; 38 import dlib.math.matrix; 39 import dlib.math.affine; 40 import dlib.math.utils; 41 42 import dgl.core.interfaces; 43 import dgl.graphics.scene; 44 import dgl.graphics.material; 45 46 class ShadowMap: Drawable 47 { 48 Scene castScene; 49 Scene receiveScene; 50 51 GLuint depthBuffer; 52 Matrix4x4f lightProjectionMatrix; 53 Matrix4x4f lightViewMatrix; 54 Vector4f lightPosition = Vector4f(0.0f, -1.0f, 0.0f, 0.0f); 55 56 Matrix4x4f biasMatrix; 57 58 Vector4f white = Vector4f(1.0f, 1.0f, 1.0f, 1.0f); 59 Vector4f c = Vector4f(0.0f, 0.1f, 0.2f, 1.0f); 60 Vector4f black = Vector4f(0.0f, 0.0f, 0.0f, 0.0f); 61 62 uint width, height; 63 GLint[4] viewport; 64 65 float ofsFactor = 4.7; 66 float ofsUnits = 5.3; 67 68 bool useShader = true; 69 70 this(uint w, uint h) 71 { 72 width = w; 73 height = h; 74 75 //glDepthFunc(GL_LEQUAL); 76 glEnable(GL_DEPTH_TEST); 77 78 glGenTextures(1, &depthBuffer); 79 glBindTexture(GL_TEXTURE_2D, depthBuffer); 80 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); //GL_NEAREST for sharp edges 81 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); //GL_NEAREST for sharp edges 82 //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 83 //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 84 85 //Enable shadow comparison 86 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); 87 //Shadow comparison should be true (i.e. not in shadow) if r <= texture 88 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); 89 //Shadow comparison should generate an INTENSITY result 90 glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY); 91 92 glTexImage2D(GL_TEXTURE_2D, 0, 93 GL_DEPTH_COMPONENT, width, height, 0, 94 GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, null); 95 //glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, null); 96 97 glLoadIdentity(); 98 float size = 20; 99 glOrtho(-size, size, -size, size, -20.0f, 100.0f); 100 glGetFloatv(GL_MODELVIEW_MATRIX, lightProjectionMatrix.arrayof.ptr); 101 glLoadIdentity(); 102 103 Vector3f v1 = Vector3f(1, -1, 1).normalized; 104 Vector3f v2 = cross(v1, Vector3f(0, 1, 0)); 105 up = cross(v2, v1); 106 } 107 108 Vector3f up; 109 110 void draw(double dt) 111 { 112 glPushMatrix(); 113 glLoadIdentity(); 114 Vector3f toVector = Vector3f(lightPosition.x + 1, -1, lightPosition.z + 1); 115 gluLookAt(lightPosition.x, 0, lightPosition.z, 116 toVector.x, toVector.y, toVector.z, 117 up.x, up.y, up.z); 118 glGetFloatv(GL_MODELVIEW_MATRIX, lightViewMatrix.arrayof.ptr); 119 glPopMatrix(); 120 121 renderDepthBuffer(dt); 122 123 glClear(GL_DEPTH_BUFFER_BIT); 124 125 //Use dim light to represent shadowed areas 126 glLightfv(GL_LIGHT7, GL_POSITION, lightPosition.arrayof.ptr); 127 glLightfv(GL_LIGHT7, GL_AMBIENT, c.arrayof.ptr); 128 glLightfv(GL_LIGHT7, GL_DIFFUSE, c.arrayof.ptr); 129 glLightfv(GL_LIGHT7, GL_SPECULAR, black.arrayof.ptr); 130 glEnable(GL_LIGHT7); 131 glEnable(GL_LIGHTING); 132 133 if (receiveScene) 134 { 135 receiveScene.lighted = false; 136 dgl.graphics.material.useDimLight = true; 137 receiveScene.draw(dt); 138 } 139 if (castScene) 140 { 141 castScene.lighted = false; 142 dgl.graphics.material.useDimLight = true; 143 castScene.draw(dt); 144 } 145 146 //Draw with bright light 147 glLightfv(GL_LIGHT7, GL_DIFFUSE, white.arrayof.ptr); 148 glLightfv(GL_LIGHT7, GL_SPECULAR, white.arrayof.ptr); 149 glDisable(GL_LIGHT7); 150 glDisable(GL_LIGHTING); 151 152 //Bind & enable shadow map texture 153 glActiveTextureARB(GL_TEXTURE3_ARB); 154 bindDepthBuffer(); 155 156 //Matrix4x4f modelView; 157 //glGetFloatv(GL_MODELVIEW_MATRIX, modelView.arrayof.ptr); 158 //Matrix4x4f invViewMartrix = modelView.inverse(); 159 160 // Calculate texture matrix for projection 161 // This matrix takes us from eye space to the light's clip space 162 // It is postmultiplied by the inverse of the current view matrix when specifying texgen 163 //Matrix4x4f textureMatrix = biasMatrix * lightProjectionMatrix * lightViewMatrix; 164 glMatrixMode(GL_TEXTURE); 165 glPushMatrix(); 166 glLoadIdentity(); 167 glTranslatef(0.5f, 0.5f, 0.5f); // bias matrix 168 glScalef(0.5f, 0.5f, 0.5f); 169 glMultMatrixf(lightProjectionMatrix.arrayof.ptr); 170 glMultMatrixf(lightViewMatrix.arrayof.ptr); 171 //glMultMatrixf(invViewMartrix.arrayof.ptr); 172 glMatrixMode(GL_MODELVIEW); 173 174 //Set up texture coordinate generation. 175 auto ide = Matrix4x4f.identity; 176 177 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); 178 glTexGenfv(GL_S, GL_EYE_PLANE, ide.getRow(0).arrayof.ptr); 179 glEnable(GL_TEXTURE_GEN_S); 180 181 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); 182 glTexGenfv(GL_T, GL_EYE_PLANE, ide.getRow(1).arrayof.ptr); 183 glEnable(GL_TEXTURE_GEN_T); 184 185 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); 186 glTexGenfv(GL_R, GL_EYE_PLANE, ide.getRow(2).arrayof.ptr); 187 glEnable(GL_TEXTURE_GEN_R); 188 189 glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); 190 glTexGenfv(GL_Q, GL_EYE_PLANE, ide.getRow(3).arrayof.ptr); 191 glEnable(GL_TEXTURE_GEN_Q); 192 193 //Set alpha test to discard false comparisons 194 //glAlphaFunc(GL_GREATER, 0.7f); 195 //glEnable(GL_ALPHA_TEST); 196 197 glActiveTextureARB(GL_TEXTURE0_ARB); 198 199 glEnable(GL_POLYGON_OFFSET_FILL); 200 glPolygonOffset(ofsFactor, ofsUnits); 201 202 if (castScene) 203 { 204 castScene.lighted = true; 205 dgl.graphics.material.useDimLight = false; 206 castScene.draw(dt); 207 } 208 if (receiveScene) 209 { 210 receiveScene.lighted = true; 211 dgl.graphics.material.useDimLight = false; 212 receiveScene.draw(dt); 213 } 214 215 //glPolygonOffset(0, 0); 216 217 //Disable textures and texgen 218 glActiveTextureARB(GL_TEXTURE3_ARB); 219 unbindDepthBuffer(); 220 221 glDisable(GL_TEXTURE_GEN_S); 222 glDisable(GL_TEXTURE_GEN_T); 223 glDisable(GL_TEXTURE_GEN_R); 224 glDisable(GL_TEXTURE_GEN_Q); 225 226 glMatrixMode(GL_TEXTURE); 227 glPopMatrix(); 228 glMatrixMode(GL_MODELVIEW); 229 230 glActiveTextureARB(GL_TEXTURE0_ARB); 231 232 //Restore other states 233 glDisable(GL_LIGHTING); 234 glDisable(GL_ALPHA_TEST); 235 } 236 237 void renderDepthBuffer(double dt) 238 { 239 //glCullFace(GL_FRONT); 240 glShadeModel(GL_FLAT); 241 glColorMask(0, 0, 0, 0); 242 243 glGetIntegerv(GL_VIEWPORT, viewport.ptr); 244 glViewport(0, 0, width, height); 245 246 glMatrixMode(GL_PROJECTION); 247 glPushMatrix(); 248 glLoadMatrixf(lightProjectionMatrix.arrayof.ptr); 249 glMatrixMode(GL_MODELVIEW); 250 glPushMatrix(); 251 glLoadMatrixf(lightViewMatrix.arrayof.ptr); 252 253 // Draw the scene 254 if (castScene) 255 { 256 dgl.graphics.material.useDimLight = true; 257 castScene.draw(dt); 258 dgl.graphics.material.useDimLight = false; 259 } 260 261 glPopMatrix(); 262 glMatrixMode(GL_PROJECTION); 263 glPopMatrix(); 264 glMatrixMode(GL_MODELVIEW); 265 266 //Read the depth buffer into the shadow map texture 267 glEnable(GL_TEXTURE_2D); 268 glBindTexture(GL_TEXTURE_2D, depthBuffer); 269 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, width, height); 270 glBindTexture(GL_TEXTURE_2D, 0); 271 glDisable(GL_TEXTURE_2D); 272 273 glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); 274 275 //restore states 276 //glCullFace(GL_BACK); 277 glShadeModel(GL_SMOOTH); 278 glColorMask(1, 1, 1, 1); 279 } 280 281 void free() 282 { 283 Delete(this); 284 } 285 286 ~this() 287 { 288 if (glIsTexture(depthBuffer)) 289 glDeleteTextures(1, &depthBuffer); 290 } 291 292 void bindDepthBuffer() 293 { 294 glEnable(GL_TEXTURE_2D); 295 glBindTexture(GL_TEXTURE_2D, depthBuffer); 296 } 297 298 void unbindDepthBuffer() 299 { 300 glBindTexture(GL_TEXTURE_2D, 0); 301 glDisable(GL_TEXTURE_2D); 302 } 303 }