Reintroduced cascaded shadow mapping while also fixing it. The old bug with popping shadows should be fixed now.

This commit is contained in:
Faerbit 2015-02-28 14:40:54 +01:00
parent 7ff11e1105
commit 2da70f156d
4 changed files with 97 additions and 48 deletions

View File

@ -3,12 +3,16 @@
in vec3 vNormal; in vec3 vNormal;
in vec2 vTexCoord; in vec2 vTexCoord;
in vec4 fragPosition; in vec4 fragPosition;
in vec4 shadowCoord; in vec4 shadowCoord0;
in vec4 shadowCoord1;
in vec4 shadowCoord2;
out vec4 oColor; out vec4 oColor;
uniform sampler2D uTexture; uniform sampler2D uTexture;
uniform sampler2DShadow shadowMap; uniform sampler2DShadow shadowMap_directional0;
uniform sampler2DShadow shadowMap_directional1;
uniform sampler2DShadow shadowMap_directional2;
uniform samplerCubeShadow shadowMap_cube0; uniform samplerCubeShadow shadowMap_cube0;
uniform samplerCubeShadow shadowMap_cube1; uniform samplerCubeShadow shadowMap_cube1;
uniform samplerCubeShadow shadowMap_cube2; uniform samplerCubeShadow shadowMap_cube2;
@ -61,7 +65,7 @@ float sampleDirectionalShadow(sampler2DShadow shadowMap, vec4 shadowCoord) {
float bias = 0.001*tan(acos(clamp(dot(vNormal, -directionalLightVector), 0.0, 1.0))); float bias = 0.001*tan(acos(clamp(dot(vNormal, -directionalLightVector), 0.0, 1.0)));
bias = clamp(bias, 0.0, 0.01); bias = clamp(bias, 0.0, 0.01);
for (int i=0; i<4; i++) { for (int i=0; i<4; i++) {
visibility -= directionalIntensity/16*(1.0-texture(shadowMap, vec3(shadowCoord.xy + poissonDisk[i]/700.0, shadowCoord.z - bias))); visibility -= directionalIntensity/16*(1.0-texture(shadowMap, vec3(shadowCoord.xy + poissonDisk[i]/800.0, shadowCoord.z - bias)));
} }
if (visibility == 1.0-(directionalIntensity/16)*4) if (visibility == 1.0-(directionalIntensity/16)*4)
{ {
@ -69,7 +73,7 @@ float sampleDirectionalShadow(sampler2DShadow shadowMap, vec4 shadowCoord) {
} }
else if (visibility != 1.0) { else if (visibility != 1.0) {
for (int i=0; i<12; i++) { for (int i=0; i<12; i++) {
visibility -= directionalIntensity/16*(1.0-texture(shadowMap, vec3(shadowCoord.xy + poissonDisk[i]/700.0, shadowCoord.z - bias))); visibility -= directionalIntensity/16*(1.0-texture(shadowMap, vec3(shadowCoord.xy + poissonDisk[i]/800.0, shadowCoord.z - bias)));
} }
} }
return visibility; return visibility;
@ -101,7 +105,18 @@ void main()
// direction lighting // direction lighting
if(length(directionalLightVector)>0.0f) { if(length(directionalLightVector)>0.0f) {
vec3 directionalVector = normalize(directionalLightVector); vec3 directionalVector = normalize(directionalLightVector);
float directionalVisibility = sampleDirectionalShadow(shadowMap, shadowCoord); float directionalVisibility = 1.0f;
if (distanceToBorder(shadowCoord1.xy) <= 0.5 && distanceToBorder(shadowCoord1.xy) > 0.0) {
if (distanceToBorder(shadowCoord0.xy) <= 0.5 && distanceToBorder(shadowCoord0.xy) > 0.0) {
directionalVisibility = sampleDirectionalShadow(shadowMap_directional0, shadowCoord0);
}
else {
directionalVisibility = sampleDirectionalShadow(shadowMap_directional1, shadowCoord1);
}
}
else {
directionalVisibility = sampleDirectionalShadow(shadowMap_directional2, shadowCoord2);
}
diffuseColor += clamp(dot(normalize(vNormal), directionalVector) diffuseColor += clamp(dot(normalize(vNormal), directionalVector)
*diffuseFactor*directionalIntensity*directionalColor, 0.0, 1.0)*directionalVisibility; *diffuseFactor*directionalIntensity*directionalColor, 0.0, 1.0)*directionalVisibility;
vec3 cameraVector = normalize(camera - vec3(fragPosition)); vec3 cameraVector = normalize(camera - vec3(fragPosition));

View File

@ -11,13 +11,17 @@ in vec2 aTexCoord;
out vec3 vNormal; out vec3 vNormal;
out vec2 vTexCoord; out vec2 vTexCoord;
out vec4 fragPosition; out vec4 fragPosition;
out vec4 shadowCoord; out vec4 shadowCoord0;
out vec4 shadowCoord1;
out vec4 shadowCoord2;
void main() void main()
{ {
fragPosition = modelMatrix * vec4(aPosition, 1.0); fragPosition = modelMatrix * vec4(aPosition, 1.0);
vNormal = inverse(transpose(mat3(modelMatrix))) * aNormal; vNormal = inverse(transpose(mat3(modelMatrix))) * aNormal;
vTexCoord = aTexCoord; vTexCoord = aTexCoord;
shadowCoord = shadowMVPs[0] * vec4(aPosition, 1.0); shadowCoord0 = shadowMVPs[0] * vec4(aPosition, 1.0);
shadowCoord1 = shadowMVPs[1] * vec4(aPosition, 1.0);
shadowCoord2 = shadowMVPs[2] * vec4(aPosition, 1.0);
gl_Position = modelViewProjectionMatrix * vec4(aPosition, 1.0); gl_Position = modelViewProjectionMatrix * vec4(aPosition, 1.0);
} }

View File

@ -58,26 +58,40 @@ void Graphics::init(Level* level) {
flameShader = ShaderProgramCreator("flame") flameShader = ShaderProgramCreator("flame")
.attributeLocations(flame_positions->getAttributeLocations()).create(); .attributeLocations(flame_positions->getAttributeLocations()).create();
depthTexture = SharedTexture2D( new Texture2D(windowSize, GL_DEPTH_COMPONENT24));
depthTexture->setMinFilter(GL_NEAREST);
depthTexture->setMagFilter(GL_NEAREST);
depthTexture->setWrapS(GL_CLAMP_TO_EDGE);
depthTexture->setWrapT(GL_CLAMP_TO_EDGE);
depthTexture->setCompareMode(GL_COMPARE_REF_TO_TEXTURE);
framebuffer = SharedFrameBufferObject(new FrameBufferObject());
framebuffer->setDepthTexture(depthTexture);
framebuffer->validate();
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &number_of_texture_units); glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &number_of_texture_units);
printf("Your graphics card supports %d texture units.\n", number_of_texture_units); printf("Your graphics card supports %d texture units.\n", number_of_texture_units);
// Exit if we need more texture units // Exit if we need more texture units
if (number_of_texture_units < 12) { if (number_of_texture_units < 14) {
printf("You need at least 12 texture units to run this application. Exiting\n"); printf("You need at least 14 texture units to run this application. Exiting\n");
exit(-1); exit(-1);
} }
// always generate and bind 32 cube maps, because otherwise the shader won't work depth_directionalMaps = std::vector<SharedTexture2D>(3);
framebuffer_directional = std::vector<SharedFrameBufferObject>(3);
for (unsigned int i = 0; i<depth_directionalMaps.size(); i++) {
depth_directionalMaps.at(i) = SharedTexture2D( new Texture2D(windowSize, GL_DEPTH_COMPONENT24));
depth_directionalMaps.at(i)->setMinFilter(GL_NEAREST);
depth_directionalMaps.at(i)->setMagFilter(GL_NEAREST);
depth_directionalMaps.at(i)->setWrapS(GL_CLAMP_TO_EDGE);
depth_directionalMaps.at(i)->setWrapT(GL_CLAMP_TO_EDGE);
depth_directionalMaps.at(i)->setCompareMode(GL_COMPARE_REF_TO_TEXTURE);
}
for (unsigned int i = 0; i<framebuffer_directional.size(); i++) {
framebuffer_directional.at(i) = SharedFrameBufferObject(new FrameBufferObject());
framebuffer_directional.at(i)->setDepthTexture(depth_directionalMaps.at(i));
framebuffer_directional.at(i)->validate();
}
lightingShader->use();
for (unsigned int i = 0; i<depth_directionalMaps.size(); i++) {
// start with texture unit 1 because the first is reserved for the texture
lightingShader->setTexture("shadowMap_directional" + std::to_string(i), depth_directionalMaps.at(i), i+1);
}
// always generate and bind 10 cube maps, because otherwise the shader won't work
depth_cubeMaps = std::vector<ACGL::OpenGL::SharedTextureCubeMap>(10); depth_cubeMaps = std::vector<ACGL::OpenGL::SharedTextureCubeMap>(10);
for (unsigned int i = 0; i<depth_cubeMaps.size(); i++) { for (unsigned int i = 0; i<depth_cubeMaps.size(); i++) {
depth_cubeMaps.at(i) = SharedTextureCubeMap(new TextureCubeMap(glm::vec2(cube_size, cube_size), GL_DEPTH_COMPONENT24)); depth_cubeMaps.at(i) = SharedTextureCubeMap(new TextureCubeMap(glm::vec2(cube_size, cube_size), GL_DEPTH_COMPONENT24));
@ -90,14 +104,11 @@ void Graphics::init(Level* level) {
framebuffer_cube = SharedFrameBufferObject(new FrameBufferObject()); framebuffer_cube = SharedFrameBufferObject(new FrameBufferObject());
lightingShader->use();
lightingShader->setTexture("shadowMap", depthTexture, 1);
if (level->getLights()->size() > 0) { if (level->getLights()->size() > 0) {
for(unsigned int i = 0; i<depth_cubeMaps.size(); i++){ for(unsigned int i = 0; i<depth_cubeMaps.size(); i++){
// start with texture unit 2 because the first two are used by the texture and the directional shadow map // start with texture unit 4 because the first four are used by the texture and the directional shadow map
lightingShader->setTexture("shadowMap_cube" + std::to_string(i), depth_cubeMaps.at(i), i+2); lightingShader->setTexture("shadowMap_cube" + std::to_string(i), depth_cubeMaps.at(i), i+4);
} }
} }
updateClosestLights(); updateClosestLights();
@ -137,20 +148,35 @@ void Graphics::render(double time)
} }
} }
} }
// render depth texture for sun // render depth textures for sun
depthShader->use(); depthShader->use();
glViewport(0, 0, windowSize.x, windowSize.y); glViewport(0, 0, windowSize.x, windowSize.y);
// far pass std::vector<glm::mat4> depthViewProjectionMatrices = std::vector<glm::mat4>(framebuffer_directional.size());
framebuffer->bind();
glClear(GL_DEPTH_BUFFER_BIT);
glm::vec3 sunVector = (level->getCameraCenter()->getPosition() + level->getDirectionalLight()->getPosition()); glm::vec3 sunVector = (level->getCameraCenter()->getPosition() + level->getDirectionalLight()->getPosition());
glm::mat4 depthViewProjectionMatrix = glm::ortho<float>(-farPlane/1.5f, farPlane/1.5f, -farPlane/1.5f, farPlane/1.5f, -farPlane/1.5f, farPlane/1.5f) *
for (unsigned int i = 0; i<framebuffer_directional.size(); i++) {
framebuffer_directional.at(i)->bind();
glClear(GL_DEPTH_BUFFER_BIT);
float projection_size = 0.0f;
switch(i) {
case 0:
projection_size = 10.0f;
break;
case 1:
projection_size = 30.0f;
break;
case 2:
projection_size = farPlane/1.5f;
break;
}
depthViewProjectionMatrices.at(i) = glm::ortho<float>(-projection_size, projection_size, -projection_size, projection_size, -farPlane/1.5f, projection_size) *
glm::lookAt(sunVector, level->getCameraCenter()->getPosition(), glm::vec3(0,1,0)); glm::lookAt(sunVector, level->getCameraCenter()->getPosition(), glm::vec3(0,1,0));
level->render(depthShader, false, &depthViewProjectionMatrix); level->render(depthShader, false, &depthViewProjectionMatrices.at(i));
if (!framebuffer->isFrameBufferObjectComplete()) { if (!framebuffer_directional.at(i)->isFrameBufferObjectComplete()) {
printf("Framebuffer incomplete, unknown error occured during shadow generation!\n"); printf("Framebuffer incomplete, unknown error occured during shadow generation!\n");
} }
}
// final render pass // final render pass
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
@ -177,7 +203,12 @@ void Graphics::render(double time)
0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0,
0.5, 0.5, 0.5, 1.0 0.5, 0.5, 0.5, 1.0
); );
glm::mat4 depthBiasVP = biasMatrix*depthViewProjectionMatrix;
std::vector<glm::mat4> depthBiasVPs = std::vector<glm::mat4>(depthViewProjectionMatrices.size());
for (unsigned int i = 0; i<depthBiasVPs.size(); i++) {
depthBiasVPs.at(i) = biasMatrix * depthViewProjectionMatrices.at(i);
}
lightingShader->setUniform("farPlane", farPlane); lightingShader->setUniform("farPlane", farPlane);
// set fog Parameters // set fog Parameters
@ -191,11 +222,8 @@ void Graphics::render(double time)
//set view and projection matrix //set view and projection matrix
glm::mat4 lightingViewProjectionMatrix = glm::perspective(1.571f, (float)windowSize.x/(float)windowSize.y, 0.1f, farPlane) * buildViewMatrix(level); glm::mat4 lightingViewProjectionMatrix = glm::perspective(1.571f, (float)windowSize.x/(float)windowSize.y, 0.1f, farPlane) * buildViewMatrix(level);
std::vector<glm::mat4> shadowVPs = std::vector<glm::mat4>();
shadowVPs.push_back(depthBiasVP);
// render the level // render the level
level->render(lightingShader, true, &lightingViewProjectionMatrix, &shadowVPs); level->render(lightingShader, true, &lightingViewProjectionMatrix, &depthBiasVPs);
// cull faces to get consistent color while using alpha // cull faces to get consistent color while using alpha
// cull front faces because normals are on the wrong side // cull front faces because normals are on the wrong side
@ -284,7 +312,9 @@ void Graphics::updateLights() {
void Graphics::resize(glm::uvec2 windowSize) { void Graphics::resize(glm::uvec2 windowSize) {
this->windowSize = windowSize; this->windowSize = windowSize;
depthTexture->resize(glm::vec2(windowSize.x, windowSize.y)); for (unsigned int i = 0; i<depth_directionalMaps.size(); i++) {
depth_directionalMaps.at(i)->resize(glm::vec2(windowSize.x, windowSize.y));
}
} }
glm::mat4 Graphics::buildViewMatrix(Level* level) { glm::mat4 Graphics::buildViewMatrix(Level* level) {

View File

@ -32,8 +32,8 @@ class Graphics {
ACGL::OpenGL::SharedShaderProgram depthCubeShader; ACGL::OpenGL::SharedShaderProgram depthCubeShader;
ACGL::OpenGL::SharedShaderProgram depthShader; ACGL::OpenGL::SharedShaderProgram depthShader;
ACGL::OpenGL::SharedShaderProgram flameShader; ACGL::OpenGL::SharedShaderProgram flameShader;
ACGL::OpenGL::SharedTexture2D depthTexture; std::vector<ACGL::OpenGL::SharedTexture2D> depth_directionalMaps;
ACGL::OpenGL::SharedFrameBufferObject framebuffer; std::vector<ACGL::OpenGL::SharedFrameBufferObject> framebuffer_directional;
std::vector<ACGL::OpenGL::SharedTextureCubeMap> depth_cubeMaps; std::vector<ACGL::OpenGL::SharedTextureCubeMap> depth_cubeMaps;
ACGL::OpenGL::SharedFrameBufferObject framebuffer_cube; ACGL::OpenGL::SharedFrameBufferObject framebuffer_cube;
ACGL::OpenGL::SharedVertexArrayObject flame_positions; ACGL::OpenGL::SharedVertexArrayObject flame_positions;