Working on getting shadow map splits properly rendered

simple_math_single_header
Martin Felis 2018-07-01 00:10:13 +02:00
parent 0fceeca4de
commit af7387175c
5 changed files with 159 additions and 47 deletions

View File

@ -95,7 +95,7 @@ void main() {
float ambient_strength = 0.2; float ambient_strength = 0.2;
vec3 ambient = ambient_strength * color; vec3 ambient = ambient_strength * color;
vec3 light_dir = uLightDirection; vec3 light_dir = -uLightDirection;
// diffuse lighting // diffuse lighting
float diff = max(dot(normal, light_dir), 0.0); float diff = max(dot(normal, light_dir), 0.0);

View File

@ -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( inline Matrix44f LookAt(
const Vector3f& eye, const Vector3f& eye,
const Vector3f& poi, const Vector3f& poi,

View File

@ -15,10 +15,12 @@ using namespace SimpleMath::GL;
struct Renderer; struct Renderer;
float moving_factor = 1.0f; float moving_factor = 1.0f;
const int cNumSplits = 3;
struct RendererSettings { struct RendererSettings {
bool DrawLightDepth = false; bool DrawLightDepth = false;
int RenderMode = 0; int RenderMode = 0;
int ActiveShadowMapSplit = 0;
}; };
enum SceneRenderMode { enum SceneRenderMode {
@ -203,13 +205,28 @@ void Light::Initialize() {
RenderTarget::EnableColor RenderTarget::EnableColor
| RenderTarget::EnableDepthTexture | RenderTarget::EnableDepthTexture
| RenderTarget::EnableLinearizedDepthTexture); | 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() { void Light::UpdateMatrices() {
mCamera.mIsOrthographic = true; mCamera.mIsOrthographic = true;
mCamera.mEye = mPosition; mCamera.mEye = mPosition;
mCamera.mPoi = mPosition - mDirection; mCamera.mPoi = mPosition + mDirection;
mCamera.mUp = Vector3f (0.0f, 1.0f, 0.0f); 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); 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(); ImVec2 content_avail = ImGui::GetContentRegionAvail();
ImGui::Checkbox("Draw Light Depth", &sRendererSettings.DrawLightDepth); 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; void* texture;
if (sRendererSettings.DrawLightDepth) { if (sRendererSettings.DrawLightDepth) {
texture = (void*) mShadowMapTarget.mLinearizedDepthTexture; texture = (void*) shadow_split_target->mLinearizedDepthTexture;
} else { } else {
texture = (void*) mShadowMapTarget.mColorTexture; texture = (void*) shadow_split_target->mColorTexture;
} }
ImGui::Image(texture, ImGui::Image(texture,
@ -580,15 +604,29 @@ void Renderer::RenderGl() {
mDebugCamera.mHeight = mSceneAreaHeight; 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 // Shadow Map
mLight.mShadowMapTarget.Bind(); mLight.mShadowMapTarget.Bind();
mLight.mPosition = mCamera.mEye;
glViewport(0, 0, mLight.mShadowMapSize, mLight.mShadowMapSize); glViewport(0, 0, mLight.mShadowMapSize, mLight.mShadowMapSize);
mLight.UpdateMatrices(); mLight.UpdateMatrices();
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
// glCullFace(GL_FRONT);
glUseProgram(mLight.mShadowMapProgram.mProgramId); glUseProgram(mLight.mShadowMapProgram.mProgramId);
// TODO: use mLight.mSplits to render shadow splits
if (mLight.mShadowMapProgram.SetMat44("uLightSpaceMatrix", mLight.mLightSpaceMatrix) == -1) { if (mLight.mShadowMapProgram.SetMat44("uLightSpaceMatrix", mLight.mLightSpaceMatrix) == -1) {
gLog ("Warning: Uniform %s not found!", "uLightSpaceMatrix"); 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_hfov = tanf(0.5f * fov * M_PI / 180.0f);
float tan_half_vfov = tanf(0.5f * aspect * 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 eye (-4.0f, 4.4f, 0.0f);
Vector3f dir (1., 0., sin(gTimer->mCurrentTime)); 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 = 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 < 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; split_near = near + mLight.mShadowSplits[i] * length;
float split_far = near + mLight.mShadowSplits[i + 1] * 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 (-xf, -yf, -split_far, 1.0f)
}; };
Vector4f frustum_corners_world[8]; BBox bbox_world;
BBox bbox_light;
float min_x = std::numeric_limits<float>::max();
float max_x = -std::numeric_limits<float>::max();
float min_y = std::numeric_limits<float>::max();
float max_y = -std::numeric_limits<float>::max();
float min_z = std::numeric_limits<float>::max();
float max_z = -std::numeric_limits<float>::max();
for (int j = 0; j < 8; ++j) { for (int j = 0; j < 8; ++j) {
Vector4f v_world = look_at.inverse().transpose() * frustum_corners[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, // gLog("vworld %d: %.3f, %.3f, %.3f, %.3f", j,
// v_world[0], // v_world[0],
// v_world[1], // v_world[1],
// v_world[2], // v_world[2],
// v_world[3]); // v_world[3]);
min_x = fmin(min_x, frustum_corners_world[j][0]); bbox_world.Update(v_world.block<3,1>(0,0));
max_x = fmax(max_x, frustum_corners_world[j][0]); bbox_light.Update(v_light.block<3,1>(0,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]);
} }
// gLog ("min/max %.3f,%.3f, %.3f,%.3f, %.3f,%.3f", // gLog ("min/max %.3f,%.3f, %.3f,%.3f, %.3f,%.3f",
@ -880,13 +912,11 @@ void Renderer::DebugDrawShadowCascades() {
// min_z, max_z // min_z, max_z
// ); // );
Vector3f dimensions = Vector3f( // Draw in world space
max_x - min_x, {
max_y - min_y, Vector3f dimensions = (bbox_world.mMax - bbox_world.mMin) * 0.5f;
max_z - min_z
) * 0.5f;
Vector3f center = Vector3f (min_x, min_y, min_z) + dimensions; Vector3f center = bbox_world.mMin + dimensions;
model_view_projection = model_view_projection =
ScaleMat44 (dimensions[0], dimensions[1], dimensions[2]) ScaleMat44 (dimensions[0], dimensions[1], dimensions[2])
@ -896,8 +926,41 @@ void Renderer::DebugDrawShadowCascades() {
mSimpleProgram.SetMat44("uModelViewProj", model_view_projection); mSimpleProgram.SetMat44("uModelViewProj", model_view_projection);
mSimpleProgram.SetVec4("uColor", Vector4f (0.0f, 1.0f, 1.0f, 1.0f)); 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); gUnitCubeLines.Draw(GL_LINES);
} }
}
// Disable wireframe // Disable wireframe
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
@ -920,12 +983,6 @@ void Renderer::RenderScene(RenderProgram &program, const Camera& camera) {
program.SetMat33("uNormalMatrix", normal_matrix); program.SetMat33("uNormalMatrix", normal_matrix);
program.SetVec4("uColor", Vector4f (1.0f, 1.0f, 1.0f, 1.0f)); 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", light_dir.normalize());
program.SetVec3("uLightDirection", mLight.mDirection); program.SetVec3("uLightDirection", mLight.mDirection);
program.SetVec3("uViewPosition", camera.mEye); program.SetVec3("uViewPosition", camera.mEye);

View File

@ -14,6 +14,19 @@
#include "Globals.h" #include "Globals.h"
#include "RenderUtils.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 { struct Light {
Vector3f mPosition; Vector3f mPosition;
Vector3f mDirection; Vector3f mDirection;
@ -25,7 +38,6 @@ struct Light {
float mShadowMapBias; float mShadowMapBias;
uint16_t mShadowMapSize; uint16_t mShadowMapSize;
Vector4f mShadowSplits = Vector4f (0.0, 0.1, 0.4, 1.0);
float mNear; float mNear;
float mFar; float mFar;
@ -34,11 +46,14 @@ struct Light {
Matrix44f mLightSpaceMatrix; Matrix44f mLightSpaceMatrix;
Vector4f mShadowSplits = Vector4f (0.0, 0.1, 0.4, 1.0);
ShadowSplitInfo mSplits[4];
Light() : Light() :
mPosition (Vector3f(0.f, 3, 0.0f)), mPosition (Vector3f(0.f, 3, 0.0f)),
mDirection (Vector3f(1.f, 1.f, 1.f)), mDirection (Vector3f(1.f, 1.f, 1.f)),
mShadowMapBias (0.004f), mShadowMapBias (0.004f),
mShadowMapSize (1024), mShadowMapSize (512),
mNear (-10.0f), mNear (-10.0f),
mFar (15.f), mFar (15.f),
mBBoxSize (35.f), mBBoxSize (35.f),

View File

@ -135,6 +135,30 @@ struct Transform {
} }
}; };
struct BBox {
Vector3f mMin = Vector3f (
std::numeric_limits<float>::max(),
std::numeric_limits<float>::max(),
std::numeric_limits<float>::max()
);
Vector3f mMax = Vector3f (
- std::numeric_limits<float>::max(),
- std::numeric_limits<float>::max(),
- std::numeric_limits<float>::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 { struct Camera {
Vector3f mEye; Vector3f mEye;
Vector3f mPoi; Vector3f mPoi;