Browse Source

dynamic shadows

Kajetan Johannes Hammerle 3 years ago
parent
commit
ffebb76cdd
11 changed files with 246 additions and 89 deletions
  1. 166 73
      Game.cpp
  2. 14 0
      resources/background.fs
  3. 15 0
      resources/background.vs
  4. 7 0
      resources/cubes.fs
  5. 9 3
      resources/cubes.gs
  6. 0 0
      resources/cubes.vs
  7. 0 13
      resources/noiceFragment.fs
  8. 12 0
      resources/noise.fs
  9. 0 0
      resources/noise.vs
  10. 13 0
      resources/post.fs
  11. 10 0
      resources/post.vs

+ 166 - 73
Game.cpp

@@ -3,6 +3,7 @@
 #include "Texture3D.h"
 #include "math/Frustum.h"
 #include "rendering/FileTexture.h"
+#include "rendering/Framebuffer.h"
 #include "rendering/Shader.h"
 #include "rendering/VertexBuffer.h"
 #include "rendering/Window.h"
@@ -12,11 +13,16 @@
 #include "utils/Utils.h"
 #include "wrapper/GL.h"
 
+static constexpr float STEP = 1.0f / 31.5f;
+
 static Window window;
 
-static Shader shader;
-static Shader noiceShader;
+static Shader cubeShader;
+static Shader noiseShader;
 static Shader particleShader;
+static Shader backgroundShader;
+static Shader postShader;
+static Framebuffer<1> shadowBuffer;
 static LayeredFramebuffer noiceBuffer;
 static FileTexture bricks;
 static FileTexture bricksBump;
@@ -25,6 +31,12 @@ static VertexBuffer rectangleBuffer;
 static VertexBuffer emptyBuffer;
 static Frustum frustum{60.0f, 0.1f, 1000.0f, window.getSize()};
 
+static Matrix projection;
+static Matrix view;
+static Matrix shadowView;
+static Matrix shadowProjectionView;
+static Matrix model;
+
 static Button up{GLFW_KEY_SPACE, "Up"};
 static Button down{GLFW_KEY_LEFT_SHIFT, "Down"};
 static Button left{GLFW_KEY_A, "left"};
@@ -57,17 +69,17 @@ static Vector3 emitterPos;
 static float emitterAge = 999999.0f;
 static float timeFactor = 1.0f;
 
-static void tickGame() {
+static void tickTimeFactors() {
     if(timeUp.isDown()) {
         timeFactor *= 1.05f;
-        std::cout << timeFactor << "\n";
     }
     if(timeDown.isDown()) {
         timeFactor /= 1.05f;
-        std::cout << timeFactor << "\n";
     }
-
     timeTicks++;
+}
+
+static void tickMovement() {
     oldHeight = height;
     oldPosition = position;
     if(up.isDown()) {
@@ -76,7 +88,7 @@ static void tickGame() {
     if(down.isDown()) {
         height -= 1.0f;
     }
-    const float speed = 1.15f;
+    constexpr float speed = 5.5f;
     if(left.isDown()) {
         position += Vector3(speed, 0.0f, 0.0f);
     }
@@ -89,7 +101,9 @@ static void tickGame() {
     if(back.isDown()) {
         position -= Vector3(0.0f, 0.0f, speed);
     }
+}
 
+static void tickParallaxSettings() {
     if(scaleUp.isDown()) {
         heightScale += 0.005f;
     }
@@ -117,38 +131,53 @@ static void tickGame() {
     }
 }
 
-static void renderGame(float lag) {
-    GL::enableDepthTesting();
+static void tickGame() {
+    tickTimeFactors();
+    tickMovement();
+    tickParallaxSettings();
+}
+
+static void prepareMatrices(float lag) {
+    projection = frustum.updateProjection();
+
+    view.translateTo(Vector3(0.0f, 0.0f, 0.0f));
+    view.translate(Utils::interpolate(oldPosition, position, lag));
+    float h = -32.0f + (oldHeight - height) * lag;
+    view.translateY(h);
+    shadowView.translateTo(Vector3(-32.0f - 180.0f, h, -340.0f));
+
+    shadowProjectionView.translateTo(Vector3(0.0f, 0.0f, 0.0f));
+    shadowProjectionView.scale(0.5f);
+    shadowProjectionView.translate(Vector3(0.5f, 0.5f, 0.5f));
+    shadowProjectionView *= projection;
+    shadowProjectionView *= shadowView;
+}
+
+static void renderNoise() {
     GL::setViewport(64, 64);
-    noiceShader.use();
+    noiseShader.use();
     noiceBuffer.bindAndClear();
-    float step = 1.0f / 31.5f;
-    noiceShader.setFloat("height", oldHeight * step);
+    noiseShader.setFloat("height", oldHeight * STEP);
     for(int i = 0; i < 64; i++) {
-        noiceShader.setFloat("layer", i * step - 1.0f);
+        noiseShader.setFloat("layer", i * STEP - 1.0f);
         noiceBuffer.bindLayer(i);
         rectangleBuffer.draw(6);
     }
+}
 
+static void renderCubes(Matrix& view) {
     GL::setViewport(window.getSize().width, window.getSize().height);
-    shader.use();
-    GL::bindMainFramebuffer();
-    GL::clear();
-    Matrix& proj = frustum.updateProjection();
-    shader.setMatrix("proj", proj.getValues());
-
-    Matrix m;
-    m.translate(Utils::interpolate(oldPosition, position, lag));
-    m.translateY(-32.0f + (oldHeight - height) * lag);
-    shader.setMatrix("view", m.getValues());
-    shader.setFloat("height", oldHeight * step * 0.5f);
-
-    shader.setVector("viewPos", -position + Vector3(0.0f, 32.0f, 0.0f));
-    shader.setVector("lightPos", Vector3());
-    shader.setFloat("heightScale", heightScale);
-    shader.setInt("steps", steps);
-    shader.setInt("fineSteps", fineSteps);
-    shader.setInt("kajetan", mode);
+    cubeShader.use();
+    cubeShader.setMatrix("proj", projection.getValues());
+    cubeShader.setMatrix("view", view.getValues());
+    cubeShader.setMatrix("shadow", shadowProjectionView.getValues());
+    cubeShader.setFloat("height", oldHeight * STEP * 0.5f);
+    cubeShader.setVector("viewPos", -position + Vector3(0.0f, 32.0f, 0.0f));
+    cubeShader.setVector("lightPos", Vector3());
+    cubeShader.setFloat("heightScale", heightScale);
+    cubeShader.setInt("steps", steps);
+    cubeShader.setInt("fineSteps", fineSteps);
+    cubeShader.setInt("kajetan", mode);
 
     if(toggle.isDown()) {
         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
@@ -157,12 +186,60 @@ static void renderGame(float lag) {
     bricks.bindTo(1);
     bricksBump.bindTo(2);
     bricksNormal.bindTo(3);
-    emptyBuffer.drawPoints(64 * 64 * 64);
+    shadowBuffer.bindTextureTo(0, 4);
+
+    for(int i = 0; i < 3; i++) {
+        model.translateTo(Vector3(80.0f * i, 0.0f, 0.0f));
+        cubeShader.setMatrix("model", model.getValues());
+        emptyBuffer.drawPoints(64 * 64 * 64);
+    }
     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+}
 
+static void pickParticleCenter() {
+    if(!primaryMouse.wasReleased()) {
+        return;
+    }
+    noiceBuffer.bindTextureTo(0);
+    static float buffer[64][64][64];
+    glGetTexImage(GL_TEXTURE_3D, 0, GL_RED, GL_FLOAT, buffer);
+
+    float hWidth = window.getSize().width * 0.5f;
+    float hHeight = window.getSize().height * 0.5f;
+
+    float x = (window.buttons.getMouseX() - hWidth) / hWidth;
+    float y = -(window.buttons.getMouseY() - hHeight) / hHeight;
+
+    float aspect = hWidth / hHeight;
+    float tan = tanf((0.5f * frustum.fieldOfView) * M_PI / 180.0f);
+    float q = 1.0f / tan;
+
+    Vector3 direction(x / (q / aspect), y / q, 1.0f);
+    direction[2] = -direction[2];
+    direction.normalize();
+
+    Vector3 pos = -position;
+    pos[1] = 32.0f;
+    pos[1] = 32.0f;
+    for(int i = 0; i < 150; i++) {
+        int x = pos[0] + 0.5f;
+        int y = pos[1] + 0.5f;
+        int z = pos[2] + 0.5f;
+        if(x >= 0 && x < 64 && y >= 0 && y < 64 && z >= 0 && z < 64 &&
+           buffer[x][y][z] > 0.5f) {
+            emitterPos = pos + Vector3(0.0f, height, 0.0f);
+            emitterAge = timeTicks;
+            break;
+        }
+        pos += direction;
+    }
+}
+
+static void renderParticles(float lag) {
     glPointSize(5.0f);
     particleShader.use();
-    particleShader.setMatrix("proj", proj.getValues());
+    particleShader.setMatrix("proj", projection.getValues());
+    Matrix m;
     m.translateTo(Utils::interpolate(oldPosition, position, lag));
     m.translateY(-32.0f - (oldHeight + (height - oldHeight) * lag));
     particleShader.setMatrix("view", m.getValues());
@@ -171,41 +248,7 @@ static void renderGame(float lag) {
     GL::enableBlending();
     glDepthMask(false);
 
-    if(primaryMouse.wasReleased()) {
-        noiceBuffer.bindTextureTo(0);
-        static float buffer[64][64][64];
-        glGetTexImage(GL_TEXTURE_3D, 0, GL_RED, GL_FLOAT, buffer);
-
-        float hWidth = window.getSize().width * 0.5f;
-        float hHeight = window.getSize().height * 0.5f;
-
-        float x = (window.buttons.getMouseX() - hWidth) / hWidth;
-        float y = -(window.buttons.getMouseY() - hHeight) / hHeight;
-
-        float aspect = hWidth / hHeight;
-        float tan = tanf((0.5f * frustum.fieldOfView) * M_PI / 180.0f);
-        float q = 1.0f / tan;
-
-        Vector3 direction(x / (q / aspect), y / q, 1.0f);
-        direction[2] = -direction[2];
-        direction.normalize();
-
-        Vector3 pos = -position;
-        pos[1] = 32.0f;
-        pos[1] = 32.0f;
-        for(int i = 0; i < 150; i++) {
-            int x = pos[0] + 0.5f;
-            int y = pos[1] + 0.5f;
-            int z = pos[2] + 0.5f;
-            if(x >= 0 && x < 64 && y >= 0 && y < 64 && z >= 0 && z < 64 &&
-               buffer[x][y][z] > 0.5f) {
-                emitterPos = pos + Vector3(0.0f, height, 0.0f);
-                emitterAge = timeTicks;
-                break;
-            }
-            pos += direction;
-        }
-    }
+    pickParticleCenter();
     particleShader.setFloat("timeFactor", timeFactor);
 
     particleShader.setVector("position", emitterPos);
@@ -236,6 +279,40 @@ static void renderGame(float lag) {
     GL::disableBlending();
 }
 
+static void renderBackground(Matrix& view) {
+    backgroundShader.use();
+    shadowBuffer.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));
+    backgroundShader.setMatrix("model", model.getValues());
+    backgroundShader.setMatrix("shadow", shadowProjectionView.getValues());
+    rectangleBuffer.draw(6);
+}
+
+static void renderGame(float lag) {
+    GL::enableDepthTesting();
+    prepareMatrices(lag);
+    renderNoise();
+
+    shadowBuffer.bindAndClear();
+    renderCubes(shadowView);
+    renderBackground(shadowView);
+
+    GL::bindMainFramebuffer();
+    GL::clear();
+
+    renderCubes(view);
+    renderBackground(view);
+    renderParticles(lag);
+
+    // postShader.use();
+    // shadowBuffer.bindTextureTo(0, 0);
+    // rectangleBuffer.draw(6);
+}
+
 void Game::init() {
     WindowOptions options(4, 0, {1024, 620}, false, "test");
     Error error = window.open(options);
@@ -243,14 +320,14 @@ void Game::init() {
         error.message.printLine();
         return;
     }
-    error = shader.compile("resources/vertex.vs", "resources/geometry.gs",
-                           "resources/fragment.fs");
+    error = cubeShader.compile("resources/cubes.vs", "resources/cubes.gs",
+                               "resources/cubes.fs");
     if(error.has()) {
         error.message.printLine();
         return;
     }
-    error = noiceShader.compile("resources/noiceVertex.vs", nullptr,
-                                "resources/noiceFragment.fs");
+    error = noiseShader.compile("resources/noise.vs", nullptr,
+                                "resources/noise.fs");
     if(error.has()) {
         error.message.printLine();
         return;
@@ -262,6 +339,23 @@ void Game::init() {
         error.message.printLine();
         return;
     }
+    error = backgroundShader.compile("resources/background.vs", nullptr,
+                                     "resources/background.fs");
+    if(error.has()) {
+        error.message.printLine();
+        return;
+    }
+    error =
+        postShader.compile("resources/post.vs", nullptr, "resources/post.fs");
+    if(error.has()) {
+        error.message.printLine();
+        return;
+    }
+    error = shadowBuffer.init(window.getSize(), TextureFormat::depth32());
+    if(error.has()) {
+        error.message.printLine();
+        return;
+    }
     error = bricks.load("resources/bricks.png", 0);
     if(error.has()) {
         error.message.printLine();
@@ -277,7 +371,6 @@ void Game::init() {
         error.message.printLine();
         return;
     }
-
     noiceBuffer.init(64, 64, 64);
     window.buttons.add(up);
     window.buttons.add(down);

+ 14 - 0
resources/background.fs

@@ -0,0 +1,14 @@
+#version 430
+
+layout (binding = 0) uniform sampler2D depthSamp;
+
+in vec4 varShadowPosition;
+
+out vec4 color;
+
+void main(void) {
+    vec3 pos = varShadowPosition.xyz / varShadowPosition.w;
+    float shadow = float(texture(depthSamp, pos.xy).r + 0.000001 > pos.z);
+    shadow = shadow * 0.6 + 0.4;
+    color = vec4(0.8, 0.8, 0.8, 1.0) * shadow;
+}

+ 15 - 0
resources/background.vs

@@ -0,0 +1,15 @@
+#version 430
+
+layout (location = 0) in vec2 position;
+
+uniform mat4 proj;
+uniform mat4 view;
+uniform mat4 model;
+uniform mat4 shadow;
+
+out vec4 varShadowPosition;
+
+void main(void) { 
+    gl_Position = proj * view * model * vec4(position, 0.0, 1.0);
+    varShadowPosition = shadow * model * vec4(position, 0.0, 1.0);
+}

+ 7 - 0
resources/fragment.fs → resources/cubes.fs

@@ -4,6 +4,7 @@ layout (binding = 0) uniform sampler3D noiseSamp;
 layout (binding = 1) uniform sampler2D textureSamp;
 layout (binding = 2) uniform sampler2D bumpSamp;
 layout (binding = 3) uniform sampler2D normalSamp;
+layout (binding = 4) uniform sampler2D depthSamp;
 
 uniform float height;
 uniform vec3 viewPos;
@@ -13,6 +14,7 @@ uniform float heightScale;
 uniform bool kajetan;
 
 in vec3 varPositionG;
+in vec4 varShadowPositionG;
 in vec2 varTextureG;
 
 out vec4 color;
@@ -67,4 +69,9 @@ void main(void) {
     normal = normalize(normal * 2.0 - 1.0);
     float l = max(dot(-light, normal), 0.0) * 0.7 + 0.3;
     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);
+    shadow = shadow * 0.6 + 0.4;
+    color *= shadow;
 }

+ 9 - 3
resources/geometry.gs → resources/cubes.gs

@@ -5,11 +5,14 @@ layout (triangle_strip, max_vertices = 12) out;
 
 uniform mat4 proj;
 uniform mat4 view;
+uniform mat4 model;
+uniform mat4 shadow;
 
 in vec3 varTexture[];
 in int varIndex[];
 
 out vec3 varPositionG;
+out vec4 varShadowPositionG;
 out vec2 varTextureG;
 
 vec3 vectors[13] = {
@@ -173,18 +176,21 @@ void main(void) {
         vec3 ac = c - a;
         vec3 normal = normalize(cross(ab, ac));
 
-        gl_Position = proj * view * vec4(a, 1.0);
+        gl_Position = proj * view * model * vec4(a, 1.0);
         varPositionG = a;
+        varShadowPositionG = shadow * model * vec4(a, 1.0);
         varTextureG = ta;
         EmitVertex();
 
-        gl_Position = proj * view * vec4(b, 1.0);
+        gl_Position = proj * view * model * vec4(b, 1.0);
         varPositionG = b;
+        varShadowPositionG = shadow * model * vec4(b, 1.0);
         varTextureG = tb;
         EmitVertex();
 
-        gl_Position = proj * view * vec4(c, 1.0);
+        gl_Position = proj * view * model * vec4(c, 1.0);
         varPositionG = c;
+        varShadowPositionG = shadow * model * vec4(c, 1.0);
         varTextureG = tc;
         EmitVertex();
 

+ 0 - 0
resources/vertex.vs → resources/cubes.vs


+ 0 - 13
resources/noiceFragment.fs

@@ -1,13 +0,0 @@
-#version 430
-
-in vec3 varPosition;
-
-out float noice;
-
-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);
-    noice = 1.0;
-}

+ 12 - 0
resources/noise.fs

@@ -0,0 +1,12 @@
+#version 430
+
+in vec3 varPosition;
+
+out float noice;
+
+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);
+}

+ 0 - 0
resources/noiceVertex.vs → resources/noise.vs


+ 13 - 0
resources/post.fs

@@ -0,0 +1,13 @@
+#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);
+}

+ 10 - 0
resources/post.vs

@@ -0,0 +1,10 @@
+#version 430
+
+layout (location = 0) in vec2 position;
+
+out vec2 varTex;
+
+void main(void) { 
+    gl_Position = vec4(position, 0.0, 1.0);
+    varTex = (position + vec2(1.0, 1.0)) * 0.5;
+}