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 uAmbientOcclusion;
const int NUM_SPLITS = 3;
const int NUM_SPLITS = 4;
#define USE_SAMPLER2D_SHADOW 1
@ -21,6 +21,7 @@ uniform mat4 uViewToLightMatrix[NUM_SPLITS];
uniform float uNear;
uniform float uFar;
uniform vec4 uShadowSplits;
uniform vec4 uShadowSplitBias;
uniform vec3 uLightDirection;
uniform float uShadowBias;
@ -29,9 +30,9 @@ in vec2 ioFragTexCoords;
out vec3 outColor;
#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
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
vec3 projected_coordinates = frag_pos_light_space.xyz / frag_pos_light_space.w;
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 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;
vec2 texel_size = 1.0 / textureSize(shadow_map, 0);
@ -101,19 +102,23 @@ void main() {
float shadow = 0;
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)
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(uShadowMap[0], position_light_space, normal);
} else if (-position.z< uShadowSplits[2]) {
shadow = ShadowCalculationPCF(uShadowMap[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(uShadowMap[1], position_light_space, normal);
} else {
shadow = ShadowCalculationPCF(uShadowMap[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(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);

View File

@ -137,3 +137,8 @@ template <typename Serializer>
bool SerializeVec3 (Serializer &serializer, const std::string &key, SimpleMath::Vector3f& value) {
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;
float moving_factor = 1.0f;
const int cNumSplits = 3;
const int cNumSplits = 4;
struct RendererSettings {
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.mDebugDrawSplitWorldBounds", gRenderer->mLight.mDebugDrawSplitWorldBounds);
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) {
@ -239,6 +242,7 @@ void Light::DrawGui() {
ImGui::SliderFloat("Near", &mNear, -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::SliderFloat4("Shadow Splits Bias", mSplitBias.data(), 0.0f, 0.01f, "%.5f", 1.0f);
ImGui::SliderFloat4("Shadow Splits", mShadowSplits.data(), 0.01f, 1.0f);
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 1", &sRendererSettings.ActiveShadowMapSplit, 1); 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;
if (sRendererSettings.ActiveShadowMapSplit == 3) {
if (sRendererSettings.ActiveShadowMapSplit == 4) {
shadow_split_target = &mShadowMapTarget;
} else {
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_inv = light_matrix.inverse();
mShadowSplits[0] = near;
mShadowSplits[1] = near + length * 0.02;
mShadowSplits[2] = near + length * 0.2;
mShadowSplits[0] = near + length * 0.02;
mShadowSplits[1] = near + length * 0.1;
mShadowSplits[2] = near + length * 0.3;
mShadowSplits[3] = far;
float prev_split_far = near;
for (int i = 0; i < cNumSplits; ++i) {
split_near = mShadowSplits[i];
float split_far = mShadowSplits[i + 1];
split_near = prev_split_far;
float split_far = mShadowSplits[i];
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
* mSplitCamera[i].mProjectionMatrix;
prev_split_far = split_far;
}
}
}
@ -929,12 +938,15 @@ void Renderer::RenderGl() {
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[3];
GLint shadow_maps[4];
shadow_maps[0] = 5;
shadow_maps[1] = 6;
shadow_maps[2] = 7;
mDeferredLighting.SetIntArray("uShadowMap", 3, shadow_maps);
shadow_maps[3] = 8;
mDeferredLighting.SetIntArray("uShadowMap", cNumSplits, shadow_maps);
Matrix44f light_matrices[3];
@ -943,11 +955,12 @@ void Renderer::RenderGl() {
* mLight.mSplitLightFrustum[i];
}
mDeferredLighting.SetMat44Array("uViewToLightMatrix", 3, light_matrices);
mDeferredLighting.SetMat44Array("uViewToLightMatrix", cNumSplits, light_matrices);
mDeferredLighting.SetFloat("uNear", mCamera.mNear);
mDeferredLighting.SetFloat("uFar", mCamera.mFar);
mDeferredLighting.SetVec4("uShadowSplits", mLight.mShadowSplits);
mDeferredLighting.SetVec4("uShadowSplitBias", mLight.mSplitBias);
mDeferredLighting.SetMat44("uViewMatrix", mCamera.mViewMatrix);
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);
Matrix44f mSplitViewFrustum[3];
Matrix44f mSplitLightFrustum[3];
RenderTarget mSplitTarget[3];
BBox mSplitBoundsLightSpace[3];
BBox mSplitBoundsWorldSpace[3];
Camera mSplitCamera[3];
Matrix44f mSplitViewFrustum[4];
Matrix44f mSplitLightFrustum[4];
Vector4f mSplitBias = Vector4f (0.001f, 0.001f, 0.001f, 0.001f);
RenderTarget mSplitTarget[4];
BBox mSplitBoundsLightSpace[4];
BBox mSplitBoundsWorldSpace[4];
Camera mSplitCamera[4];
Light() :
mPosition (Vector3f(0.f, 3, 0.0f)),