From 6884adf0c2f8eeee2f05cd768d79733b932aa17c Mon Sep 17 00:00:00 2001
From: Daniel Chappuis <chappuis.daniel@gmail.com>
Date: Sun, 26 Jul 2015 22:30:45 +0000
Subject: [PATCH] Fix issue with shadow mapping

---
 testbed/opengl-framework/src/maths/Matrix4.h | 58 +++++++++++++++++++-
 testbed/shaders/phong.frag                   |  6 +-
 testbed/src/SceneDemo.cpp                    | 10 +++-
 testbed/src/SceneDemo.h                      |  3 +
 4 files changed, 70 insertions(+), 7 deletions(-)

diff --git a/testbed/opengl-framework/src/maths/Matrix4.h b/testbed/opengl-framework/src/maths/Matrix4.h
index bcfbcebd..f481ecc9 100644
--- a/testbed/opengl-framework/src/maths/Matrix4.h
+++ b/testbed/opengl-framework/src/maths/Matrix4.h
@@ -27,7 +27,7 @@
 #define MATRIX4_H
 
 // Libraries
-#include <math.h>
+#include <cmath>
 #include <assert.h>
 #include <iostream>
 #include "Vector3.h"
@@ -376,6 +376,15 @@ class Matrix4 {
 
         // Return a 4x4 rotation matrix
         static Matrix4 rotationMatrix(const Vector3& axis, float angle);
+
+        // Return a 4x4 perspective projection matrix
+        static Matrix4 perspectiveProjectionMatrix(float near, float far,
+                                                   int width, int height,
+                                                   float fieldOfView);
+
+        // Return a 4x4 orthographic projection matrix
+        static Matrix4 orthoProjectionMatrix(float near, float far, int width,
+                                             int height);
 };
 
 // * operator
@@ -422,6 +431,53 @@ inline Matrix4 Matrix4::rotationMatrix(const Vector3& axis, float angle) {
     return rotationMatrix;
 }
 
+// Return a 4x4 perspective projection matrix
+inline Matrix4 Matrix4::perspectiveProjectionMatrix(float near, float far, int width, int height,
+                                                    float fieldOfView) {
+
+    // Compute the aspect ratio
+    float aspect = float(width) / float(height);
+
+    float top = near * tan((fieldOfView / 2.0f) * (float(M_PI) / 180.0f));
+    float bottom = -top;
+    float left = bottom * aspect;
+    float right = top * aspect;
+
+    float fx = 2.0f * near / (right - left);
+    float fy = 2.0f * near / (top - bottom);
+    float fz = -(far + near) / (far - near);
+    float fw = -2.0f * far * near / (far - near);
+
+    // Compute the projection matrix
+    return Matrix4(fx, 0, 0, 0,
+                   0, fy, 0, 0,
+                   0, 0, fz, fw,
+                   0, 0, -1, 0);
+}
+
+// Return a 4x4 orthographic projection matrix
+inline Matrix4 Matrix4::orthoProjectionMatrix(float near, float far, int width, int height) {
+
+    // Compute the aspect ratio
+    float aspect = float(width) / float(height);
+
+    float top = height * 0.5f;
+    float bottom = -top;
+    float left = bottom * aspect;
+    float right = top * aspect;
+
+    float fx = 2.0f / (right - left);
+    float fy = 2.0f / (top - bottom);
+    float fz = -2.0f / (far - near);
+    float fw = -(far + near) / (far - near);
+
+    // Compute the projection matrix
+    return Matrix4(fx, 0, 0, 0,
+                   0, fy, 0, 0,
+                   0, 0, fz, fw,
+                   0, 0, 0, 1);
+}
+
 }
 
 #endif //_MATRIX4_H
diff --git a/testbed/shaders/phong.frag b/testbed/shaders/phong.frag
index 677b289a..498f7238 100644
--- a/testbed/shaders/phong.frag
+++ b/testbed/shaders/phong.frag
@@ -71,9 +71,8 @@ void main() {
 
     // Compute shadow factor
     vec4 shadowMapCoordsOverW = shadowMapCoords / shadowMapCoords.w ;
-    shadowMapCoordsOverW += 0.0005;
-    vec2 shadowMapCoordsWithBias = (shadowMapCoordsOverW.xy + vec2(1, 1)) * 0.5;
-    float distanceInShadowMap = texture(shadowMapSampler, shadowMapCoordsWithBias).r;
+    //shadowMapCoordsOverW += 0.0005;
+    float distanceInShadowMap = texture(shadowMapSampler, shadowMapCoordsOverW.xy).r;
     float shadow = 0.0;
     if (shadowMapCoords.w > 0) {
         shadow = distanceInShadowMap < shadowMapCoordsOverW.z ? 0.0 : 1.0;
@@ -81,5 +80,4 @@ void main() {
 
     // Compute the final color
     color = vec4(ambient + shadow * vertexColor.rgb, 1.0);
-    //color = vec4(distanceInShadowMap, distanceInShadowMap, distanceInShadowMap, 1.0);
 }
diff --git a/testbed/src/SceneDemo.cpp b/testbed/src/SceneDemo.cpp
index 69ab76db..efee5fcc 100644
--- a/testbed/src/SceneDemo.cpp
+++ b/testbed/src/SceneDemo.cpp
@@ -47,6 +47,12 @@ SceneDemo::SceneDemo(const std::string& name, float sceneRadius) : Scene(name),
     mShadowMapLightCamera.setSceneRadius(200);
     //mShadowMapLightCamera.setZoom(1.0);
 
+
+    mShadowMapBiasMatrix.setAllValues(0.5, 0.0, 0.0, 0.5,
+                                      0.0, 0.5, 0.0, 0.5,
+                                      0.0, 0.0, 0.5, 0.5,
+                                      0.0, 0.0, 0.0, 1.0);
+
     // Create the Shadow map FBO and texture
     createShadowMapFBOAndTexture();
 
@@ -115,7 +121,7 @@ void SceneDemo::render() {
 
     // Set the variables of the shader
     mPhongShader.setMatrix4x4Uniform("projectionMatrix", mCamera.getProjectionMatrix());
-    mPhongShader.setMatrix4x4Uniform("shadowMapProjectionMatrix", shadowMapProjMatrix);
+    mPhongShader.setMatrix4x4Uniform("shadowMapProjectionMatrix", mShadowMapBiasMatrix * shadowMapProjMatrix);
     mPhongShader.setMatrix4x4Uniform("worldToLight0CameraMatrix", worldToLightCameraMatrix);
     mPhongShader.setVector3Uniform("light0PosCameraSpace", worldToCameraMatrix * mLight0.getOrigin());
     mPhongShader.setVector3Uniform("lightAmbientColor", Vector3(0.3f, 0.3f, 0.3f));
@@ -148,7 +154,7 @@ void SceneDemo::render() {
 void SceneDemo::createShadowMapFBOAndTexture() {
 
     // Create the texture for the depth values
-    mShadowMapTexture.create(SHADOWMAP_WIDTH, SHADOWMAP_HEIGHT, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT,
+    mShadowMapTexture.create(SHADOWMAP_WIDTH, SHADOWMAP_HEIGHT, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT,
                              GL_UNSIGNED_BYTE, GL_NEAREST, GL_NEAREST, GL_CLAMP, GL_CLAMP, NULL);
     mShadowMapTexture.setLayer(1);
 
diff --git a/testbed/src/SceneDemo.h b/testbed/src/SceneDemo.h
index 28d571a9..92e64c10 100644
--- a/testbed/src/SceneDemo.h
+++ b/testbed/src/SceneDemo.h
@@ -51,6 +51,9 @@ class SceneDemo : public Scene {
         /// Shadow map texture
         openglframework::Texture2D mShadowMapTexture;
 
+        /// Shadow map bias matrix
+        openglframework::Matrix4 mShadowMapBiasMatrix;
+
         /// Camera at light0 position for the shadow map
         openglframework::Camera mShadowMapLightCamera;