Added 4th shadow split and exposed per-split shadow map bias

simple_math_single_header
Martin Felis 2018-07-21 17:15:21 +02:00
parent e9ba7f77cc
commit 0fd0b8409e
4 changed files with 51 additions and 27 deletions

View File

@ -6,7 +6,7 @@ uniform sampler2D uNormal;
uniform sampler2D uColor; uniform sampler2D uColor;
uniform sampler2D uAmbientOcclusion; uniform sampler2D uAmbientOcclusion;
const int NUM_SPLITS = 3; const int NUM_SPLITS = 4;
#define USE_SAMPLER2D_SHADOW 1 #define USE_SAMPLER2D_SHADOW 1
@ -21,6 +21,7 @@ uniform mat4 uViewToLightMatrix[NUM_SPLITS];
uniform float uNear; uniform float uNear;
uniform float uFar; uniform float uFar;
uniform vec4 uShadowSplits; uniform vec4 uShadowSplits;
uniform vec4 uShadowSplitBias;
uniform vec3 uLightDirection; uniform vec3 uLightDirection;
uniform float uShadowBias; uniform float uShadowBias;
@ -29,9 +30,9 @@ in vec2 ioFragTexCoords;
out vec3 outColor; out vec3 outColor;
#ifdef USE_SAMPLER2D_SHADOW #ifdef USE_SAMPLER2D_SHADOW
float ShadowCalculationPCF(sampler2DShadow shadow_map, vec4 frag_pos_light_space, vec3 frag_normal_light_space) { float ShadowCalculationPCF(sampler2DShadow shadow_map, vec4 frag_pos_light_space, vec3 frag_normal_light_space, float shadow_bias) {
#else #else
float ShadowCalculationPCF(sampler2D shadow_map, vec4 frag_pos_light_space, vec3 frag_normal_light_space) { float ShadowCalculationPCF(sampler2D shadow_map, vec4 frag_pos_light_space, vec3 frag_normal_light_space, float shadow_bias) {
#endif #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;
@ -43,7 +44,7 @@ float ShadowCalculationPCF(sampler2D shadow_map, vec4 frag_pos_light_space, vec3
float current_depth = projected_coordinates.z; float current_depth = projected_coordinates.z;
float bias = 0.00; float bias = 0.00;
bias = max(0.001 * (1.0 - dot(frag_normal_light_space, uLightDirection)), uShadowBias); bias = max(shadow_bias * (1.0 - dot(frag_normal_light_space, uLightDirection)), shadow_bias);
float shadow = 0.0; float shadow = 0.0;
vec2 texel_size = 1.0 / textureSize(shadow_map, 0); vec2 texel_size = 1.0 / textureSize(shadow_map, 0);
@ -101,19 +102,23 @@ void main() {
float shadow = 0; float shadow = 0;
float normalized_depth = (depth - uNear) / (uFar - uNear); float normalized_depth = (depth - uNear) / (uFar - uNear);
if (-position.z < uShadowSplits[1]) { if (-position.z < uShadowSplits[0]) {
// shadow (need to transform position and normal to light space) // shadow (need to transform position and normal to light space)
vec4 position_light_space = uViewToLightMatrix[0] * vec4(position, 1.0); vec4 position_light_space = uViewToLightMatrix[0] * vec4(position, 1.0);
vec3 normal_light_space = (transpose(inverse(uViewToLightMatrix[0])) * vec4(normal, 1.0)).xyz; vec3 normal_light_space = (transpose(inverse(uViewToLightMatrix[0])) * vec4(normal, 1.0)).xyz;
shadow = ShadowCalculationPCF(uShadowMap[0], position_light_space, normal); shadow = ShadowCalculationPCF(uShadowMap[0], position_light_space, normal, uShadowSplitBias[0]);
} else if (-position.z< uShadowSplits[2]) { } else if (-position.z< uShadowSplits[1]) {
vec4 position_light_space = uViewToLightMatrix[1] * vec4(position, 1.0); vec4 position_light_space = uViewToLightMatrix[1] * vec4(position, 1.0);
vec3 normal_light_space = (transpose(inverse(uViewToLightMatrix[1])) * vec4(normal, 1.0)).xyz; vec3 normal_light_space = (transpose(inverse(uViewToLightMatrix[1])) * vec4(normal, 1.0)).xyz;
shadow = ShadowCalculationPCF(uShadowMap[1], position_light_space, normal); shadow = ShadowCalculationPCF(uShadowMap[1], position_light_space, normal, uShadowSplitBias[1]);
} else { } else if (-position.z< uShadowSplits[2]) {
vec4 position_light_space = uViewToLightMatrix[2] * vec4(position, 1.0); vec4 position_light_space = uViewToLightMatrix[2] * vec4(position, 1.0);
vec3 normal_light_space = (transpose(inverse(uViewToLightMatrix[2])) * vec4(normal, 1.0)).xyz; vec3 normal_light_space = (transpose(inverse(uViewToLightMatrix[2])) * vec4(normal, 1.0)).xyz;
shadow = ShadowCalculationPCF(uShadowMap[2], position_light_space, normal); shadow = ShadowCalculationPCF(uShadowMap[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(uShadowMap[3], position_light_space, normal, uShadowSplitBias[3]);
} }
// vec3 cascade = get_cascade_color(-position.z); // vec3 cascade = get_cascade_color(-position.z);

View File

@ -137,3 +137,8 @@ template <typename Serializer>
bool SerializeVec3 (Serializer &serializer, const std::string &key, SimpleMath::Vector3f& value) { bool SerializeVec3 (Serializer &serializer, const std::string &key, SimpleMath::Vector3f& value) {
return serializer.SerializeData(key, reinterpret_cast<char*>(&value), sizeof(SimpleMath::Vector3f)); return serializer.SerializeData(key, reinterpret_cast<char*>(&value), sizeof(SimpleMath::Vector3f));
} }
template <typename Serializer>
bool SerializeVec4 (Serializer &serializer, const std::string &key, SimpleMath::Vector4f& value) {
return serializer.SerializeData(key, reinterpret_cast<char*>(&value), sizeof(SimpleMath::Vector4f));
}

View File

@ -15,7 +15,7 @@ using namespace SimpleMath::GL;
struct Renderer; struct Renderer;
float moving_factor = 1.0f; float moving_factor = 1.0f;
const int cNumSplits = 3; const int cNumSplits = 4;
struct RendererSettings { struct RendererSettings {
bool DrawLightDepth = false; bool DrawLightDepth = false;
@ -134,6 +134,9 @@ static void module_serialize (
SerializeBool(*serializer, "protot.RenderModule.mLight.mDebugDrawSplitViewBounds", gRenderer->mLight.mDebugDrawSplitViewBounds); SerializeBool(*serializer, "protot.RenderModule.mLight.mDebugDrawSplitViewBounds", gRenderer->mLight.mDebugDrawSplitViewBounds);
SerializeBool(*serializer, "protot.RenderModule.mLight.mDebugDrawSplitWorldBounds", gRenderer->mLight.mDebugDrawSplitWorldBounds); SerializeBool(*serializer, "protot.RenderModule.mLight.mDebugDrawSplitWorldBounds", gRenderer->mLight.mDebugDrawSplitWorldBounds);
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.mShadowSplits", gRenderer->mLight.mShadowSplits);
} }
static void module_finalize(struct module_state *state) { static void module_finalize(struct module_state *state) {
@ -239,6 +242,7 @@ void Light::DrawGui() {
ImGui::SliderFloat("Near", &mNear, -10.0f, 50.0f); ImGui::SliderFloat("Near", &mNear, -10.0f, 50.0f);
ImGui::SliderFloat("Far", &mFar, -10.0f, 50.0f); ImGui::SliderFloat("Far", &mFar, -10.0f, 50.0f);
ImGui::SliderFloat("Shadow Bias", &mShadowBias, 0.0f, 0.01f, "%.5f", 1.0f); ImGui::SliderFloat("Shadow Bias", &mShadowBias, 0.0f, 0.01f, "%.5f", 1.0f);
ImGui::SliderFloat4("Shadow Splits Bias", mSplitBias.data(), 0.0f, 0.01f, "%.5f", 1.0f);
ImGui::SliderFloat4("Shadow Splits", mShadowSplits.data(), 0.01f, 1.0f); ImGui::SliderFloat4("Shadow Splits", mShadowSplits.data(), 0.01f, 1.0f);
ImGui::Checkbox("Draw Split View Bounds", &mDebugDrawSplitViewBounds); ImGui::Checkbox("Draw Split View Bounds", &mDebugDrawSplitViewBounds);
@ -250,11 +254,12 @@ void Light::DrawGui() {
ImGui::RadioButton("Split 0", &sRendererSettings.ActiveShadowMapSplit, 0); ImGui::SameLine(); ImGui::RadioButton("Split 0", &sRendererSettings.ActiveShadowMapSplit, 0); ImGui::SameLine();
ImGui::RadioButton("Split 1", &sRendererSettings.ActiveShadowMapSplit, 1); ImGui::SameLine(); ImGui::RadioButton("Split 1", &sRendererSettings.ActiveShadowMapSplit, 1); ImGui::SameLine();
ImGui::RadioButton("Split 2", &sRendererSettings.ActiveShadowMapSplit, 2); ImGui::SameLine(); ImGui::RadioButton("Split 2", &sRendererSettings.ActiveShadowMapSplit, 2); ImGui::SameLine();
ImGui::RadioButton("Default", &sRendererSettings.ActiveShadowMapSplit, 3); ImGui::RadioButton("Split 3", &sRendererSettings.ActiveShadowMapSplit, 3); ImGui::SameLine();
ImGui::RadioButton("Default", &sRendererSettings.ActiveShadowMapSplit, 4);
RenderTarget* shadow_split_target = nullptr; RenderTarget* shadow_split_target = nullptr;
if (sRendererSettings.ActiveShadowMapSplit == 3) { if (sRendererSettings.ActiveShadowMapSplit == 4) {
shadow_split_target = &mShadowMapTarget; shadow_split_target = &mShadowMapTarget;
} else { } else {
shadow_split_target = &mSplitTarget[sRendererSettings.ActiveShadowMapSplit]; shadow_split_target = &mSplitTarget[sRendererSettings.ActiveShadowMapSplit];
@ -295,14 +300,16 @@ void Light::UpdateSplits(const Camera& camera) {
Matrix44f light_matrix = LookAt (mPosition, mPosition + mDirection, Vector3f (0.f, 1.0f, 0.0f)); Matrix44f light_matrix = LookAt (mPosition, mPosition + mDirection, Vector3f (0.f, 1.0f, 0.0f));
Matrix44f light_matrix_inv = light_matrix.inverse(); Matrix44f light_matrix_inv = light_matrix.inverse();
mShadowSplits[0] = near; mShadowSplits[0] = near + length * 0.02;
mShadowSplits[1] = near + length * 0.02; mShadowSplits[1] = near + length * 0.1;
mShadowSplits[2] = near + length * 0.2; mShadowSplits[2] = near + length * 0.3;
mShadowSplits[3] = far; mShadowSplits[3] = far;
float prev_split_far = near;
for (int i = 0; i < cNumSplits; ++i) { for (int i = 0; i < cNumSplits; ++i) {
split_near = mShadowSplits[i]; split_near = prev_split_far;
float split_far = mShadowSplits[i + 1]; float split_far = mShadowSplits[i];
mSplitViewFrustum[i] = look_at * Perspective (camera.mFov, aspect, split_near, split_far); mSplitViewFrustum[i] = look_at * Perspective (camera.mFov, aspect, split_near, split_far);
@ -369,6 +376,8 @@ void Light::UpdateSplits(const Camera& camera) {
mSplitLightFrustum[i] = mSplitCamera[i].mViewMatrix mSplitLightFrustum[i] = mSplitCamera[i].mViewMatrix
* mSplitCamera[i].mProjectionMatrix; * mSplitCamera[i].mProjectionMatrix;
prev_split_far = split_far;
} }
} }
} }
@ -929,12 +938,15 @@ void Renderer::RenderGl() {
glBindTexture(GL_TEXTURE_2D, mLight.mSplitTarget[1].mDepthTexture); glBindTexture(GL_TEXTURE_2D, mLight.mSplitTarget[1].mDepthTexture);
glActiveTexture(GL_TEXTURE7); glActiveTexture(GL_TEXTURE7);
glBindTexture(GL_TEXTURE_2D, mLight.mSplitTarget[2].mDepthTexture); glBindTexture(GL_TEXTURE_2D, mLight.mSplitTarget[2].mDepthTexture);
glActiveTexture(GL_TEXTURE8);
glBindTexture(GL_TEXTURE_2D, mLight.mSplitTarget[3].mDepthTexture);
GLint shadow_maps[3]; GLint shadow_maps[4];
shadow_maps[0] = 5; shadow_maps[0] = 5;
shadow_maps[1] = 6; shadow_maps[1] = 6;
shadow_maps[2] = 7; shadow_maps[2] = 7;
mDeferredLighting.SetIntArray("uShadowMap", 3, shadow_maps); shadow_maps[3] = 8;
mDeferredLighting.SetIntArray("uShadowMap", cNumSplits, shadow_maps);
Matrix44f light_matrices[3]; Matrix44f light_matrices[3];
@ -943,11 +955,12 @@ void Renderer::RenderGl() {
* mLight.mSplitLightFrustum[i]; * mLight.mSplitLightFrustum[i];
} }
mDeferredLighting.SetMat44Array("uViewToLightMatrix", 3, light_matrices); mDeferredLighting.SetMat44Array("uViewToLightMatrix", cNumSplits, light_matrices);
mDeferredLighting.SetFloat("uNear", mCamera.mNear); mDeferredLighting.SetFloat("uNear", mCamera.mNear);
mDeferredLighting.SetFloat("uFar", mCamera.mFar); mDeferredLighting.SetFloat("uFar", mCamera.mFar);
mDeferredLighting.SetVec4("uShadowSplits", mLight.mShadowSplits); mDeferredLighting.SetVec4("uShadowSplits", mLight.mShadowSplits);
mDeferredLighting.SetVec4("uShadowSplitBias", mLight.mSplitBias);
mDeferredLighting.SetMat44("uViewMatrix", mCamera.mViewMatrix); mDeferredLighting.SetMat44("uViewMatrix", mCamera.mViewMatrix);
Matrix33f view_mat_rot = mCamera.mViewMatrix.block<3,3>(0,0); Matrix33f view_mat_rot = mCamera.mViewMatrix.block<3,3>(0,0);

View File

@ -39,12 +39,13 @@ struct Light {
Vector4f mShadowSplits = Vector4f (0.0, 0.1, 0.4, 1.0); Vector4f mShadowSplits = Vector4f (0.0, 0.1, 0.4, 1.0);
Matrix44f mSplitViewFrustum[3]; Matrix44f mSplitViewFrustum[4];
Matrix44f mSplitLightFrustum[3]; Matrix44f mSplitLightFrustum[4];
RenderTarget mSplitTarget[3]; Vector4f mSplitBias = Vector4f (0.001f, 0.001f, 0.001f, 0.001f);
BBox mSplitBoundsLightSpace[3]; RenderTarget mSplitTarget[4];
BBox mSplitBoundsWorldSpace[3]; BBox mSplitBoundsLightSpace[4];
Camera mSplitCamera[3]; BBox mSplitBoundsWorldSpace[4];
Camera mSplitCamera[4];
Light() : Light() :
mPosition (Vector3f(0.f, 3, 0.0f)), mPosition (Vector3f(0.f, 3, 0.0f)),