From 867b1e4a60a6b5e7b4fd14b11508a63374809ad3 Mon Sep 17 00:00:00 2001 From: Faerbit Date: Thu, 4 Dec 2014 17:19:58 +0100 Subject: [PATCH] Implemented cascaded shadow mapping. --- Shader/phong.fsh | 53 ++++++++++++++++++++--------- Shader/phong.vsh | 12 +++++-- graphics.cc | 87 +++++++++++++++++++++++++++++++++++++----------- graphics.hh | 8 +++-- 4 files changed, 119 insertions(+), 41 deletions(-) diff --git a/Shader/phong.fsh b/Shader/phong.fsh index 3d9d719..9d78f8f 100644 --- a/Shader/phong.fsh +++ b/Shader/phong.fsh @@ -3,12 +3,16 @@ in vec3 vNormal; in vec2 vTexCoord; in vec4 fragPosition; -in vec4 shadowCoord; +in vec4 shadowCoord_near; +in vec4 shadowCoord_middle; +in vec4 shadowCoord_far; out vec4 oColor; uniform sampler2D uTexture; -uniform sampler2DShadow shadowMap; +uniform sampler2DShadow shadowMap_near; +uniform sampler2DShadow shadowMap_middle; +uniform sampler2DShadow shadowMap_far; uniform vec3 ambientColor; uniform float ambientFactor; uniform float diffuseFactor; @@ -45,6 +49,25 @@ vec2 poissonDisk[16] = vec2[]( vec2( 0.14383161, -0.14100790 ) ); +float sampleShadow(sampler2DShadow shadowMap, vec4 shadowCoord) { + float visibility = 1.0; + float bias = 0.001*tan(acos(clamp(dot(vNormal, -directionalLightVector), 0.0, 1.0))); + bias = clamp(bias, 0.0, 0.01); + for (int i=0; i<4; i++) { + visibility -= directionalIntensity/16*(1.0-texture(shadowMap, vec3(shadowCoord.xy + poissonDisk[i]/700.0, (shadowCoord.z - bias)/shadowCoord.w))); + } + if (visibility == 1.0-(directionalIntensity/16)*4) + { + visibility = 1.0-directionalIntensity; + } + else if (visibility != 1.0) { + for (int i=0; i<12; i++) { + visibility -= directionalIntensity/16*(1.0-texture(shadowMap, vec3(shadowCoord.xy + poissonDisk[i]/700.0, (shadowCoord.z - bias)/shadowCoord.w))); + } + } + return visibility; +} + void main() { vec3 ambientColor = ambientFactor * ambientColor; @@ -78,24 +101,22 @@ void main() } // shadows - float bias = 0.001*tan(acos(clamp(dot(vNormal, -directionalLightVector), 0.0, 1.0))); - bias = clamp(bias, 0.0, 0.01); float visibility = 1.0; - if (shadowCoord.x > 0.0 && shadowCoord.x < 1.0) { - if (shadowCoord.y > 0.0 && shadowCoord.y < 1.0) { - for (int i=0; i<4; i++) { - visibility -= directionalIntensity/16*(1.0-texture(shadowMap, vec3(shadowCoord.xy + poissonDisk[i]/700.0, (shadowCoord.z - bias)/shadowCoord.w))); + if ((shadowCoord_far.x > 0.0 && shadowCoord_far.x < 1.0) && + (shadowCoord_far.y > 0.0 && shadowCoord_far.y < 1.0)) { + if ((shadowCoord_middle.x > 0.0 && shadowCoord_middle.x < 1.0) && + (shadowCoord_middle.y > 0.0 && shadowCoord_middle.y < 1.0)) { + if ((shadowCoord_near.x > 0.0 && shadowCoord_near.x < 1.0) && + (shadowCoord_near.y > 0.0 && shadowCoord_near.y < 1.0)) { + visibility = sampleShadow(shadowMap_near, shadowCoord_near); } - if (visibility == 1.0-(directionalIntensity/16)*4) - { - visibility = 1.0-directionalIntensity; - } - else if (visibility != 1.0) { - for (int i=0; i<12; i++) { - visibility -= directionalIntensity/16*(1.0-texture(shadowMap, vec3(shadowCoord.xy + poissonDisk[i]/700.0, (shadowCoord.z - bias)/shadowCoord.w))); - } + else { + visibility = sampleShadow(shadowMap_middle, shadowCoord_middle); } } + else { + visibility = sampleShadow(shadowMap_far, shadowCoord_far); + } } specularColor *= visibility; diff --git a/Shader/phong.vsh b/Shader/phong.vsh index df35a04..d2f840e 100644 --- a/Shader/phong.vsh +++ b/Shader/phong.vsh @@ -2,7 +2,9 @@ uniform mat4 modelMatrix; uniform mat4 lightingViewProjectionMatrix; -uniform mat4 shadowMVP; +uniform mat4 shadowMVP_near; +uniform mat4 shadowMVP_middle; +uniform mat4 shadowMVP_far; in vec3 aPosition; in vec3 aNormal; @@ -11,13 +13,17 @@ in vec2 aTexCoord; out vec3 vNormal; out vec2 vTexCoord; out vec4 fragPosition; -out vec4 shadowCoord; +out vec4 shadowCoord_near; +out vec4 shadowCoord_middle; +out vec4 shadowCoord_far; void main() { fragPosition = modelMatrix * vec4(aPosition, 1.0); vNormal = inverse(transpose(mat3(modelMatrix))) * aNormal; vTexCoord = aTexCoord; - shadowCoord = shadowMVP * modelMatrix * vec4(aPosition, 1.0); + shadowCoord_near = shadowMVP_near * modelMatrix * vec4(aPosition, 1.0); + shadowCoord_middle = shadowMVP_middle * modelMatrix * vec4(aPosition, 1.0); + shadowCoord_far = shadowMVP_far * modelMatrix * vec4(aPosition, 1.0); gl_Position = lightingViewProjectionMatrix * modelMatrix * vec4(aPosition, 1.0); } diff --git a/graphics.cc b/graphics.cc index 0f6845f..06f3bf6 100644 --- a/graphics.cc +++ b/graphics.cc @@ -29,19 +29,35 @@ void Graphics::init() { lightingShader = ShaderProgramCreator("phong").attributeLocations( vao->getAttributeLocations()).create(); - depthTexture = SharedTexture2D( new Texture2D(windowSize, GL_DEPTH24_STENCIL8)); - depthTexture->setMinFilter(GL_LINEAR); - depthTexture->setMagFilter(GL_LINEAR); - depthTexture->setCompareMode(GL_COMPARE_REF_TO_TEXTURE); - - framebuffer = SharedFrameBufferObject(new FrameBufferObject()); - framebuffer->setDepthTexture(depthTexture); - framebuffer->validate(); - depthShader = ShaderProgramCreator("depth") - .attributeLocations(vao->getAttributeLocations()) - .fragmentDataLocations(framebuffer->getAttachmentLocations()) - .create(); + .attributeLocations(vao->getAttributeLocations()).create(); + + depthTexture_near = SharedTexture2D( new Texture2D(windowSize, GL_DEPTH24_STENCIL8)); + depthTexture_near->setMinFilter(GL_NEAREST); + depthTexture_near->setMagFilter(GL_NEAREST); + depthTexture_near->setCompareMode(GL_COMPARE_REF_TO_TEXTURE); + + framebuffer_near = SharedFrameBufferObject(new FrameBufferObject()); + framebuffer_near->setDepthTexture(depthTexture_near); + framebuffer_near->validate(); + + depthTexture_middle = SharedTexture2D( new Texture2D(windowSize, GL_DEPTH24_STENCIL8)); + depthTexture_middle->setMinFilter(GL_NEAREST); + depthTexture_middle->setMagFilter(GL_NEAREST); + depthTexture_middle->setCompareMode(GL_COMPARE_REF_TO_TEXTURE); + + framebuffer_middle = SharedFrameBufferObject(new FrameBufferObject()); + framebuffer_middle->setDepthTexture(depthTexture_middle); + framebuffer_middle->validate(); + + depthTexture_far = SharedTexture2D( new Texture2D(windowSize, GL_DEPTH24_STENCIL8)); + depthTexture_far->setMinFilter(GL_NEAREST); + depthTexture_far->setMagFilter(GL_NEAREST); + depthTexture_far->setCompareMode(GL_COMPARE_REF_TO_TEXTURE); + + framebuffer_far = SharedFrameBufferObject(new FrameBufferObject()); + framebuffer_far->setDepthTexture(depthTexture_far); + framebuffer_far->validate(); } GLFWwindow* Graphics::getWindow() { @@ -55,15 +71,38 @@ glm::uvec2 Graphics::getWindowSize() { void Graphics::render(Level* level) { // render depth texture for sun - framebuffer->bind(); + // near pass + framebuffer_near->bind(); glClear(GL_DEPTH_BUFFER_BIT); depthShader->use(); glm::vec3 sunVector = (level->getCameraCenter()->getPosition() + level->getDirectionalLight()->getPosition()); - glm::mat4 depthViewProjectionMatrix = glm::ortho(-20, 20, -20, 20, -20, 40) * + glm::mat4 depthViewProjectionMatrix_near = glm::ortho(-5, 5, -5, 5, -5, 5) * glm::lookAt(sunVector, level->getCameraCenter()->getPosition(), glm::vec3(0,1,0)); - depthShader->setUniform("viewProjectionMatrix", depthViewProjectionMatrix); + depthShader->setUniform("viewProjectionMatrix", depthViewProjectionMatrix_near); level->render(depthShader, false); - if (!framebuffer->isFrameBufferObjectComplete()) { + if (!framebuffer_near->isFrameBufferObjectComplete()) { + printf("Framebuffer incomplete, unknown error occured during shadow generation!\n"); + } + + // middle pass + framebuffer_middle->bind(); + glClear(GL_DEPTH_BUFFER_BIT); + glm::mat4 depthViewProjectionMatrix_middle = glm::ortho(-20, 20, -20, 20, -20, 20) * + glm::lookAt(sunVector, level->getCameraCenter()->getPosition(), glm::vec3(0,1,0)); + depthShader->setUniform("viewProjectionMatrix", depthViewProjectionMatrix_middle); + level->render(depthShader, false); + if (!framebuffer_middle->isFrameBufferObjectComplete()) { + printf("Framebuffer incomplete, unknown error occured during shadow generation!\n"); + } + + // far pass + framebuffer_far->bind(); + glClear(GL_DEPTH_BUFFER_BIT); + glm::mat4 depthViewProjectionMatrix_far = glm::ortho(-farPlane/2.0f, farPlane/2.0f, -farPlane/2.0f, farPlane/2.0f, -farPlane/2.0f, farPlane/2.0f) * + glm::lookAt(sunVector, level->getCameraCenter()->getPosition(), glm::vec3(0,1,0)); + depthShader->setUniform("viewProjectionMatrix", depthViewProjectionMatrix_far); + level->render(depthShader, false); + if (!framebuffer_far->isFrameBufferObjectComplete()) { printf("Framebuffer incomplete, unknown error occured during shadow generation!\n"); } @@ -85,10 +124,16 @@ void Graphics::render(Level* level) 0.0, 0.0, 0.5, 0.0, 0.5, 0.5, 0.5, 1.0 ); - glm::mat4 depthBiasMVP = biasMatrix*depthViewProjectionMatrix; + glm::mat4 depthBiasMVP_near = biasMatrix*depthViewProjectionMatrix_near; + glm::mat4 depthBiasMVP_middle = biasMatrix*depthViewProjectionMatrix_middle; + glm::mat4 depthBiasMVP_far = biasMatrix*depthViewProjectionMatrix_far; - lightingShader->setUniform("shadowMVP", depthBiasMVP); - lightingShader->setTexture("shadowMap", depthTexture, 1); + lightingShader->setUniform("shadowMVP_near", depthBiasMVP_near); + lightingShader->setTexture("shadowMap_near", depthTexture_near, 1); + lightingShader->setUniform("shadowMVP_middle", depthBiasMVP_middle); + lightingShader->setTexture("shadowMap_middle", depthTexture_middle, 2); + lightingShader->setUniform("shadowMVP_far", depthBiasMVP_far); + lightingShader->setTexture("shadowMap_far", depthTexture_far, 3); //set lighting parameters if (level->getLights().size() > 0) { @@ -142,7 +187,9 @@ void Graphics::render(Level* level) void Graphics::resize(glm::uvec2 windowSize) { this->windowSize = windowSize; - depthTexture->resize(glm::vec2(windowSize.x, windowSize.y)); + depthTexture_near->resize(glm::vec2(windowSize.x, windowSize.y)); + depthTexture_middle->resize(glm::vec2(windowSize.x, windowSize.y)); + depthTexture_far->resize(glm::vec2(windowSize.x, windowSize.y)); } glm::mat4 Graphics::buildFrustum( float phiInDegree, float _near, float _far, float aspectRatio) { diff --git a/graphics.hh b/graphics.hh index 73aa112..a807d11 100644 --- a/graphics.hh +++ b/graphics.hh @@ -30,8 +30,12 @@ class Graphics { GLFWwindow* window; ACGL::OpenGL::SharedShaderProgram lightingShader; ACGL::OpenGL::SharedShaderProgram depthShader; - ACGL::OpenGL::SharedTexture2D depthTexture; - ACGL::OpenGL::SharedFrameBufferObject framebuffer; + ACGL::OpenGL::SharedTexture2D depthTexture_near; + ACGL::OpenGL::SharedFrameBufferObject framebuffer_near; + ACGL::OpenGL::SharedTexture2D depthTexture_middle; + ACGL::OpenGL::SharedFrameBufferObject framebuffer_middle; + ACGL::OpenGL::SharedTexture2D depthTexture_far; + ACGL::OpenGL::SharedFrameBufferObject framebuffer_far; }; #endif