Enabled cascaded shadow maps in forward rendering mode

opengl3
Martin Felis 2019-04-23 23:17:10 +02:00
parent 2c132e2abc
commit b456d24934
5 changed files with 166 additions and 64 deletions

View File

@ -7,12 +7,33 @@ uniform sampler2D uAlbedoTexture;
#define USE_SAMPLER2D_SHADOW 1 #define USE_SAMPLER2D_SHADOW 1
//
// Single Shadow MAp
//
#ifdef USE_SAMPLER2D_SHADOW #ifdef USE_SAMPLER2D_SHADOW
uniform sampler2DShadow uShadowMap; uniform sampler2DShadow uShadowMap;
#else #else
uniform sampler2D uShadowMap; uniform sampler2D uShadowMap;
#endif #endif
//
// Cascaded Shadow Maps
//
const int NUM_SPLITS = 4;
#ifdef USE_SAMPLER2D_SHADOW
uniform sampler2DShadow uShadowMaps[NUM_SPLITS];
#else
uniform sampler2D uShadowMaps[NUM_SPLITS];
#endif
uniform mat4 uViewToLightMatrix[NUM_SPLITS];
uniform float uShowCascadesAlpha;
uniform vec4 uShadowSplits;
uniform vec4 uShadowSplitBias;
uniform mat4 uModelMatrix; uniform mat4 uModelMatrix;
uniform mat4 uViewMatrix; uniform mat4 uViewMatrix;
@ -26,7 +47,7 @@ out vec4 outColor;
out vec3 outPosition; out vec3 outPosition;
out vec3 outNormal; out vec3 outNormal;
float ShadowCalculationPCF(vec4 frag_pos_light_space) { float ShadowCalculationPCF_OLD(vec4 frag_pos_light_space) {
vec3 projected_coordinates = frag_pos_light_space.xyz / frag_pos_light_space.w; vec3 projected_coordinates = frag_pos_light_space.xyz / frag_pos_light_space.w;
projected_coordinates = projected_coordinates * 0.5 + 0.5; projected_coordinates = projected_coordinates * 0.5 + 0.5;
@ -54,46 +75,101 @@ float ShadowCalculationPCF(vec4 frag_pos_light_space) {
return shadow; return shadow;
} }
float ShadowCalculation(vec4 frag_pos_light_space) { #ifdef USE_SAMPLER2D_SHADOW
float ShadowCalculationPCF(sampler2DShadow shadow_map, vec4 frag_pos_light_space, vec3 frag_normal_light_space, float shadow_bias) {
#else
float ShadowCalculationPCF(sampler2D shadow_map, vec4 frag_pos_light_space, vec3 frag_normal_light_space, float shadow_bias) {
#endif
vec3 projected_coordinates = frag_pos_light_space.xyz / frag_pos_light_space.w; vec3 projected_coordinates = frag_pos_light_space.xyz / frag_pos_light_space.w;
projected_coordinates = projected_coordinates * 0.5 + 0.5; projected_coordinates = projected_coordinates * 0.5 + 0.5;
if (abs(projected_coordinates.z) > 1.0 ) {
return 0.0;
}
float current_depth = projected_coordinates.z; float current_depth = projected_coordinates.z;
float bias = 0.01; float bias = 0.00;
bias = max(shadow_bias * (1.0 - dot(frag_normal_light_space, uLightDirection)), shadow_bias);
float shadow = 0.0;
vec2 texel_size = 1.0 / textureSize(shadow_map, 0);
for (int x = -1; x <= 1; ++x) {
for (int y = -1; y <= 1; ++y) {
#ifdef USE_SAMPLER2D_SHADOW #ifdef USE_SAMPLER2D_SHADOW
float closest_depth = texture(uShadowMap, vec3(projected_coordinates.xy, current_depth - bias)); vec2 coordinate = projected_coordinates.xy + vec2(x, y) * texel_size;
float pcf_depth = texture(shadow_map, vec3(coordinate, current_depth - bias));
#else #else
float closest_depth = texture(uShadowMap, projected_coordinates.xy).r; float pcf_depth = texture(shadow_map, projected_coordinates.xy).r;
bias = max(0.005 * (1.0 - dot(ioFragNormal, uLightDirection)), 0.003);
#endif #endif
shadow += current_depth - bias > pcf_depth ? 1.0 : 0.0;
}
}
return current_depth - bias > closest_depth ? 1.0 : 0.0; shadow /= 9.0;
return shadow;
}
vec3 get_cascade_color (float depth) {
if (depth < uShadowSplits[0]) {
return vec3 (1.0, 0.0, 0.0);
} else if (depth < uShadowSplits[1]) {
return vec3 (1.0, 1.0, 0.0);
} else if (depth < uShadowSplits[2]) {
return vec3 (0.0, 1.0, 0.0);
}
return vec3 (0.0, 0.0, 1.0);
} }
void main() { void main() {
vec4 albedo_color = texture(uAlbedoTexture, ioFragTexCoords) * ioFragColor * uColor; vec4 albedo_color = texture(uAlbedoTexture, ioFragTexCoords) * ioFragColor * uColor;
vec3 position = ioFragPosition.xyz;
// ambient lighting // ambient lighting
float ambient_strength = 0.2; float ambient_strength = 0.2;
vec4 ambient = ambient_strength * albedo_color; vec4 ambient = ambient_strength * albedo_color;
// diffuse lighting // diffuse lighting
vec3 normal_dir = normalize(ioFragNormal); vec3 normal = normalize(ioFragNormal);
vec3 light_dir = -(mat3(uViewMatrix)) * uLightDirection; vec3 light_dir = -(mat3(uViewMatrix)) * uLightDirection;
float diff = max(dot(normal_dir, light_dir), 0.0); float diff = max(dot(normal, light_dir), 0.0);
vec4 diffuse = diff * albedo_color; vec4 diffuse = diff * albedo_color;
// specular lighting // specular lighting
vec3 view_dir = normalize(-ioFragPosition); vec3 view_dir = normalize(-ioFragPosition);
vec3 halfway_dir = normalize(light_dir + view_dir); vec3 halfway_dir = normalize(light_dir + view_dir);
float spec = pow(max(dot(normal_dir, halfway_dir), 0.0), 32); float spec = pow(max(dot(normal, halfway_dir), 0.0), 32);
vec4 specular = spec * vec4(0.5); vec4 specular = spec * vec4(0.5);
// shadow // shadow
float shadow = ShadowCalculationPCF(ioFragPosLightSpace); float shadow = 0;
if (-position.z < uShadowSplits[0]) {
// shadow (need to transform position and normal to light space)
vec4 position_light_space = uViewToLightMatrix[0] * vec4(position, 1.0);
vec3 normal_light_space = (transpose(inverse(uViewToLightMatrix[0])) * vec4(normal, 1.0)).xyz;
shadow = ShadowCalculationPCF(uShadowMaps[0], position_light_space, normal, uShadowSplitBias[0]);
} else if (-position.z< uShadowSplits[1]) {
vec4 position_light_space = uViewToLightMatrix[1] * vec4(position, 1.0);
vec3 normal_light_space = (transpose(inverse(uViewToLightMatrix[1])) * vec4(normal, 1.0)).xyz;
shadow = ShadowCalculationPCF(uShadowMaps[1], position_light_space, normal, uShadowSplitBias[1]);
} else if (-position.z< uShadowSplits[2]) {
vec4 position_light_space = uViewToLightMatrix[2] * vec4(position, 1.0);
vec3 normal_light_space = (transpose(inverse(uViewToLightMatrix[2])) * vec4(normal, 1.0)).xyz;
shadow = ShadowCalculationPCF(uShadowMaps[2], position_light_space, normal, uShadowSplitBias[2]);
} else {
vec4 position_light_space = uViewToLightMatrix[3] * vec4(position, 1.0);
vec3 normal_light_space = (transpose(inverse(uViewToLightMatrix[3])) * vec4(normal, 1.0)).xyz;
shadow = ShadowCalculationPCF(uShadowMaps[3], position_light_space, normal, uShadowSplitBias[3]);
}
vec4 cascade = vec4(get_cascade_color(-position.z), 1.0);
ambient = (uShowCascadesAlpha * cascade) + (1.0 - uShowCascadesAlpha) * ambient;
outColor = (ambient + (1.0 - shadow) * (diffuse + specular));
// float shadow = ShadowCalculationPCF(uShadowMap, ioFragPosLightSpace, normal, 0.001);
outColor = ambient + (1.0 - shadow) * (diffuse + specular); outColor = ambient + (1.0 - shadow) * (diffuse + specular);
outPosition = ioFragPosition.xyz; outPosition = ioFragPosition.xyz;

View File

@ -8,11 +8,13 @@ in vec4 inColor;
uniform mat4 uModelMatrix; uniform mat4 uModelMatrix;
uniform mat4 uViewMatrix; uniform mat4 uViewMatrix;
uniform mat4 uProjectionMatrix; uniform mat4 uProjectionMatrix;
uniform mat4 uLightSpaceMatrix;
out vec3 ioFragPosition; out vec3 ioFragPosition;
out vec3 ioFragNormal; out vec3 ioFragNormal;
out vec2 ioFragTexCoords; out vec2 ioFragTexCoords;
out vec4 ioFragColor; out vec4 ioFragColor;
out vec4 ioFragPosLightSpace;
void main() { void main() {
mat4 model_view_matrix = uViewMatrix * uModelMatrix; mat4 model_view_matrix = uViewMatrix * uModelMatrix;
@ -21,6 +23,7 @@ void main() {
ioFragNormal = transpose(inverse(mat3(model_view_matrix))) * inNormal; ioFragNormal = transpose(inverse(mat3(model_view_matrix))) * inNormal;
ioFragTexCoords = inUV; ioFragTexCoords = inUV;
ioFragColor = inColor; ioFragColor = inColor;
ioFragPosLightSpace = uLightSpaceMatrix * uModelMatrix * inCoord;
gl_Position = uProjectionMatrix * model_view_matrix * inCoord; gl_Position = uProjectionMatrix * model_view_matrix * inCoord;
} }

View File

@ -124,7 +124,6 @@ static void module_serialize (
SerializeBool(*serializer, "protot.RenderModule.mLight.mDebugDrawSplitLightBounds", gRenderer->mLight.mDebugDrawSplitLightBounds); SerializeBool(*serializer, "protot.RenderModule.mLight.mDebugDrawSplitLightBounds", gRenderer->mLight.mDebugDrawSplitLightBounds);
SerializeVec4 (*serializer, "protot.RenderModule.mLight.mSplitBias", gRenderer->mLight.mSplitBias); SerializeVec4 (*serializer, "protot.RenderModule.mLight.mSplitBias", gRenderer->mLight.mSplitBias);
SerializeVec4 (*serializer, "protot.RenderModule.mLight.mShadowSplits", gRenderer->mLight.mShadowSplits); SerializeVec4 (*serializer, "protot.RenderModule.mLight.mShadowSplits", gRenderer->mLight.mShadowSplits);
} }
static void module_finalize(struct module_state *state) { static void module_finalize(struct module_state *state) {
@ -584,12 +583,6 @@ void Renderer::CheckRenderBuffers() {
} }
} }
void Renderer::ResizeTargets(int width, int height) {
mSSAOTarget.Resize(mSceneAreaWidth, mSceneAreaHeight, RenderTarget::EnableColor);
mSSAOBlurTarget.Resize(mSceneAreaWidth, mSceneAreaHeight, RenderTarget::EnableColor);
}
void Renderer::RenderGl() { void Renderer::RenderGl() {
CheckRenderBuffers(); CheckRenderBuffers();
@ -652,12 +645,21 @@ void Renderer::RenderGl() {
* mCamera.mViewMatrix * mCamera.mViewMatrix
* mCamera.mProjectionMatrix; * mCamera.mProjectionMatrix;
// Clear the SSAO Blur target
if (!mIsSSAOEnabled) {
mSSAOBlurTarget.Bind();
GLenum draw_attachment_0[] = {GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, draw_attachment_0);
glClearColor(1.f, 1.f, 1.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
}
// enable the render target // enable the render target
mForwardRenderingTarget.Bind(); mForwardRenderingTarget.Bind();
GLenum draw_attachment_0[] = {GL_COLOR_ATTACHMENT0 };
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { glDrawBuffers(1, draw_attachment_0);
gLog ("Cannot render: frame buffer invalid!"); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
RenderProgram *program = &mDefaultProgram; RenderProgram *program = &mDefaultProgram;
@ -711,29 +713,54 @@ void Renderer::RenderGl() {
gVertexArray.Bind(); gVertexArray.Bind();
gXZPlaneGrid.Draw(GL_LINES); gXZPlaneGrid.Draw(GL_LINES);
if (!mIsSSAOEnabled) {
// Clear the SSAO Blur target
mSSAOBlurTarget.Bind();
glViewport(0, 0, mCamera.mWidth, mCamera.mHeight);
GLenum draw_attachment_0[] = {GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, draw_attachment_0);
glClearColor(255, 255, 255, 255);
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
gVertexArray.Bind();
gScreenQuad.Draw(GL_TRIANGLES);
}
// Scene // Scene
glUseProgram(program->mProgramId); glUseProgram(program->mProgramId);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mLight.mShadowMapTarget.mDepthTexture);
program->SetInt("uShadowMap", 0);
if (!mUseDeferred) {
// Shadow Map Cascades
glActiveTexture(GL_TEXTURE5);
glBindTexture(GL_TEXTURE_2D, mLight.mSplitTarget[0].mDepthTexture);
glActiveTexture(GL_TEXTURE6);
glBindTexture(GL_TEXTURE_2D, mLight.mSplitTarget[1].mDepthTexture);
glActiveTexture(GL_TEXTURE7);
glBindTexture(GL_TEXTURE_2D, mLight.mSplitTarget[2].mDepthTexture);
glActiveTexture(GL_TEXTURE8);
glBindTexture(GL_TEXTURE_2D, mLight.mSplitTarget[3].mDepthTexture);
GLint shadow_maps[cNumSplits];
shadow_maps[0] = 5;
shadow_maps[1] = 6;
shadow_maps[2] = 7;
shadow_maps[3] = 8;
program->SetIntArray("uShadowMaps", cNumSplits, shadow_maps);
Matrix44f light_matrices[cNumSplits];
for (int i = 0; i < cNumSplits; ++i) {
light_matrices[i] = mCamera.mViewMatrix.inverse()
* mLight.mSplitLightFrustum[i];
}
program->SetFloat("uNear", mCamera.mNear);
program->SetFloat("uFar", mCamera.mFar);
program->SetVec4("uShadowSplits", mLight.mShadowSplits);
program->SetVec4("uShadowSplitBias", mLight.mSplitBias);
program->SetFloat("uShowCascadesAlpha", mLight.mShowCascadesAlpha);
program->SetMat44Array("uViewToLightMatrix", cNumSplits, light_matrices);
program->SetMat44("uLightSpaceMatrix", mLight.mLightSpaceMatrix);
}
RenderScene(*program, mCamera); RenderScene(*program, mCamera);
if (mSettings->RenderMode == SceneRenderModeDepth) { if (mSettings->RenderMode == SceneRenderModeDepth) {
mForwardRenderingTarget.RenderToLinearizedDepth(mCamera.mNear, mCamera.mFar, mCamera.mIsOrthographic); mForwardRenderingTarget.RenderToLinearizedDepth(mCamera.mNear, mCamera.mFar, mCamera.mIsOrthographic);
} }
if (mUseDeferred && mIsSSAOEnabled) { if (mIsSSAOEnabled) {
mSSAOTarget.Bind(); mSSAOTarget.Bind();
glViewport(0, 0, mCamera.mWidth, mCamera.mHeight); glViewport(0, 0, mCamera.mWidth, mCamera.mHeight);
GLenum draw_attachment_0[] = {GL_COLOR_ATTACHMENT0 }; GLenum draw_attachment_0[] = {GL_COLOR_ATTACHMENT0 };
@ -774,6 +801,7 @@ void Renderer::RenderGl() {
mSSAOBlurTarget.Bind(); mSSAOBlurTarget.Bind();
glViewport(0, 0, mCamera.mWidth, mCamera.mHeight); glViewport(0, 0, mCamera.mWidth, mCamera.mHeight);
glDrawBuffers(1, draw_attachment_0); glDrawBuffers(1, draw_attachment_0);
glClearColor(1.f, 1.f, 1.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
@ -830,14 +858,14 @@ void Renderer::RenderGl() {
glActiveTexture(GL_TEXTURE8); glActiveTexture(GL_TEXTURE8);
glBindTexture(GL_TEXTURE_2D, mLight.mSplitTarget[3].mDepthTexture); glBindTexture(GL_TEXTURE_2D, mLight.mSplitTarget[3].mDepthTexture);
GLint shadow_maps[4]; GLint shadow_maps[cNumSplits];
shadow_maps[0] = 5; shadow_maps[0] = 5;
shadow_maps[1] = 6; shadow_maps[1] = 6;
shadow_maps[2] = 7; shadow_maps[2] = 7;
shadow_maps[3] = 8; shadow_maps[3] = 8;
mDeferredLighting.SetIntArray("uShadowMap", cNumSplits, shadow_maps); mDeferredLighting.SetIntArray("uShadowMap", cNumSplits, shadow_maps);
Matrix44f light_matrices[3]; Matrix44f light_matrices[cNumSplits];
for (int i = 0; i < cNumSplits; ++i) { for (int i = 0; i < cNumSplits; ++i) {
light_matrices[i] = mCamera.mViewMatrix.inverse() light_matrices[i] = mCamera.mViewMatrix.inverse()
@ -860,6 +888,7 @@ void Renderer::RenderGl() {
mDeferredLighting.SetVec3("uLightDirection", light_direction.normalized()); mDeferredLighting.SetVec3("uLightDirection", light_direction.normalized());
mDeferredLighting.SetFloat("uShadowBias", mLight.mShadowBias); mDeferredLighting.SetFloat("uShadowBias", mLight.mShadowBias);
glDisable(GL_DEPTH_TEST);
gVertexArray.Bind(); gVertexArray.Bind();
gScreenQuad.Draw(GL_TRIANGLES); gScreenQuad.Draw(GL_TRIANGLES);
} }
@ -945,12 +974,6 @@ void Renderer::SubmitRenderCommands (RenderProgram &program, const Camera &camer
program.SetVec3("uLightDirection", mLight.mDirection); program.SetVec3("uLightDirection", mLight.mDirection);
program.SetVec3("uViewPosition", camera.mEye); program.SetVec3("uViewPosition", camera.mEye);
program.SetMat44("uLightSpaceMatrix", mLight.mLightSpaceMatrix);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mLight.mShadowMapTarget.mDepthTexture);
program.SetInt("uShadowMap", 0);
glActiveTexture(GL_TEXTURE1); glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, mDefaultTexture.mTextureId); glBindTexture(GL_TEXTURE_2D, mDefaultTexture.mTextureId);
program.SetInt("uAlbedoTexture", 1); program.SetInt("uAlbedoTexture", 1);