Browse Source

experimental shadow mapping

Kajetan Johannes Hammerle 4 years ago
parent
commit
223fdcf764

+ 1 - 0
client/Game.cpp

@@ -17,6 +17,7 @@ Game::Game() : lengthAngle(0.0f), widthAngle(0.0f), texture("resources/textures.
             }
         }
     }
+    addCube(-3, -1, -10);
     m.build();
 }
 

+ 69 - 4
client/GameClient.cpp

@@ -58,6 +58,7 @@ struct Shaders
         world("resources/shader/worldVertex.vs", "resources/shader/worldFragment.fs"),
         ssao("resources/shader/ssaoVertex.vs", "resources/shader/ssaoFragment.fs"),
         ssaoBlur("resources/shader/ssaoBlurVertex.vs", "resources/shader/ssaoBlurFragment.fs"),
+        shadow("resources/shader/worldShadowVertex.vs", "resources/shader/worldShadowFragment.fs"),
         postWorld("resources/shader/worldPostVertex.vs", "resources/shader/worldPostFragment.fs"),
         text("resources/shader/textVertex.vs", "resources/shader/textFragment.fs")
     {
@@ -66,8 +67,10 @@ struct Shaders
     Shader world;
     Shader ssao;
     Shader ssaoBlur;
+    Shader shadow;
     Shader postWorld;
     Shader text;
+    bool once = true;
     
     float worldProj[16] = 
     {
@@ -85,9 +88,26 @@ struct Shaders
         0.0f, 0.0f, 0.0f, 1.0f
     };
     
+    float worldShadowProj[16] = 
+    {
+        1.0f, 0.0f, 0.0f, 0.0f,
+        0.0f, 1.0f, 0.0f, 0.0f,
+        0.0f, 0.0f, 1.0f, -1.0f,
+        0.0f, 0.0f, 1.0, 0.0f
+    };
+    
+    float worldShadowView[16]= 
+    {
+        1.0f, 0.0f, 0.0f, 0.0f,
+        0.0f, 1.0f, 0.0f, 0.0f,
+        0.0f, 0.0f, 1.0f, 0.0f,
+        0.0f, 0.0f, 0.0f, 1.0f
+    };
+    
     bool isValid() const
     {
-        return world.isValid() && ssao.isValid() && ssaoBlur.isValid() && postWorld.isValid() && text.isValid();
+        return world.isValid() && ssao.isValid() && ssaoBlur.isValid() && 
+                shadow.isValid() && postWorld.isValid() && text.isValid();
     }
     
     void updateWorldProjection()
@@ -99,6 +119,14 @@ struct Shaders
         worldProj[5] = q;
         worldProj[10] = (nearClip + farClip) / (nearClip - farClip);
         worldProj[14] = (2.0f * nearClip * farClip) / (nearClip - farClip);
+        
+        if(once)
+        {
+            worldShadowProj[0] = q / aspect;
+            worldShadowProj[5] = q;
+            worldShadowProj[10] = (nearClip + farClip) / (nearClip - farClip);
+            worldShadowProj[14] = (2.0f * nearClip * farClip) / (nearClip - farClip);
+        }
     }
 
     void updateWorldView(float lag, Camera& cam)
@@ -120,14 +148,32 @@ struct Shaders
         worldView[12] = right.dotInverse(pos);
         worldView[13] = up.dotInverse(pos);
         worldView[14] = back.dotInverse(pos);
+        
+        if(once)
+        {
+            once = false;
+            worldShadowView[0] = right.getX();
+            worldShadowView[1] = up.getX();
+            worldShadowView[2] = back.getX();
+            worldShadowView[4] = right.getY();
+            worldShadowView[5] = up.getY();
+            worldShadowView[6] = back.getY();
+            worldShadowView[8] = right.getZ();
+            worldShadowView[9] = up.getZ();
+            worldShadowView[10] = back.getZ();
+            worldShadowView[12] = right.dotInverse(pos);
+            worldShadowView[13] = up.dotInverse(pos);
+            worldShadowView[14] = back.dotInverse(pos);
+        }
     }
 };
 
 struct Framebuffers
 {
     Framebuffers(u32 w, u32 h) : world(w, h, Framebuffer::POSITION | 
-        Framebuffer::NORMAL | Framebuffer::COLOR | Framebuffer::DEPTH24_STENCIL8),
-        ssao(w, h, Framebuffer::RED), ssaoBlur(w, h, Framebuffer::RED)
+        Framebuffer::NORMAL | Framebuffer::COLOR | Framebuffer::RED | Framebuffer::DEPTH24_STENCIL8),
+        ssao(w, h, Framebuffer::RED), ssaoBlur(w, h, Framebuffer::RED),
+        shadow(w, h, Framebuffer::DEPTH24_STENCIL8)
     {
     }
     
@@ -136,6 +182,7 @@ struct Framebuffers
         world.resize(w, h);
         ssao.resize(w, h);
         ssaoBlur.resize(w, h);
+        shadow.resize(w, h);
     }
     
     bool isValid() const
@@ -146,6 +193,7 @@ struct Framebuffers
     Framebuffer world;
     Framebuffer ssao;
     Framebuffer ssaoBlur;
+    Framebuffer shadow;
 };
 
 struct InternGame
@@ -275,15 +323,31 @@ static void tick(InternGame& game)
     mButtons.postTick();
 }
 
+static void renderShadow(float lag, Shaders& shaders, InternGame& game, Framebuffers& fb)
+{
+    fb.shadow.bind();
+    glEnable(GL_DEPTH_TEST);
+    shaders.shadow.use();
+    shaders.shadow.setMatrix("proj", shaders.worldShadowProj);
+    shaders.shadow.setMatrix("view", shaders.worldShadowView);
+    glEnable(GL_POLYGON_OFFSET_FILL);
+    glPolygonOffset(2.0f, 4.0f);
+    game.game.renderWorld(lag, game.model, shaders.shadow);
+    glDisable(GL_POLYGON_OFFSET_FILL);
+}
+
 static void renderWorld(float lag, Shaders& shaders, InternGame& game, Framebuffers& fb)
 {
     fb.world.bind();
     glEnable(GL_DEPTH_TEST);
     shaders.world.use();
+    shaders.world.setMatrix("projShadow", shaders.worldShadowProj);
+    shaders.world.setMatrix("viewShadow", shaders.worldShadowView);
     shaders.world.setMatrix("proj", shaders.worldProj);
     shaders.world.setMatrix("view", shaders.worldView);
     game.model.clear();
     shaders.world.setMatrix("model", game.model.get().getValues());
+    fb.shadow.bindDepthTexture(1);
     game.game.renderWorld(lag, game.model, shaders.world);
 }
 
@@ -305,7 +369,6 @@ static void renderSSAO(Shaders& shaders, InternGame& game, Framebuffers& fb)
     // ssao blur
     shaders.ssaoBlur.use();
     fb.ssao.bindRedTexture(0);
-    fb.world.bindColorTexture(1);
     fb.ssaoBlur.bind();
     game.rectangle.draw();
 }
@@ -317,6 +380,7 @@ static void renderPostWorld(Shaders& shaders, InternGame& game, Framebuffers& fb
     shaders.postWorld.use();
     fb.world.bindColorTexture(0);
     fb.ssaoBlur.bindRedTexture(1);
+    fb.world.bindRedTexture(2);
     shaders.postWorld.setInt("useSSAO", useSSAO);
     game.rectangle.draw();
 }
@@ -352,6 +416,7 @@ static void renderTick(float lag, Shaders& shaders, InternGame& game, Framebuffe
     shaders.updateWorldProjection();
     shaders.updateWorldView(lag, game.cam);
     
+    renderShadow(lag, shaders, game, fb);
     renderWorld(lag, shaders, game, fb);
     if(useSSAO)
     {

+ 0 - 1
resources/shader/ssaoBlurFragment.fs

@@ -1,7 +1,6 @@
 #version 430
 
 layout (binding = 0) uniform sampler2D ssaoSamp;
-layout (binding = 1) uniform sampler2D test;
 
 in vec2 varTex;
 out float color;

+ 5 - 0
resources/shader/worldFragment.fs

@@ -3,8 +3,10 @@
 layout (location = 0) out vec3 worldPosition;
 layout (location = 1) out vec3 worldNormal;
 layout (location = 2) out vec4 worldColor;
+layout (location = 3) out float worldShadow;
 
 layout (binding = 0) uniform sampler2D samp;
+layout (binding = 1) uniform sampler2D shadowSamp;
 
 uniform mat4 proj;
 uniform mat4 view;
@@ -13,10 +15,13 @@ uniform mat4 model;
 in vec3 varPosition;
 in vec2 varTex;
 in vec3 varNormal;
+in vec4 varShadow;
 
 void main(void)
 {
     worldPosition = varPosition;
     worldNormal = normalize(varNormal);
+
+    worldShadow = float(varShadow.z < texture(shadowSamp, varShadow.xy).x);
     worldColor = texture(samp, varTex);
 }

+ 16 - 0
resources/shader/worldPostFragment.fs

@@ -2,6 +2,7 @@
 
 layout (binding = 0) uniform sampler2D colorSamp;
 layout (binding = 1) uniform sampler2D ssaoSamp;
+layout (binding = 2) uniform sampler2D shadowSamp;
 
 uniform bool useSSAO;
 
@@ -19,4 +20,19 @@ void main()
     {
         color = vec4(texture(colorSamp, varTex).xyz, 1.0);
     }
+
+    vec2 texelSize = 1.0 / vec2(textureSize(shadowSamp, 0));
+    float result = 0.0;
+    const int radius = 5;
+    for(int x = -radius; x < radius; x++) 
+    {
+        for(int y = -radius; y < radius; y++) 
+        {
+            vec2 offset = vec2(float(x), float(y)) * texelSize;
+            result += texture(shadowSamp, varTex + offset).r;
+        }
+    }
+    result /= (radius * radius * 4);
+    result = result * 0.5 + 0.5;
+    color *= result;
 }  

+ 6 - 5
resources/shader/worldShadowVertex.vs

@@ -1,12 +1,13 @@
 #version 430
 
 layout (location = 0) in vec3 position;
+layout (location = 1) in vec2 tex;
+layout (location = 2) in vec3 normal;
 
-uniform mat4 projMatrix;
-uniform mat4 viewMatrix;
-uniform mat4 modelMatrix;
+uniform mat4 proj;
+uniform mat4 view;
 
 void main(void)
 { 
-    gl_Position = projMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);
-}
+    gl_Position = proj * view * vec4(position, 1.0);
+}

+ 8 - 0
resources/shader/worldVertex.vs

@@ -8,9 +8,13 @@ uniform mat4 proj;
 uniform mat4 view;
 uniform mat4 model;
 
+uniform mat4 projShadow;
+uniform mat4 viewShadow;
+
 out vec3 varPosition;
 out vec2 varTex;
 out vec3 varNormal;
+out vec4 varShadow;
 
 void main(void)
 { 
@@ -23,4 +27,8 @@ void main(void)
     vec4 worldPos = view * model * vec4(position, 1.0);
     varPosition = worldPos.xyz;
     gl_Position = proj * worldPos;
+
+    varShadow = projShadow * viewShadow * vec4(position, 1.0);
+    varShadow /= varShadow.w;
+    varShadow = varShadow * 0.5 + 0.5;
 }