diff --git a/include/Engine/Rendering/ShadowPass.h b/include/Engine/Rendering/ShadowPass.h index 685432c8..306ae8e0 100644 --- a/include/Engine/Rendering/ShadowPass.h +++ b/include/Engine/Rendering/ShadowPass.h @@ -33,9 +33,7 @@ public: void ClearBuffer(); void Draw(RenderScene& scene); - - - GLuint DepthMap() const { return m_DepthMap; } + GLuint DepthMap() const { return m_DepthMap[m_ShadowLevel]; } glm::mat4 lightSpaceMatrix() const { return m_LightSpaceMatrix; } glm::mat4 lightP() const { return m_LightProjection; } glm::mat4 lightV() const { return m_LightView; } @@ -44,18 +42,20 @@ public: private: - void CalculateFrustum(RenderScene & scene, std::shared_ptr directionalLightJob); + glm::mat4 CalculateFrustum(RenderScene & scene, std::shared_ptr directionalLightJob, glm::mat4& p, glm::mat4& v, ShadowCamera shad_cam); glm::vec3 LightDirectionToPoint(glm::vec4 direction); std::array UpdateFrustumPoints(Camera* cam, glm::vec3 center, glm::vec3 view_dir); void UpdateSplitDist(std::array shadow_cams, float far_distance, float near_distance); + void InitializeLightCameras(); + glm::mat4 ApplyCropMatrix(ShadowCamera& shadow_cam, glm::mat4 m, glm::mat4 v); + glm::mat4 FindNewFrustum(ShadowCamera shadow_cam); EventBroker* m_EventBroker; const IRenderer* m_Renderer; - GLuint m_DepthMap; - - FrameBuffer m_DepthBuffer; + std::array m_DepthMap; + std::array m_DepthBuffer; ShaderProgram* m_ShadowProgram; @@ -69,15 +69,16 @@ private: glm::mat4 m_LightView; glm::mat4 m_LightSpaceMatrix; - GLuint resolutionSizeWidth = 1024 * 8; - GLuint resolutionSizeHeigth = 1024 * 8; + GLuint resolutionSizeWidth = 1024 * 2; + GLuint resolutionSizeHeigth = 1024 * 2; bool m_ShadowOn = true; + int m_ShadowLevel = 0; int m_CurrentNrOfSplits = 3; float m_SplitWeight = 0.75f; - std::array shadCams; + std::array m_shadCams; }; #endif \ No newline at end of file diff --git a/resources/Shaders/ForwardPlus.frag.glsl b/resources/Shaders/ForwardPlus.frag.glsl index 205f1c5d..1f3ba711 100644 --- a/resources/Shaders/ForwardPlus.frag.glsl +++ b/resources/Shaders/ForwardPlus.frag.glsl @@ -143,9 +143,9 @@ float random(vec3 seed, int i) float CalcShadowValue(vec4 positionLightSpace, vec3 normal, vec3 lightDir, sampler2DShadow depthTexture) { - float bias = 0.005; + //float bias = 0.005; //float bias = max(0.05 * (1.0 - dot(normal, lightDir)), 0.005); - //float bias = 0.005 * tan(acos(clamp(dot(normal, -lightDir), 0.0, 1.0))); + float bias = 0.005 * tan(acos(clamp(dot(normal, -lightDir), 0.0, 1.0))); vec3 projCoords = vec3(positionLightSpace.xy, positionLightSpace.z + bias) / positionLightSpace.w; projCoords = projCoords * 0.5 + 0.5; diff --git a/src/Engine/Editor/EditorSystem.cpp b/src/Engine/Editor/EditorSystem.cpp index ccbc1b48..96b48874 100644 --- a/src/Engine/Editor/EditorSystem.cpp +++ b/src/Engine/Editor/EditorSystem.cpp @@ -17,7 +17,9 @@ EditorSystem::EditorSystem(World* world, EventBroker* eventBroker, IRenderer* re m_EditorCamera = importEntity(EntityWrapper(m_EditorWorld, EntityID_Invalid), "Schema/Entities/Empty.xml"); m_ActualCamera = m_EditorCamera; m_EditorWorld->AttachComponent(m_EditorCamera.ID, "Transform"); - m_EditorWorld->AttachComponent(m_EditorCamera.ID, "Camera"); + auto cCamera = m_EditorWorld->AttachComponent(m_EditorCamera.ID, "Camera"); + (double&)cCamera["FarClip"] = 30.0; + m_EditorCameraInputController = new EditorCameraInputController(m_EventBroker, -1); m_EditorGUI = new EditorGUI(m_World, m_EventBroker); diff --git a/src/Engine/Rendering/ShadowPass.cpp b/src/Engine/Rendering/ShadowPass.cpp index ca7b59f0..7be01b5b 100644 --- a/src/Engine/Rendering/ShadowPass.cpp +++ b/src/Engine/Rendering/ShadowPass.cpp @@ -11,7 +11,7 @@ ShadowPass::ShadowPass(IRenderer * renderer) ShadowPass::~ShadowPass() { - + // m_shadCams } // Compute the 8 corner points of the current view frustum @@ -25,28 +25,28 @@ std::array ShadowPass::UpdateFrustumPoints(Camera* cam, glm::vec3 up = glm::normalize(glm::cross(right, view_dir)); - float near_height = tan(cam->FOV() / 2.0f) * cam->NearClip(); + float near_height = tan(cam->FOV() / 2.f) * cam->NearClip(); float near_width = near_height * cam->AspectRatio(); - float far_height = tan(cam->FOV() / 2.0f) * cam->FarClip(); + float far_height = tan(cam->FOV() / 2.f) * cam->FarClip(); float far_width = far_height * cam->AspectRatio(); std::array frustumPoints; - frustumPoints[0] = nearCenter - up*near_height - right*near_width; - frustumPoints[1] = nearCenter + up*near_height - right*near_width; - frustumPoints[2] = nearCenter + up*near_height + right*near_width; - frustumPoints[3] = nearCenter - up*near_height + right*near_width; - - frustumPoints[4] = farCenter - up*far_height - right*far_width; - frustumPoints[5] = farCenter + up*far_height - right*far_width; - frustumPoints[6] = farCenter + up*far_height + right*far_width; - frustumPoints[7] = farCenter - up*far_height + right*far_width; + frustumPoints[0] = nearCenter - up * near_height - right * near_width; + frustumPoints[1] = nearCenter + up * near_height - right * near_width; + frustumPoints[2] = nearCenter + up * near_height + right * near_width; + frustumPoints[3] = nearCenter - up * near_height + right * near_width; + + frustumPoints[4] = farCenter - up * far_height - right * far_width; + frustumPoints[5] = farCenter + up * far_height - right * far_width; + frustumPoints[6] = farCenter + up * far_height + right * far_width; + frustumPoints[7] = farCenter - up * far_height + right * far_width; return frustumPoints; } // UpdateSplitDist computes the near and far distances for every frustum slice // in camera eye space - that is, at what distance does a slice start and end -void ShadowPass::UpdateSplitDist(std::array shadow_cams, float far_distance, float near_distance) +void ShadowPass::UpdateSplitDist(std::array shadow_cams, float near_distance, float far_distance) { float lambda = m_SplitWeight; float ratio = far_distance / near_distance; @@ -63,66 +63,165 @@ void ShadowPass::UpdateSplitDist(std::array shadow_cam shadow_cams[m_CurrentNrOfSplits - 1].camera->SetFarClip(far_distance); } -float applyCropMatrix() +glm::mat4 ShadowPass::FindNewFrustum(ShadowCamera shadow_cam) { + float maxX = -1000.0f; + float maxY = -1000.0f; + float maxZ; + float minX = 1000.0f; + float minY = 1000.0f; + float minZ; + glm::vec4 transf = glm::vec4(shadow_cam.frustumCorners[0], 1.f); + + //if (transf.x > maxX) maxX = transf.x; + //if (transf.x < minX) minX = transf.x; + //if (transf.y > maxY) maxY = transf.y; + //if (transf.y < minY) minY = transf.y; + + for (int i = 0; i < 8; i++) + { + transf = glm::vec4(shadow_cam.frustumCorners[i], 1.f); + + transf.x /= transf.w; + transf.y /= transf.w; + + if (transf.x > maxX) maxX = transf.x; + if (transf.x < minX) minX = transf.x; + if (transf.y > maxY) maxY = transf.y; + if (transf.y < minY) minY = transf.y; + } + + glm::mat4 p = glm::ortho(minX, maxX, minY, maxY, m_NearFarPlane[Near], m_NearFarPlane[Far]); + + return p; } -// GLM wants a point for glm::lookAt, brute out a point that is on the light direction's tangent. -glm::vec3 ShadowPass::LightDirectionToPoint(glm::vec4 direction) +glm::mat4 ShadowPass::ApplyCropMatrix(ShadowCamera& shadow_cam, glm::mat4 m, glm::mat4 v) { - return -glm::normalize(glm::vec3(direction)); + glm::mat4 shad_modelview; + glm::mat4 shad_proj; + glm::mat4 shad_crop; + glm::mat4 shad_mvp; + float maxX = -1000.0f; + float maxY = -1000.0f; + float maxZ; + float minX = 1000.0f; + float minY = 1000.0f; + float minZ; + + glm::mat4 nv_mvp; + glm::vec4 transf; + + shad_modelview = m * v; + nv_mvp = shad_modelview; + + transf = nv_mvp * glm::vec4(shadow_cam.frustumCorners[0], 1.f); + minZ = transf.z; + maxZ = transf.z; + + for (int i = 1; i < 8; i++) { + transf = nv_mvp * glm::vec4(shadow_cam.frustumCorners[i], 1.f); + if (transf.z > maxZ) { + maxZ = transf.z; + } + if (transf.z < minZ) { + minZ = transf.z; + } + } + + // make sure all relevant shadow casters are included here + + shad_proj = glm::ortho(-1.f, 1.f, -1.f, 1.f, m_NearFarPlane[0], m_NearFarPlane[1]); + + //return shad_proj; + + shad_mvp = shad_proj * shad_modelview; + + nv_mvp = shad_mvp; + + for (int i = 0; i < 8; i++) + { + transf = nv_mvp * glm::vec4(shadow_cam.frustumCorners[i], 1.0f); + + transf.x /= transf.w; + transf.y /= transf.w; + + if (transf.x > maxX) maxX = transf.x; + if (transf.x < minX) minX = transf.x; + if (transf.y > maxY) maxY = transf.y; + if (transf.y < minY) minY = transf.y; + } + + float scaleX = 2.0f / (maxX - minX); + float scaleY = 2.0f / (maxY - minY); + float offsetX = -0.5f*(maxX + minX)*scaleX; + float offsetY = -0.5f*(maxY + minY)*scaleY; + + nv_mvp = glm::mat4(); + nv_mvp[0][0] = scaleX; + nv_mvp[1][1] = scaleY; + nv_mvp[0][3] = offsetX; + nv_mvp[1][3] = offsetY; + glm::transpose(nv_mvp); + + shad_crop = nv_mvp; + shad_crop *= shad_proj; + + //return nv_mvp; + //return shad_crop; + return glm::mat4(); } -void ShadowPass::CalculateFrustum(RenderScene & scene, std::shared_ptr directionalLightJob) +void MakeShadowMap(glm::mat4 m, glm::mat4 v, glm::mat4 p, glm::vec3 light_dir) { - //m_LightView = glm::lookAt(LightDirectionToPoint(directionalLightJob->Direction), glm::vec3(0.f, 0.f, 0.f), glm::vec3(0.f, 1.f, 0.f)); + //float shad_modelview[16]; - m_LightProjection = glm::ortho(m_LRBT[Left], m_LRBT[Right], m_LRBT[Bottom], m_LRBT[Top], m_NearFarPlane[Near], m_NearFarPlane[Far]); - - glm::vec3 LightPoint = LightDirectionToPoint(directionalLightJob->Direction); + glDisable(GL_TEXTURE_2D); - float CameraDistance = scene.Camera->FarClip() - scene.Camera->NearClip(); - float CameraPercentiles[3] = { 0.f, CameraDistance * 0.2f, CameraDistance * 0.65f }; + glm::mat4 viewMatrix = glm::lookAt(glm::vec3(0.f), light_dir, glm::vec3(-1.f, 0.f, 0.f)); - - glm::vec3 point = scene.Camera->Position() + (scene.Camera->Forward() * 30.f); - - m_LightView = glm::lookAt(LightPoint + point, point, glm::vec3(0.f, 1.f, 0.f)); - m_LightSpaceMatrix = m_LightProjection * m_LightView; - //scene.Camera-> + + + + + + + glEnable(GL_TEXTURE_2D); +} + +glm::mat4 ShadowPass::CalculateFrustum(RenderScene & scene, std::shared_ptr directionalLightJob, glm::mat4& p, glm::mat4& v, ShadowCamera shad_cam) +{ + p = glm::ortho(m_LRBT[Left], m_LRBT[Right], m_LRBT[Bottom], m_LRBT[Top], m_NearFarPlane[Near], m_NearFarPlane[Far]); + v = glm::lookAt(glm::vec3(0.f) + shad_cam.camera->Position(), glm::vec3(directionalLightJob->Direction) + shad_cam.camera->Position(), glm::vec3(-1.f, 0.f, 0.f)); + + return p * v; } void ShadowPass::InitializeFrameBuffers() { - -// glGenRenderbuffers(1, &m_DepthFBO); -// glBindRenderbuffer(GL_RENDERBUFFER, m_DepthFBO); -// glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height); - // Depth texture - glGenTextures(1, &m_DepthMap); - glBindTexture(GL_TEXTURE_2D, m_DepthMap); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, resolutionSizeWidth, resolutionSizeHeigth, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr); - //glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height, 0, GL_RGB, GL_FLOAT, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, glm::vec4(1.f).data); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); - //glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY); + glGenTextures(m_CurrentNrOfSplits, m_DepthMap.data()); + for (int i = 0; i < m_CurrentNrOfSplits; i++) { + glBindTexture(GL_TEXTURE_2D, m_DepthMap[i]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, resolutionSizeWidth / (1 + i), resolutionSizeHeigth + (1 + i), 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); + glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, glm::vec4(1.f).data); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + //glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY); - m_DepthBuffer.AddResource(std::shared_ptr(new Texture2D(&m_DepthMap, GL_DEPTH_ATTACHMENT))); - //m_DepthBuffer.AddResource(std::shared_ptr(new Texture2D(&m_DepthMap, GL_COLOR_ATTACHMENT0))); - m_DepthBuffer.Generate(); + m_DepthBuffer[i].AddResource(std::shared_ptr(new Texture2D(&m_DepthMap[i], GL_DEPTH_ATTACHMENT))); + m_DepthBuffer[i].Generate(); + } GLERROR("depthMap failed"); - } void ShadowPass::InitializeShaderPrograms() @@ -135,74 +234,92 @@ void ShadowPass::InitializeShaderPrograms() m_ShadowProgram->Link(); } +void ShadowPass::InitializeLightCameras() +{ + //for (int i = 0; i < MAX_SPLITS; i++) { + // m_shadCams[i].camera = new Camera(1.f, ); + // Camera. + //} +} + void ShadowPass::ClearBuffer() { - m_DepthBuffer.Bind(); - glClearColor(0.f, 0.f, 0.f, 0.f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - m_DepthBuffer.Unbind(); + for (int i = 0; i < m_CurrentNrOfSplits; i++) { + m_DepthBuffer[i].Bind(); + glClearColor(0.f, 0.f, 0.f, 0.f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + m_DepthBuffer[i].Unbind(); + } } void ShadowPass::Draw(RenderScene & scene) { - ShadowPassState* state = new ShadowPassState(m_DepthBuffer.GetHandle()); + ImGui::DragFloat4("ShadowMapCam", m_LRBT, 1.f, -1000.f, 1000.f); + ImGui::DragFloat2("ShadowMapNearFar", m_NearFarPlane, 1.f, -1000.f, 1000.f); + ImGui::Checkbox("EnableShadow", &m_ShadowOn); + ImGui::DragInt("ShadowLevel", &m_ShadowLevel, 0.05f, 0, m_CurrentNrOfSplits - 1); - GLuint shaderHandle = m_ShadowProgram->GetHandle(); - m_ShadowProgram->Bind(); + for (int i = 0; i < m_CurrentNrOfSplits; i++) { + m_shadCams[i].camera = new Camera(*scene.Camera); + //m_shadCams[i].frustumCorners = tempPoints; + } - glViewport(0, 0, resolutionSizeWidth, resolutionSizeHeigth); + UpdateSplitDist(m_shadCams, scene.Camera->NearClip(), scene.Camera->FarClip()); + + for (int i = 0; i < m_CurrentNrOfSplits; i++) { + m_shadCams[i].frustumCorners = UpdateFrustumPoints(m_shadCams[i].camera, m_shadCams[i].camera->Position(), m_shadCams[i].camera->Forward()); - glCullFace(GL_FRONT); - //state->Disable(GL_CULL_FACE); + ShadowPassState* state = new ShadowPassState(m_DepthBuffer[i].GetHandle()); - ImGui::DragFloat4("ShadowMapCam", m_LRBT, 1.f, -1000.f, 1000.f); - ImGui::DragFloat2("ShadowMapNearFar", m_NearFarPlane, 1.f, -1000.f, 1000.f); - ImGui::Checkbox("EnableShadow", &m_ShadowOn); + GLuint shaderHandle = m_ShadowProgram->GetHandle(); + m_ShadowProgram->Bind(); - if (m_ShadowOn == true) - { - for (auto &job : scene.DirectionalLightJobs) { - auto directionalLightJob = std::dynamic_pointer_cast(job); - - if(directionalLightJob) { - CalculateFrustum(scene, directionalLightJob); + glViewport(0, 0, resolutionSizeWidth / (1 + i), resolutionSizeHeigth); + glDisable(GL_TEXTURE_2D); + glCullFace(GL_FRONT); + //state->Disable(GL_CULL_FACE); - glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(m_LightProjection)); - glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "V"), 1, GL_FALSE, glm::value_ptr(m_LightView)); + //m_LightProjection = FindNewFrustum(m_shadCams[0], m_LightProjection, m_LightProjection); - GLERROR("ShadowLight ERROR"); + if (m_ShadowOn == true) + { + for (auto &job : scene.DirectionalLightJobs) { + auto directionalLightJob = std::dynamic_pointer_cast(job); - for (auto &objectJob : scene.OpaqueObjects) { - auto modelJob = std::dynamic_pointer_cast(objectJob); - - glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->Matrix)); + if (directionalLightJob) { + m_LightSpaceMatrix = CalculateFrustum(scene, directionalLightJob, m_LightProjection, m_LightView, m_shadCams[i]); + m_LightProjection = FindNewFrustum(m_shadCams[i]); - glBindVertexArray(modelJob->Model->VAO); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelJob->Model->ElementBuffer); - glDrawElements(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, (void*)(modelJob->StartIndex * sizeof(unsigned int))); + glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(m_LightProjection)); + glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "V"), 1, GL_FALSE, glm::value_ptr(m_LightView)); - GLERROR("Shadow Draw ERROR"); + GLERROR("ShadowLight ERROR"); - } - - } + for (auto &objectJob : scene.OpaqueObjects) { + auto modelJob = std::dynamic_pointer_cast(objectJob); - m_DepthBuffer.Unbind(); + glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->Matrix)); - delete state; - - - } - } - - - - glViewport(0, 0, m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height); - glCullFace(GL_BACK); - m_ShadowProgram->Unbind(); + //glm::mat4 proj_mat = ApplyCropMatrix(m_shadCams[0], modelJob->Matrix, m_LightView); + //glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(proj_mat)); + glBindVertexArray(modelJob->Model->VAO); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelJob->Model->ElementBuffer); + glDrawElements(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, (void*)(modelJob->StartIndex * sizeof(unsigned int))); + GLERROR("Shadow Draw ERROR"); + } + } + m_DepthBuffer[i].Unbind(); + delete state; + } + } + glViewport(0, 0, m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height); + glEnable(GL_TEXTURE_2D); + glCullFace(GL_BACK); + m_ShadowProgram->Unbind(); + } }