Browse Source

variance shadow mapping

Kajetan Johannes Hammerle 3 years ago
parent
commit
f1f4f64bc8
7 changed files with 98 additions and 27 deletions
  1. 20 10
      Game.cpp
  2. 25 1
      resources/background.fs
  3. 24 0
      resources/blur.fs
  4. 0 0
      resources/blur.vs
  5. 27 1
      resources/cubes.fs
  6. 2 2
      resources/noise.fs
  7. 0 13
      resources/post.fs

+ 20 - 10
Game.cpp

@@ -21,8 +21,9 @@ static Shader cubeShader;
 static Shader noiseShader;
 static Shader particleShader;
 static Shader backgroundShader;
-static Shader postShader;
+static Shader blurShader;
 static Framebuffer<1> shadowBuffer;
+static Framebuffer<1> blurShadowBuffer;
 static LayeredFramebuffer noiceBuffer;
 static FileTexture bricks;
 static FileTexture bricksBump;
@@ -88,7 +89,7 @@ static void tickMovement() {
     if(down.isDown()) {
         height -= 1.0f;
     }
-    constexpr float speed = 5.5f;
+    constexpr float speed = 3.5f;
     if(left.isDown()) {
         position += Vector3(speed, 0.0f, 0.0f);
     }
@@ -186,7 +187,8 @@ static void renderCubes(Matrix& view) {
     bricks.bindTo(1);
     bricksBump.bindTo(2);
     bricksNormal.bindTo(3);
-    shadowBuffer.bindTextureTo(0, 4);
+    blurShadowBuffer.bindTextureTo(0, 4);
+    shadowBuffer.bindTextureTo(0, 5);
 
     for(int i = 0; i < 3; i++) {
         model.translateTo(Vector3(80.0f * i, 0.0f, 0.0f));
@@ -281,12 +283,13 @@ static void renderParticles(float lag) {
 
 static void renderBackground(Matrix& view) {
     backgroundShader.use();
-    shadowBuffer.bindTextureTo(0, 0);
+    blurShadowBuffer.bindTextureTo(0, 0);
     backgroundShader.setMatrix("proj", frustum.updateProjection().getValues());
     backgroundShader.setMatrix("view", view.getValues());
     model.translateTo(Vector3(0.0f, 0.0f, 0.0f));
     model.scale(Vector3(260.0f, 120.0f, 1.0f));
     model.translate(Vector3(0.0f, 20.0f, -200.0f));
+    model.rotateX(-5.0f);
     backgroundShader.setMatrix("model", model.getValues());
     backgroundShader.setMatrix("shadow", shadowProjectionView.getValues());
     rectangleBuffer.draw(6);
@@ -301,16 +304,17 @@ static void renderGame(float lag) {
     renderCubes(shadowView);
     renderBackground(shadowView);
 
+    blurShader.use();
+    shadowBuffer.bindTextureTo(0, 0);
+    blurShadowBuffer.bindAndClear();
+    rectangleBuffer.draw(6);
+
     GL::bindMainFramebuffer();
     GL::clear();
 
     renderCubes(view);
     renderBackground(view);
     renderParticles(lag);
-
-    // postShader.use();
-    // shadowBuffer.bindTextureTo(0, 0);
-    // rectangleBuffer.draw(6);
 }
 
 void Game::init() {
@@ -346,12 +350,18 @@ void Game::init() {
         return;
     }
     error =
-        postShader.compile("resources/post.vs", nullptr, "resources/post.fs");
+        blurShader.compile("resources/blur.vs", nullptr, "resources/blur.fs");
+    if(error.has()) {
+        error.message.printLine();
+        return;
+    }
+    error = shadowBuffer.init(window.getSize(), TextureFormat::depth32(true));
     if(error.has()) {
         error.message.printLine();
         return;
     }
-    error = shadowBuffer.init(window.getSize(), TextureFormat::depth32());
+    error = blurShadowBuffer.init(window.getSize(),
+                                  TextureFormat::float32(2, true));
     if(error.has()) {
         error.message.printLine();
         return;

+ 25 - 1
resources/background.fs

@@ -2,13 +2,37 @@
 
 layout (binding = 0) uniform sampler2D depthSamp;
 
+const float minVariance = 4.096e-06;
+const float cutoff = 0.998;
+
 in vec4 varShadowPosition;
 
 out vec4 color;
 
+float chebyshevUpperBound(vec2 moments, float t) {   
+    float variance = moments.y - (moments.x * moments.x);   
+    variance = max(variance, minVariance);    
+    float d = t - moments.x;   
+    float pMax = variance / (variance + d * d);   
+    return max(pMax, float(t < moments.x)); 
+} 
+
+float linstep(float from, float to, float v) {   
+    return clamp((v - from) / (to - from), 0.0, 1.0); 
+} 
+    
+float reduceLightBleeding(float light, float Amount) {     
+    return linstep(Amount, 1.0, light); 
+} 
+
+float getShadow(vec2 varTex, float distanceToLight) {   
+    vec2 Moments = texture(depthSamp, varTex).xy;    
+    return reduceLightBleeding(chebyshevUpperBound(Moments, distanceToLight), cutoff); 
+}
+
 void main(void) {
     vec3 pos = varShadowPosition.xyz / varShadowPosition.w;
-    float shadow = float(texture(depthSamp, pos.xy).r + 0.000001 > pos.z);
+    float shadow = getShadow(pos.xy, pos.z);
     shadow = shadow * 0.6 + 0.4;
     color = vec4(0.8, 0.8, 0.8, 1.0) * shadow;
 }

+ 24 - 0
resources/blur.fs

@@ -0,0 +1,24 @@
+#version 430
+
+layout (binding = 0) uniform sampler2D depthSamp;
+
+in vec2 varTex;
+
+out vec2 color;
+
+void main(void) {
+    vec2 sum = vec2(0.0, 0.0);
+
+    vec2 texelSize = 1.0 / vec2(textureSize(depthSamp, 0));
+    const int radius = 4;
+    for(int x = -radius; x < radius; x++) {
+        for(int y = -radius; y < radius; y++) {
+            vec2 offset = vec2(x, y) * texelSize;
+            float depth = texture(depthSamp, varTex + offset).r;
+            sum += vec2(depth, depth * depth);
+        }
+    }
+    sum /= (radius * radius * 4);
+
+    color = sum;
+}

+ 0 - 0
resources/post.vs → resources/blur.vs


+ 27 - 1
resources/cubes.fs

@@ -5,6 +5,7 @@ layout (binding = 1) uniform sampler2D textureSamp;
 layout (binding = 2) uniform sampler2D bumpSamp;
 layout (binding = 3) uniform sampler2D normalSamp;
 layout (binding = 4) uniform sampler2D depthSamp;
+layout (binding = 5) uniform sampler2D depthSamp2;
 
 uniform float height;
 uniform vec3 viewPos;
@@ -21,6 +22,30 @@ out vec4 color;
 
 const vec3 light = vec3(-0.746, -0.373, -0.224);
 
+const float minVariance = 1.84582e-7;
+const float cutoff = 0.9999;
+
+float chebyshevUpperBound(vec2 moments, float t) {   
+    float variance = moments.y - (moments.x * moments.x);   
+    variance = max(variance, minVariance);    
+    float d = t - moments.x;   
+    float pMax = variance / (variance + d * d);   
+    return max(pMax, float(t < moments.x)); 
+} 
+
+float linstep(float from, float to, float v) {   
+    return clamp((v - from) / (to - from), 0.0, 1.0); 
+} 
+    
+float reduceLightBleeding(float light, float Amount) {     
+    return linstep(Amount, 1.0, light); 
+} 
+
+float getShadow(vec2 varTex, float distanceToLight) {   
+    vec2 Moments = texture(depthSamp, varTex).xy;    
+    return reduceLightBleeding(chebyshevUpperBound(Moments, distanceToLight), cutoff); 
+}
+
 void main(void) {
     vec2 tex = varTextureG + vec2(0.0, height);
     vec2 eye = -normalize(viewPos - varPositionG).xy * heightScale;
@@ -71,7 +96,8 @@ void main(void) {
     color = vec4(texture(textureSamp, tex).xyz * l, 1.0);
 
     vec3 pos = varShadowPositionG.xyz / varShadowPositionG.w;
-    float shadow = float(texture(depthSamp, pos.xy).r + 0.000001 > pos.z);
+    float shadow = getShadow(pos.xy, pos.z);
+    //float shadow = float(texture(depthSamp2, pos.xy).r + 0.00001 > pos.z);
     shadow = shadow * 0.6 + 0.4;
     color *= shadow;
 }

+ 2 - 2
resources/noise.fs

@@ -2,11 +2,11 @@
 
 in vec3 varPosition;
 
-out float noice;
+out float noise;
 
 void main(void) {
     float sinX = sin(varPosition.x * 5.8905);
     float cosY = cos(varPosition.y * 5.8905);
     float cosZ = cos(varPosition.z * 5.8905);
-    noice = (sinX * sinX + cosY * cosY + cosZ * cosZ) * (1.0f / 3.0f);
+    noise = (sinX * sinX + cosY * cosY + cosZ * cosZ) * (1.0f / 3.0f);
 }

+ 0 - 13
resources/post.fs

@@ -1,13 +0,0 @@
-#version 430
-
-layout (binding = 0) uniform sampler2D samp;
-
-in vec2 varTex;
-
-out vec4 color;
-
-void main(void) {
-    float a = texture(samp, varTex).r;
-    float f = 1 - pow(a, 1000);
-    color = vec4(f, f, f, 1.0);
-}