Browse Source

experimental calculation of the volume of the shadow map

Kajetan Johannes Hammerle 3 years ago
parent
commit
55e1bae891

+ 2 - 2
client/Game.cpp

@@ -2,7 +2,7 @@
 
 #include "client/Game.h"
 
-Game::Game() : lengthAngle(0.0f), widthAngle(0.0f), texture("resources/textures.png") {
+Game::Game() : lengthAngle(20.0f), widthAngle(35.0f), texture("resources/textures.png") {
     for(int x = -6; x <= 6; x++) {
         for(int y = -6; y <= 6; y++) {
             for(int z = -6; z <= 6; z++) {
@@ -19,7 +19,7 @@ Game::Game() : lengthAngle(0.0f), widthAngle(0.0f), texture("resources/textures.
         }
     }
     addCube(-3, -1, -10, false, true, true, true, true, true);
-    pos.set(-3, 0, -10);
+    //pos.set(-3, 0, -10);
     m.build();
 }
 

+ 163 - 37
client/GameClient.cpp

@@ -5,6 +5,7 @@
 #include <cmath>
 #include <cstring>
 #include <array>
+#include <cfloat>
 
 #include "common/utils/Types.h"
 #include "client/GameClient.h"
@@ -17,6 +18,7 @@
 #include "client/Utils.h"
 #include "client/math/Camera.h"
 #include "client/math/Matrix.h"
+#include "client/math/Plane.h"
 #include "client/math/MatrixStack.h"
 #include "client/Game.h"
 #include "rendering/NoiseTexture.h"
@@ -44,14 +46,16 @@ static int height = 0;
 static bool resize = false;
 static float fovY = 60.0f;
 static float nearClip = 0.1f;
-static float farClip = 1000.0f;
+static float farClip = 80.0f;
 static InternGameClient client;
 static Keys keys;
 static MouseButtons mButtons;
 static bool useSSAO = false;
 
-static float testRadius = 0.005;
-static float testBias = 0.00025;
+static float testRadius = 0.0005;
+static float testBias = 0.000025;
+static bool ortho = false;
+static Vector testOrthoCenter;
 
 struct Shaders {
 
@@ -64,9 +68,6 @@ struct Shaders {
     text("resources/shader/textVertex.vs", "resources/shader/textFragment.fs") {
         worldProj.set(11, -1.0f);
         worldProj.set(15, 0.0f);
-
-        worldShadowProj.set(11, -1.0f);
-        worldShadowProj.set(15, 0.0f);
     }
 
     Shader world;
@@ -89,31 +90,150 @@ struct Shaders {
                 shadow.isValid() && postWorld.isValid() && text.isValid();
     }
 
-    void updateWorldProjection() {
+    void updateWorldProjection(const Camera& cam) {
         float tan = tanf((0.5f * fovY) * M_PI / 180.0f);
         float q = 1.0f / tan;
         float aspect = (float) width / height;
 
+        worldProj.setToIdentity();
+        worldProj.set(11, -1.0f);
+        worldProj.set(15, 0.0f);
         worldProj.set(0, q / aspect);
         worldProj.set(5, q);
         worldProj.set(10, (nearClip + farClip) / (nearClip - farClip));
         worldProj.set(14, (2.0f * nearClip * farClip) / (nearClip - farClip));
 
+        // http://cgvr.informatik.uni-bremen.de/teaching/cg_literatur/lighthouse3d_view_frustum_culling/index.html
+        float closeFarClip = 4;
+        float nearHigh = tan * nearClip;
+        float nearWidth = nearHigh * aspect;
+        float farHigh = tan * closeFarClip;
+        float farWidth = farHigh * aspect;
+
+        Vector farCenter = cam.getPosition();
+        farCenter.addMul(cam.getFront(), closeFarClip);
+
+        Vector farTopLeft = farCenter;
+        farTopLeft.addMul(cam.getLeft(), farWidth);
+        farTopLeft.addMul(cam.getUp(), farHigh);
+
+        Vector farBottomLeft = farCenter;
+        farBottomLeft.addMul(cam.getLeft(), farWidth);
+        farBottomLeft.addMul(cam.getDown(), farHigh);
+
+        Vector farTopRight = farCenter;
+        farTopRight.addMul(cam.getRight(), farWidth);
+        farTopRight.addMul(cam.getUp(), farHigh);
+
+        Vector farBottomRight = farCenter;
+        farBottomRight.addMul(cam.getRight(), farWidth);
+        farBottomRight.addMul(cam.getDown(), farHigh);
+
+        Vector nearCenter = cam.getPosition();
+        nearCenter.addMul(cam.getFront(), nearClip);
+
+        Vector nearTopLeft = nearCenter;
+        nearTopLeft.addMul(cam.getLeft(), nearWidth);
+        nearTopLeft.addMul(cam.getUp(), nearHigh);
+
+        Vector nearBottomLeft = nearCenter;
+        nearBottomLeft.addMul(cam.getLeft(), nearWidth);
+        nearBottomLeft.addMul(cam.getDown(), nearHigh);
+
+        Vector nearTopRight = nearCenter;
+        nearTopRight.addMul(cam.getRight(), nearWidth);
+        nearTopRight.addMul(cam.getUp(), nearHigh);
+
+        Vector nearBottomRight = nearCenter;
+        nearBottomRight.addMul(cam.getRight(), nearWidth);
+        nearBottomRight.addMul(cam.getDown(), nearHigh);
+
+        Vector light(-0.280166, -0.573576, -0.769751);
+        Vector lightLeft = light;
+        lightLeft.cross(0.0f, 1.0f, 0.0f);
+        Vector lightUp = lightLeft;
+        lightUp.cross(light);
+        
+        //std::cout << "-------------------------\n";
+        Plane plane;
+        plane.set(Vector(), light, lightUp);
+        float f[8];
+        f[0] = plane.getSignedDistance(farTopLeft);
+        f[1] = plane.getSignedDistance(farBottomLeft);
+        f[2] = plane.getSignedDistance(farTopRight);
+        f[3] = plane.getSignedDistance(farBottomRight);
+        f[4] = plane.getSignedDistance(nearTopLeft);
+        f[5] = plane.getSignedDistance(nearBottomLeft);
+        f[6] = plane.getSignedDistance(nearTopRight);
+        f[7] = plane.getSignedDistance(nearBottomRight);
+        float min = FLT_MAX;
+        float max = -FLT_MAX;
+        for(uint i = 0; i < 8; i++) {
+            if(f[i] < min) {
+                min = f[i];
+            }
+            if(f[i] > max) {
+                max = f[i];
+            }
+        }
+        float lightWidth = max - min;
+        //std::cout << lightWidth << "\n";
+        
+        plane.set(Vector(), light, lightLeft);
+        f[0] = plane.getSignedDistance(farTopLeft);
+        f[1] = plane.getSignedDistance(farBottomLeft);
+        f[2] = plane.getSignedDistance(farTopRight);
+        f[3] = plane.getSignedDistance(farBottomRight);
+        f[4] = plane.getSignedDistance(nearTopLeft);
+        f[5] = plane.getSignedDistance(nearBottomLeft);
+        f[6] = plane.getSignedDistance(nearTopRight);
+        f[7] = plane.getSignedDistance(nearBottomRight);
+        
+        min = FLT_MAX;
+        max = -FLT_MAX;
+        for(uint i = 0; i < 8; i++) {
+            if(f[i] < min) {
+                min = f[i];
+            }
+            if(f[i] > max) {
+                max = f[i];
+            }
+        }
+        float lightHeight = max - min;
+        //std::cout << "\n" << max << " - " << min << " " << lightHeight << "\n";
+        
+        // not the real center, but good guess
+        testOrthoCenter = nearCenter;
+        testOrthoCenter.addMul(cam.getFront(), closeFarClip * 0.5f);
+
+        if(ortho) {
+            worldProj.setToIdentity();
+            worldProj.set(0, 2.0f / lightWidth);
+            worldProj.set(5, 2.0f / lightHeight);
+            worldProj.set(10, -2.0f / (farClip - nearClip));
+        }
+
         if(once) {
             worldShadowProj.setToIdentity();
-            worldShadowProj.set(0, 2.0f / (10.0f * aspect));
-            worldShadowProj.set(5, 2.0f / (10.0f));
+            worldShadowProj.set(0, 2.0f / lightWidth);
+            worldShadowProj.set(5, 2.0f / lightHeight);
             worldShadowProj.set(10, -2.0f / (farClip - nearClip));
         }
     }
 
-    void updateWorldView(float lag, Camera& cam) {
-        cam.update(lag);
+    void updateWorldView(Camera& cam) {
         Vector right = cam.getRight();
         Vector up = cam.getUp();
         Vector back = cam.getBack();
         Vector pos = cam.getPosition();
 
+        if(ortho) {
+            right.set(0.939693f, 0.0f, -0.34202f);
+            back.set(0.280166f, 0.573576f, 0.769751f);
+            up.set(-0.196175f, 0.819152f, -0.538986f);
+            pos = testOrthoCenter;
+        }
+
         worldView.set(0, right.getX());
         worldView.set(1, up.getX());
         worldView.set(2, back.getX());
@@ -127,27 +247,27 @@ struct Shaders {
         worldView.set(13, up.dotInverse(pos));
         worldView.set(14, back.dotInverse(pos));
 
-        if(once) {
-            // lengthAngle = 20; widthAngle = 35;
-            right.set(0.939693f, 0.0f, -0.34202f);
-            back.set(0.280166f, 0.573576f, 0.769751f);
-            up.set(-0.196175f, 0.819152f, -0.538986f);
-            pos.set(0.0f, 2.5f, 0.0f);
-
-            once = false;
-            worldShadowView.set(0, right.getX());
-            worldShadowView.set(1, up.getX());
-            worldShadowView.set(2, back.getX());
-            worldShadowView.set(4, right.getY());
-            worldShadowView.set(5, up.getY());
-            worldShadowView.set(6, back.getY());
-            worldShadowView.set(8, right.getZ());
-            worldShadowView.set(9, up.getZ());
-            worldShadowView.set(10, back.getZ());
-            worldShadowView.set(12, right.dotInverse(pos));
-            worldShadowView.set(13, up.dotInverse(pos));
-            worldShadowView.set(14, back.dotInverse(pos));
-        }
+        //if(once) {
+        // lengthAngle = 20; widthAngle = 35;
+        right.set(0.939693f, 0.0f, -0.34202f);
+        back.set(0.280166f, 0.573576f, 0.769751f);
+        up.set(-0.196175f, 0.819152f, -0.538986f);
+        pos = testOrthoCenter;
+
+        //once = false;
+        worldShadowView.set(0, right.getX());
+        worldShadowView.set(1, up.getX());
+        worldShadowView.set(2, back.getX());
+        worldShadowView.set(4, right.getY());
+        worldShadowView.set(5, up.getY());
+        worldShadowView.set(6, back.getY());
+        worldShadowView.set(8, right.getZ());
+        worldShadowView.set(9, up.getZ());
+        worldShadowView.set(10, back.getZ());
+        worldShadowView.set(12, right.dotInverse(pos));
+        worldShadowView.set(13, up.dotInverse(pos));
+        worldShadowView.set(14, back.dotInverse(pos));
+        //}
     }
 };
 
@@ -277,9 +397,11 @@ static void tick(InternGame& game) {
     keys.tick();
     mButtons.tick();
     game.game.tick(keys, mButtons, game.cam);
+    if(keys.test5.getDownTime() == 1) {
+        ortho = !ortho;
+    }
     if(keys.test.isDown()) {
-        //useSSAO = !useSSAO;
-        //useSSAO = true;
+        //ortho = !ortho;
         testRadius /= 0.95f;
     }
     if(keys.test2.isDown()) {
@@ -301,8 +423,11 @@ static void renderShadow(float lag, Shaders& shaders, InternGame& game, Framebuf
     shaders.worldShadowProjView = shaders.worldShadowProj;
     shaders.worldShadowProjView.mul(shaders.worldShadowView);
     shaders.shadow.setMatrix("projView", shaders.worldShadowProjView.getValues());
-    
+
+    //glEnable(GL_CULL_FACE);
+    //glCullFace(GL_FRONT);
     game.game.renderWorld(lag, game.model, shaders.shadow);
+    //glCullFace(GL_BACK);
 }
 
 static void renderWorld(float lag, Shaders& shaders, InternGame& game, Framebuffers& fb) {
@@ -404,8 +529,9 @@ static void renderTick(float lag, Shaders& shaders, InternGame& game, Framebuffe
         fb.resize(width, height);
         resize = false;
     }
-    shaders.updateWorldProjection();
-    shaders.updateWorldView(lag, game.cam);
+    game.cam.update(lag);
+    shaders.updateWorldProjection(game.cam);
+    shaders.updateWorldView(game.cam);
 
     renderShadow(lag, shaders, game, fb);
     renderWorld(lag, shaders, game, fb);

+ 2 - 1
client/input/Keys.cpp

@@ -22,7 +22,7 @@ std::ostream& operator<<(std::ostream& os, const Keys::Key& k) {
 
 Keys::Keys() : left(keys[0]), right(keys[1]), up(keys[2]), down(keys[3]), jump(keys[4]), sneak(keys[5]),
 camLeft(keys[6]), camRight(keys[7]), camUp(keys[8]), camDown(keys[9]), test(keys[10]), test2(keys[11]), test3(keys[12]),
-test4(keys[13]) {
+test4(keys[13]), test5(keys[14]) {
     keys[0].glfwKey = GLFW_KEY_A;
     keys[1].glfwKey = GLFW_KEY_D;
     keys[2].glfwKey = GLFW_KEY_W;
@@ -37,6 +37,7 @@ test4(keys[13]) {
     keys[11].glfwKey = GLFW_KEY_Y;
     keys[12].glfwKey = GLFW_KEY_U;
     keys[13].glfwKey = GLFW_KEY_I;
+    keys[14].glfwKey = GLFW_KEY_R;
 }
 
 void Keys::release(int key) {

+ 2 - 1
client/input/Keys.h

@@ -31,7 +31,7 @@ public:
     };
 
 private:
-    Key keys[14];
+    Key keys[15];
 
 public:
     Keys();
@@ -49,6 +49,7 @@ public:
     const Key& test2;
     const Key& test3;
     const Key& test4;
+    const Key& test5;
 
     void release(int key);
     void press(int key);

+ 4 - 0
client/math/Plane.cpp

@@ -19,4 +19,8 @@ void Plane::set(const Vector& va, const Vector& vb, const Vector& vc) {
 
 float Plane::getSignedDistance(float x, float y, float z) const {
     return x * a + y * b + z * c + d;
+}
+
+float Plane::getSignedDistance(const Vector& v) const {
+    return getSignedDistance(v.getX(), v.getY(), v.getZ());
 }

+ 1 - 0
client/math/Plane.h

@@ -9,6 +9,7 @@ public:
 
     void set(const Vector& va, const Vector& vb, const Vector& vc);
     float getSignedDistance(float x, float y, float z) const;
+    float getSignedDistance(const Vector& v) const;
 
 private:
     float a;

+ 2 - 2
client/rendering/Framebuffer.cpp

@@ -13,7 +13,7 @@ Framebuffer::Framebuffer(u32 width, u32 height, u32 mode, int textureCompareFunc
     if(mode & POSITION) {
         glGenTextures(1, &(textures[0]));
         glBindTexture(GL_TEXTURE_2D, textures[0]);
-        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, width, height, 0, GL_RGB, GL_FLOAT, nullptr);
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_FLOAT, nullptr);
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@@ -26,7 +26,7 @@ Framebuffer::Framebuffer(u32 width, u32 height, u32 mode, int textureCompareFunc
     if(mode & NORMAL) {
         glGenTextures(1, &(textures[1]));
         glBindTexture(GL_TEXTURE_2D, textures[1]);
-        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGB, GL_FLOAT, nullptr);
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_FLOAT, nullptr);
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);

+ 4 - 4
resources/shader/worldFragment.fs

@@ -51,11 +51,11 @@ void main(void) {
 
     vec3 pos = varShadow.xyz / varShadow.w;
 
-    float fbias = bias * (1.0 - dot(worldNormal, -light)); 
+    float fbias = bias * (1.0 - max(dot(worldNormal, -light), 0.0)); 
 
     float shadow = 0;
     for(int i = 0; i < sampleAmount; i++) {
-        shadow += float(texture(shadowSamp, pos.xy + vec2(samples[i].x, abs(samples[i].y)) * radius).r + fbias > pos.z);
+        shadow += float(texture(shadowSamp, pos.xy + vec2(samples[i].x, samples[i].y) * radius).r + fbias > pos.z);
     }
     shadow /= sampleAmount;
 
@@ -67,12 +67,12 @@ void main(void) {
     }*/
     //shadow = 1 - exp(-40 * shadow - 0.693147180559945 + 20);
     //shadow = 1 - exp(-shadow);
-    //shadow = float(shadow > 0.05);
+    shadow = float(shadow > 0.05);
 
     worldShadow = shadow;
 
     //worldShadow = textureProj(shadowSamp, varShadow);
-    //float f = 1 - dot(worldNormal, -light);
+    //float f = 1.0 - max(dot(worldNormal, -light), 0.0);
     //worldColor = vec4(f, f, f, 1.0);
     worldColor = texture(samp, varTex);
 }