diff --git a/data/shaders/fs_deferred_lighting.glsl b/data/shaders/fs_deferred_lighting.glsl index 21cb729..702b76f 100644 --- a/data/shaders/fs_deferred_lighting.glsl +++ b/data/shaders/fs_deferred_lighting.glsl @@ -95,7 +95,7 @@ void main() { float ambient_strength = 0.2; vec3 ambient = ambient_strength * color; - vec3 light_dir = uLightDirection; + vec3 light_dir = -uLightDirection; // diffuse lighting float diff = max(dot(normal, light_dir), 0.0); diff --git a/src/SimpleMath/SimpleMathGL.h b/src/SimpleMath/SimpleMathGL.h index d1f9ecd..a4c948e 100644 --- a/src/SimpleMath/SimpleMathGL.h +++ b/src/SimpleMath/SimpleMathGL.h @@ -102,6 +102,22 @@ inline Matrix44f Perspective(float fovy, float aspect, ); } +inline Matrix44f Frustum(float left, float right, + float bottom, float top, + float near, float far) { + float A = (right + left) / (right - left); + float B = (top + bottom) / (top - bottom); + float C = -(far + near) / (far - near); + float D = - (2.0f * far * near) / (far - near); + + return Matrix44f( + 2.0f * near / (right - left), 0.0f, 0.0f, 0.0f, + 0.0f, 2.0f * near / (top - bottom), 0.0f, 0.0f, + A, B, C, -1.0f, + 0.0f, 0.0f, D, 0.0f + ); +} + inline Matrix44f LookAt( const Vector3f& eye, const Vector3f& poi, diff --git a/src/modules/RenderModule.cc b/src/modules/RenderModule.cc index 136227a..24528af 100644 --- a/src/modules/RenderModule.cc +++ b/src/modules/RenderModule.cc @@ -15,10 +15,12 @@ using namespace SimpleMath::GL; struct Renderer; float moving_factor = 1.0f; +const int cNumSplits = 3; struct RendererSettings { bool DrawLightDepth = false; int RenderMode = 0; + int ActiveShadowMapSplit = 0; }; enum SceneRenderMode { @@ -203,13 +205,28 @@ void Light::Initialize() { RenderTarget::EnableColor | RenderTarget::EnableDepthTexture | RenderTarget::EnableLinearizedDepthTexture); + + mSplits[0].mShadowMapTarget.Initialize(mShadowMapSize, mShadowMapSize, + RenderTarget::EnableColor + | RenderTarget::EnableDepthTexture + | RenderTarget::EnableLinearizedDepthTexture); + + mSplits[1].mShadowMapTarget.Initialize(mShadowMapSize, mShadowMapSize, + RenderTarget::EnableColor + | RenderTarget::EnableDepthTexture + | RenderTarget::EnableLinearizedDepthTexture); + + mSplits[2].mShadowMapTarget.Initialize(mShadowMapSize, mShadowMapSize, + RenderTarget::EnableColor + | RenderTarget::EnableDepthTexture + | RenderTarget::EnableLinearizedDepthTexture); } void Light::UpdateMatrices() { mCamera.mIsOrthographic = true; mCamera.mEye = mPosition; - mCamera.mPoi = mPosition - mDirection; + mCamera.mPoi = mPosition + mDirection; mCamera.mUp = Vector3f (0.0f, 1.0f, 0.0f); mCamera.mProjectionMatrix = Ortho (-mBBoxSize * 0.5f, mBBoxSize * 0.5f, -mBBoxSize * 0.5f, mBBoxSize * 0.5f, mNear, mFar); @@ -230,11 +247,18 @@ void Light::DrawGui() { ImVec2 content_avail = ImGui::GetContentRegionAvail(); ImGui::Checkbox("Draw Light Depth", &sRendererSettings.DrawLightDepth); + + 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); + + RenderTarget* shadow_split_target = &mSplits[sRendererSettings.ActiveShadowMapSplit].mShadowMapTarget; + void* texture; if (sRendererSettings.DrawLightDepth) { - texture = (void*) mShadowMapTarget.mLinearizedDepthTexture; + texture = (void*) shadow_split_target->mLinearizedDepthTexture; } else { - texture = (void*) mShadowMapTarget.mColorTexture; + texture = (void*) shadow_split_target->mColorTexture; } ImGui::Image(texture, @@ -580,15 +604,29 @@ void Renderer::RenderGl() { mDebugCamera.mHeight = mSceneAreaHeight; } + // Cascaded Shadow Maps + for (int i = 0; i < cNumSplits; ++i) { + mLight.mSplits[i].mShadowMapTarget.Bind(); + glViewport(0, 0, mLight.mShadowMapSize, mLight.mShadowMapSize); + glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + glEnable(GL_DEPTH_TEST); + glUseProgram(mLight.mShadowMapProgram.mProgramId); + if (mLight.mShadowMapProgram.SetMat44("uLightSpaceMatrix", mLight.mSplits[i].mFrustum) == -1) { + gLog ("Warning: Uniform %s not found!", "uLightSpaceMatrix"); + } + RenderScene(mLight.mShadowMapProgram, mLight.mSplits[i].mCamera); + mLight.mShadowMapTarget.RenderToLinearizedDepth(mLight.mCamera.mNear, mLight.mCamera.mFar, true); + } + // Shadow Map mLight.mShadowMapTarget.Bind(); - mLight.mPosition = mCamera.mEye; glViewport(0, 0, mLight.mShadowMapSize, mLight.mShadowMapSize); mLight.UpdateMatrices(); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glEnable(GL_DEPTH_TEST); -// glCullFace(GL_FRONT); glUseProgram(mLight.mShadowMapProgram.mProgramId); + + // TODO: use mLight.mSplits to render shadow splits if (mLight.mShadowMapProgram.SetMat44("uLightSpaceMatrix", mLight.mLightSpaceMatrix) == -1) { gLog ("Warning: Uniform %s not found!", "uLightSpaceMatrix"); } @@ -809,13 +847,17 @@ void Renderer::DebugDrawShadowCascades() { float tan_half_hfov = tanf(0.5f * fov * M_PI / 180.0f); float tan_half_vfov = tanf(0.5f * aspect * fov * M_PI / 180.0f); - Vector3f eye (4., 4., 2.0); - Vector3f dir (1., 0., sin(gTimer->mCurrentTime)); + Vector3f eye (-4.0f, 4.4f, 0.0f); + Vector3f poi (-3.2f, 3.8f, 0.2f); + Vector3f dir = (poi - eye).normalized(); Matrix44f look_at = LookAt(eye, eye + dir, Vector3f (0., 1.0, 0.0)); + Matrix44f look_at_inv = look_at.inverse(); + Matrix44f light_matrix = LookAt (mLight.mPosition, mLight.mPosition + mLight.mDirection, Vector3f (0.f, 1.0f, 0.0f)); + Matrix44f light_matrix_inv = light_matrix.inverse(); // for (int i = 0; i < mLight.mShadowSplits.size(); ++i) { - for (int i = 0; i < 3; ++i) { + for (int i = 0; i < cNumSplits; ++i) { split_near = near + mLight.mShadowSplits[i] * length; float split_far = near + mLight.mShadowSplits[i + 1] * length; @@ -847,31 +889,21 @@ void Renderer::DebugDrawShadowCascades() { Vector4f (-xf, -yf, -split_far, 1.0f) }; - Vector4f frustum_corners_world[8]; - - float min_x = std::numeric_limits::max(); - float max_x = -std::numeric_limits::max(); - float min_y = std::numeric_limits::max(); - float max_y = -std::numeric_limits::max(); - float min_z = std::numeric_limits::max(); - float max_z = -std::numeric_limits::max(); + BBox bbox_world; + BBox bbox_light; for (int j = 0; j < 8; ++j) { Vector4f v_world = look_at.inverse().transpose() * frustum_corners[j]; + Vector4f v_light = light_matrix.transpose() * v_world; - frustum_corners_world[j] = v_world; // gLog("vworld %d: %.3f, %.3f, %.3f, %.3f", j, // v_world[0], // v_world[1], // v_world[2], // v_world[3]); - min_x = fmin(min_x, frustum_corners_world[j][0]); - max_x = fmax(max_x, frustum_corners_world[j][0]); - min_y = fmin(min_y, frustum_corners_world[j][1]); - max_y = fmax(max_y, frustum_corners_world[j][1]); - min_z = fmin(min_z, frustum_corners_world[j][2]); - max_z = fmax(max_z, frustum_corners_world[j][2]); + bbox_world.Update(v_world.block<3,1>(0,0)); + bbox_light.Update(v_light.block<3,1>(0,0)); } // gLog ("min/max %.3f,%.3f, %.3f,%.3f, %.3f,%.3f", @@ -880,23 +912,54 @@ void Renderer::DebugDrawShadowCascades() { // min_z, max_z // ); - Vector3f dimensions = Vector3f( - max_x - min_x, - max_y - min_y, - max_z - min_z - ) * 0.5f; + // Draw in world space + { + Vector3f dimensions = (bbox_world.mMax - bbox_world.mMin) * 0.5f; - Vector3f center = Vector3f (min_x, min_y, min_z) + dimensions; + Vector3f center = bbox_world.mMin + dimensions; - model_view_projection = - ScaleMat44 (dimensions[0], dimensions[1], dimensions[2]) - * TranslateMat44(center[0], center[1], center[2]) - * mCamera.mViewMatrix - * mCamera.mProjectionMatrix; - - mSimpleProgram.SetMat44("uModelViewProj", model_view_projection); - mSimpleProgram.SetVec4("uColor", Vector4f (0.0f, 1.0f, 1.0f, 1.0f)); - gUnitCubeLines.Draw(GL_LINES); + model_view_projection = + ScaleMat44 (dimensions[0], dimensions[1], dimensions[2]) + * TranslateMat44(center[0], center[1], center[2]) + * mCamera.mViewMatrix + * mCamera.mProjectionMatrix; + + mSimpleProgram.SetMat44("uModelViewProj", model_view_projection); + mSimpleProgram.SetVec4("uColor", Vector4f (0.0f, 1.0f, 1.0f, 1.0f)); +// gUnitCubeLines.Draw(GL_LINES); + } + + // Draw in light space + { + Vector3f dimensions = (bbox_light.mMax - bbox_light.mMin) * 0.5f; + Vector3f center = bbox_light.mMin + dimensions; + + mLight.mSplits[i].mCamera.mViewMatrix = light_matrix; + + // TODO: values for near and far planes are off + mLight.mSplits[i].mCamera.mProjectionMatrix = Ortho ( + bbox_light.mMin[0], bbox_light.mMax[0], + bbox_light.mMin[1], bbox_light.mMax[1], +// mLight.mNear, bbox_light.mMax[2] + mLight.mNear, mLight.mFar +// bbox_light.mMin[2], mLight.mFar +// bbox_light.mMin[2], bbox_light.mMax[2] + ) ; + + mLight.mSplits[i].mFrustum = + mLight.mSplits[i].mCamera.mViewMatrix + * mLight.mSplits[i].mCamera.mProjectionMatrix; + + model_view_projection = + mLight.mSplits[i].mFrustum.inverse() +// * light_matrix_inv + * mCamera.mViewMatrix + * mCamera.mProjectionMatrix; + + mSimpleProgram.SetMat44("uModelViewProj", model_view_projection); + mSimpleProgram.SetVec4("uColor", Vector4f (0.0f, 0.0f, 1.0f, 1.0f)); + gUnitCubeLines.Draw(GL_LINES); + } } // Disable wireframe @@ -920,12 +983,6 @@ void Renderer::RenderScene(RenderProgram &program, const Camera& camera) { program.SetMat33("uNormalMatrix", normal_matrix); program.SetVec4("uColor", Vector4f (1.0f, 1.0f, 1.0f, 1.0f)); - Vector3f light_dir = (camera.mViewMatrix * Vector4f ( - mLight.mDirection[0], - mLight.mDirection[1], - mLight.mDirection[2], - 1.0f - )).block<3,1>(0,0); // program.SetVec3("uLightDirection", light_dir.normalize()); program.SetVec3("uLightDirection", mLight.mDirection); program.SetVec3("uViewPosition", camera.mEye); diff --git a/src/modules/RenderModule.h b/src/modules/RenderModule.h index 8bbf26b..573ef6f 100644 --- a/src/modules/RenderModule.h +++ b/src/modules/RenderModule.h @@ -14,6 +14,19 @@ #include "Globals.h" #include "RenderUtils.h" +struct ShadowSplitInfo { + float mLeft; + float mRight; + float mTop; + float mBottom; + float mNear; + float mFar; + + Matrix44f mFrustum; + RenderTarget mShadowMapTarget; + Camera mCamera; +}; + struct Light { Vector3f mPosition; Vector3f mDirection; @@ -25,7 +38,6 @@ struct Light { float mShadowMapBias; uint16_t mShadowMapSize; - Vector4f mShadowSplits = Vector4f (0.0, 0.1, 0.4, 1.0); float mNear; float mFar; @@ -34,11 +46,14 @@ struct Light { Matrix44f mLightSpaceMatrix; + Vector4f mShadowSplits = Vector4f (0.0, 0.1, 0.4, 1.0); + ShadowSplitInfo mSplits[4]; + Light() : mPosition (Vector3f(0.f, 3, 0.0f)), mDirection (Vector3f(1.f, 1.f, 1.f)), mShadowMapBias (0.004f), - mShadowMapSize (1024), + mShadowMapSize (512), mNear (-10.0f), mFar (15.f), mBBoxSize (35.f), diff --git a/src/modules/RenderUtils.h b/src/modules/RenderUtils.h index 2c02a0d..2138704 100644 --- a/src/modules/RenderUtils.h +++ b/src/modules/RenderUtils.h @@ -135,6 +135,30 @@ struct Transform { } }; +struct BBox { + Vector3f mMin = Vector3f ( + std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::max() + ); + Vector3f mMax = Vector3f ( + - std::numeric_limits::max(), + - std::numeric_limits::max(), + - std::numeric_limits::max() + ); + + void Update (const Vector3f &v) { + mMin[0] = fmin(mMin[0], v[0]); + mMax[0] = fmax(mMax[0], v[0]); + mMin[1] = fmin(mMin[1], v[1]); + mMax[1] = fmax(mMax[1], v[1]); + mMin[2] = fmin(mMin[2], v[2]); + mMax[2] = fmax(mMax[2], v[2]); + } +}; + + + struct Camera { Vector3f mEye; Vector3f mPoi;