diff --git a/imgui.ini b/imgui.ini index 39c660b..925f5a5 100644 --- a/imgui.ini +++ b/imgui.ini @@ -9,7 +9,7 @@ Size=894,195 Collapsed=0 [Window][Debug Utils] -Pos=37,5 +Pos=14,6 Size=863,335 Collapsed=0 diff --git a/res/shaders/basic.frag b/res/shaders/basic.frag index 2a0032d..6d9f1a6 100644 --- a/res/shaders/basic.frag +++ b/res/shaders/basic.frag @@ -5,6 +5,7 @@ layout(location = 0) out vec4 f_color; in vec3 v_normal; in vec2 v_texCoord; in vec3 v_fragmentPosition; +in vec4 v_fragmentPositionLightSpace; struct Material { sampler2D texture_diffuse0; @@ -63,6 +64,8 @@ uniform SpotLight u_spotLight; uniform mat3 u_normalMatrix; uniform vec3 u_viewPosition; +uniform sampler2D u_texture_shadowMap; + vec3 directionalLightContribution(DirectionalLight light, vec3 normal, vec3 viewDir); vec3 pointLightContribution(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir); vec3 spotLightContribution(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir); @@ -75,6 +78,8 @@ void computeShading( float computeAttenuation(vec3 lightPos, vec3 fragPos, float K_q); +float computeShadows(vec4 fragPosLightSpace); + void main() { vec3 fragmentColor = vec3(0.0f); @@ -88,6 +93,10 @@ void main() { fragmentColor += pointLightContribution(u_pointLight[i], normal, v_fragmentPosition, viewDir); } + // This is not final: ambient lighting should not be affected of shadows. + float shadows = computeShadows(v_fragmentPositionLightSpace); + fragmentColor *= (1.0f - shadows); + //fragmentColor += spotLightContribution(u_spotLight, normal, v_fragmentPosition, viewDir); f_color = vec4(fragmentColor, 1.0f); @@ -181,3 +190,20 @@ float computeAttenuation(vec3 lightPos, vec3 fragPos, float K_q) { return 1.0f / (K_q * distanceLightFragment * distanceLightFragment); } + +float computeShadows(vec4 fragPosLightSpace) { + + // Perspective divide + vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w; + + // Transform from [-1,1] to [0,1] + projCoords *= 0.5f; + projCoords += 0.5f; + + float closestDepth = texture(u_texture_shadowMap, projCoords.xy).r; + float currentDepth = projCoords.z; + + float shadow = currentDepth > closestDepth ? 1.0 : 0.0; + + return shadow; +} diff --git a/res/shaders/basic.vert b/res/shaders/basic.vert index 4f13209..b4af7cd 100644 --- a/res/shaders/basic.vert +++ b/res/shaders/basic.vert @@ -8,14 +8,18 @@ out vec3 v_normal; out vec2 v_texCoord; out vec3 v_fragmentPosition; +out vec4 v_fragmentPositionLightSpace; uniform mat4 u_modelViewProjMatrix; uniform mat4 u_modelMatrix; +uniform mat4 u_lightViewProjMatrix; + void main() { gl_Position = u_modelViewProjMatrix * vec4(a_position, 1.0f); v_fragmentPosition = vec3(u_modelMatrix * vec4(a_position, 1.0f)); + v_fragmentPositionLightSpace = u_lightViewProjMatrix * vec4(v_fragmentPosition, 1.0); v_normal = a_normal; v_texCoord = a_texCoord; diff --git a/res/shaders/shadowDepth.frag b/res/shaders/shadowDepth.frag new file mode 100644 index 0000000..6087418 --- /dev/null +++ b/res/shaders/shadowDepth.frag @@ -0,0 +1,5 @@ +#version 330 core + +void main() { + +} \ No newline at end of file diff --git a/res/shaders/shadowDepth.vert b/res/shaders/shadowDepth.vert new file mode 100644 index 0000000..dec698e --- /dev/null +++ b/res/shaders/shadowDepth.vert @@ -0,0 +1,11 @@ +#version 330 core + +layout(location = 0) in vec3 a_position; + +uniform mat4 u_modelViewProjMatrix; + +void main() { + + gl_Position = u_modelViewProjMatrix * vec4(a_position, 1.0f); + +} \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 936a4ab..a66d9bf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,7 +13,6 @@ add_executable(Fall-Fever Light.cpp World.cpp Framebuffer.cpp - Shadows.cpp ) target_link_libraries( diff --git a/src/Controller.cpp b/src/Controller.cpp index 2f12890..e1ce563 100644 --- a/src/Controller.cpp +++ b/src/Controller.cpp @@ -80,6 +80,7 @@ void Controller::run() { ShaderProgram lightProgram("res/shaders/light.vert", "res/shaders/light.frag"); ShaderProgram skyboxProgram("res/shaders/skybox.vert", "res/shaders/skybox.frag"); ShaderProgram postProcessingProgram("res/shaders/postprocessing.vert", "res/shaders/postprocessing.frag"); + ShaderProgram shadowDepthProgram("res/shaders/shadowDepth.vert", "res/shaders/shadowDepth.frag"); updateExposure(&postProcessingProgram); @@ -126,13 +127,14 @@ void Controller::run() { // Update game // ... - static bool rotateLightSource = 0; + static bool rotateLightSource = false; if(rotateLightSource) { float radius = 4.0; glm::vec3 newPos = glm::vec3(-cos(glfwGetTime()*0.5), 0.5f, sin(glfwGetTime()*0.5)) * radius; world.getEntities()->operator[](1).setPosition(newPos); } - static glm::vec3 lightColor = glm::vec3(1.f); static float intensity = 1.0f; + static glm::vec3 lightColor = glm::vec3(1.f); + static float intensity = 20.0f; world.updatePointLight(0, true, world.getEntities()->operator[](1).getPosition(), lightColor * intensity); world.updateDirectionalLight(true, glm::vec3(-0.2f, -1.0f, -0.3f), lightColor * 0.1f); lightProgram.bind(); @@ -154,12 +156,16 @@ void Controller::run() { glViewport(0, 0, gameWindow->getWindowWidth(), gameWindow->getWindowHeight()); skybox.draw(camera->getView(), camera->getProj()); world.draw(camera->getViewProj(), camera->getPosition()); - pp_framebuffer->unbind(); + static bool drawShadows = false; + if(drawShadows) + world.calculateShadows(&shadowDepthProgram); + + pp_framebuffer->unbind(); pp_framebuffer->render(); #ifdef _DEBUG - renderImGui(world.getEntities(), &world.getPointLights()[0], &lightColor, &rotateLightSource, &postProcessingProgram, &intensity); + renderImGui(world.getEntities(), &world.getPointLights()[0], &lightColor, &rotateLightSource, &postProcessingProgram, &intensity, &drawShadows); #endif glfwSwapBuffers(gameWindow->getGLFWwindow()); @@ -222,7 +228,7 @@ void Controller::updateExposure(ShaderProgram *shaderProgram) { } #ifdef _DEBUG -void Controller::renderImGui(std::vector *entites, PointLight *pointLight, glm::vec3 *lightColor, bool *rotateLightSource, ShaderProgram *postProcessingProgram, float *intensity) { +void Controller::renderImGui(std::vector *entites, PointLight *pointLight, glm::vec3 *lightColor, bool *rotateLightSource, ShaderProgram *postProcessingProgram, float *intensity, bool *drawShadows) { ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); @@ -244,7 +250,7 @@ void Controller::renderImGui(std::vector *entites, PointLight *pointLigh // color picker ImGui::Text("\nLight Source"); - static float K_q = 0.062f; + static float K_q = 1.0f; ImGui::SliderFloat("Attenuation Parameter", &K_q, 0, 1.5f); updateExposure(postProcessingProgram); @@ -262,6 +268,7 @@ void Controller::renderImGui(std::vector *entites, PointLight *pointLigh ImGui::Text("\nMiscellaneous"); ImGui::SliderFloat("Exposure", &exposure, 0, 5.0f); + ImGui::Checkbox("Draw Shadows", drawShadows); ImGui::Checkbox("Rotate Lightsource", rotateLightSource); ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", diff --git a/src/Controller.h b/src/Controller.h index 72f1b3b..b5b5a3a 100644 --- a/src/Controller.h +++ b/src/Controller.h @@ -29,7 +29,7 @@ private: void updateWindowSize(ShaderProgram *pp_program); void updateExposure(ShaderProgram *shaderProgram); - void renderImGui(std::vector *entites, PointLight *pointLight, glm::vec3 *lightColor, bool *rotateLightSource, ShaderProgram *postProcessingProgram, float *intensity); + void renderImGui(std::vector *entites, PointLight *pointLight, glm::vec3 *lightColor, bool *rotateLightSource, ShaderProgram *postProcessingProgram, float *intensity, bool *drawShadows); Window *gameWindow; EventHandler *gameEventHandler; diff --git a/src/Entity.cpp b/src/Entity.cpp index b98edf6..949f254 100644 --- a/src/Entity.cpp +++ b/src/Entity.cpp @@ -32,6 +32,20 @@ void Entity::draw(glm::mat4 viewProjMatrix, glm::vec3 viewPosition) { } +void Entity::drawShadows(glm::mat4 viewProjMatrix, ShaderProgram *p_shaderProgram) { + + p_shaderProgram->bind(); + + glm::mat4 modelViewProj = viewProjMatrix * modelMatrix; + shaderProgram->setUniform("u_modelViewProjMatrix", modelViewProj); + + // Draw the model + model->drawWithoutTextures(); + + p_shaderProgram->unbind(); + +} + void Entity::translate(glm::vec3 vector) { position += vector; updateModelMatrix(); diff --git a/src/Entity.h b/src/Entity.h index 635789e..cdb3b46 100644 --- a/src/Entity.h +++ b/src/Entity.h @@ -15,6 +15,7 @@ public: ~Entity() = default; void draw(glm::mat4 viewProjMatrix, glm::vec3 viewPosition); + void drawShadows(glm::mat4 viewProjMatrix, ShaderProgram *p_shaderProgram); void translate(glm::vec3 vector); void rotate(glm::vec3 axis, float radians); diff --git a/src/Framebuffer.cpp b/src/Framebuffer.cpp index fab34f4..1b91a38 100644 --- a/src/Framebuffer.cpp +++ b/src/Framebuffer.cpp @@ -1,6 +1,7 @@ #include "Framebuffer.h" #include +#include Framebuffer::Framebuffer(uint32_t width, uint32_t height, ShaderProgram *shaderProgram) { @@ -19,6 +20,7 @@ Framebuffer::Framebuffer(uint32_t width, uint32_t height, ShaderProgram *shaderP glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, width, height, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glBindTexture(GL_TEXTURE_2D, 0); bind(); @@ -66,24 +68,25 @@ void Framebuffer::render() { -DepthMap::DepthMap(int resolution) { +DepthMap::DepthMap(int RESOLUTION) { glGenFramebuffers(1, &depthMapFBO); - unsigned int depthMap; glGenTextures(1, &depthMap); glBindTexture(GL_TEXTURE_2D, depthMap); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, resolution, resolution, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, RESOLUTION, RESOLUTION, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO); + glBindTexture(GL_TEXTURE_2D, 0); + + bind(); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthMap, 0); glDrawBuffer(GL_NONE); glReadBuffer(GL_NONE); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + unbind(); } diff --git a/src/Framebuffer.h b/src/Framebuffer.h index 5d01ed6..56e6098 100644 --- a/src/Framebuffer.h +++ b/src/Framebuffer.h @@ -33,13 +33,16 @@ class DepthMap { public: - DepthMap(int resolution); + DepthMap(int RESOLUTION); void bind(); void unbind(); + GLuint getDepthMap() { return depthMap; } + private: GLuint depthMapFBO; + GLuint depthMap; }; \ No newline at end of file diff --git a/src/Light.h b/src/Light.h index 0e3ba06..4268a89 100644 --- a/src/Light.h +++ b/src/Light.h @@ -39,6 +39,7 @@ protected: ShaderProgram *shaderProgram; bool isActive = false; + bool shouldCastShadow = true; // Color glm::vec3 lightColor; diff --git a/src/Model.cpp b/src/Model.cpp index 692349f..b43955d 100644 --- a/src/Model.cpp +++ b/src/Model.cpp @@ -28,6 +28,15 @@ void Model::draw(ShaderProgram *shaderProgram) { } +void Model::drawWithoutTextures() { + + // Iterate through every mesh and call the draw function + for(auto it = meshes.begin(); it != meshes.end(); it++) { + (*it)->drawWithoutTextures(); + } + +} + void Model::loadModel(std::string pathToModel) { std::ifstream input(pathToModel, std::ios::in | std::ios::binary); diff --git a/src/Model.h b/src/Model.h index b3c1791..59548b0 100644 --- a/src/Model.h +++ b/src/Model.h @@ -13,6 +13,7 @@ public: ~Model(); void draw(ShaderProgram *shaderProgram); + void drawWithoutTextures(); Mesh * getMesh(unsigned int index) { return meshes[index]; } diff --git a/src/Shadows.cpp b/src/Shadows.cpp deleted file mode 100644 index 4dc3a54..0000000 --- a/src/Shadows.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "Shadows.h" - -#include -#include - -Shadows::Shadows() - : depthMap(SHADOW_RES) { - -} - -void Shadows::calculate() { - - glViewport(0, 0, SHADOW_RES, SHADOW_RES); - depthMap.bind(); - glClear(GL_DEPTH_BUFFER_BIT); - // ConfigureShaderAndMatrices(); - float near_plane = 1.0f, far_plane = 7.5f; - glm::mat4 lightProjection = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, near_plane, far_plane); - glm::mat4 lightView = glm::lookAt(glm::vec3(-0.2f, -1.0f, -0.3f), glm::vec3( 0.0f, 0.0f, 0.0f), glm::vec3( 0.0f, 1.0f, 0.0f)); - glm::mat4 lightSpaceMatrix = lightProjection * lightView; - // RenderScene(); - depthMap.unbind(); - -} diff --git a/src/Shadows.h b/src/Shadows.h deleted file mode 100644 index bbe6fd7..0000000 --- a/src/Shadows.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include "Framebuffer.h" - -class Shadows { - -public: - - Shadows(); - - void calculate(); - -private: - - DepthMap depthMap; - - const int SHADOW_RES = 1024; - -}; \ No newline at end of file diff --git a/src/World.cpp b/src/World.cpp index 2eeaf6c..d686489 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -7,7 +7,7 @@ // constructors for Light and PointLight have only this reason to exist. World::World(ShaderProgram *shaderProgram) - : shaderProgram(shaderProgram) { + : shaderProgram(shaderProgram), depthMapFBO(SHADOW_RES) { // PointLights for(unsigned int i = 0; i < NUM_POINT_LIGHTS; i++) { @@ -57,8 +57,55 @@ void World::updateDirectionalLight(bool active, glm::vec3 direction, glm::vec3 c void World::draw(glm::mat4 viewProjMatrix, glm::vec3 viewPosition) { + // Draw all entities for(auto it = entities.begin(); it != entities.end(); it++) { it->draw(viewProjMatrix, viewPosition); } + // Calculate shadows + // calculateShadows(); + +} + +void World::calculateShadows(ShaderProgram *p_shaderProgram) { + + // Get old viewport dimensions to reset them later... + GLint VIEWPORT[4]; + glGetIntegerv(GL_VIEWPORT, VIEWPORT); + + glViewport(0, 0, SHADOW_RES, SHADOW_RES); + + depthMapFBO.bind(); + + glClear(GL_DEPTH_BUFFER_BIT); + // ConfigureShaderAndMatrices(); + float near_plane = 0.1f, far_plane = 7.5f; + glm::mat4 lightProjection = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, near_plane, far_plane); + glm::mat4 lightView = glm::lookAt(-glm::vec3(-0.2f, -1.0f, -0.3f), glm::vec3( 0.0f, 0.0f, 0.0f), glm::vec3( 0.0f, 1.0f, 0.0f)); + glm::mat4 lightViewProjectionMatrix = lightProjection * lightView; + + // Draw scene from light perspective + // Draw all entities + for(auto it = entities.begin(); it != entities.end(); it++) { + it->drawShadows(lightViewProjectionMatrix, p_shaderProgram); + } + + depthMapFBO.unbind(); + + // Reset viewport size + glViewport(VIEWPORT[0], VIEWPORT[1], VIEWPORT[2], VIEWPORT[3]); + + shaderProgram->bind(); + + // Send lightViewProjMatrix to basic shader + shaderProgram->setUniform("u_lightViewProjMatrix", lightViewProjectionMatrix); + + // Send shadowMap to basic shader + const int textureUnit = TEXTURE_TYPE_NUM_ITEMS * 2; + shaderProgram->setUniform("u_texture_shadowMap", (int)textureUnit); + glActiveTexture(GL_TEXTURE0 + textureUnit); + glBindTexture(GL_TEXTURE_2D, depthMapFBO.getDepthMap()); + + shaderProgram->unbind(); + } diff --git a/src/World.h b/src/World.h index 9763a44..28e8aef 100644 --- a/src/World.h +++ b/src/World.h @@ -5,6 +5,8 @@ #include "Light.h" #include "Camera.h" #include "Entity.h" +#include "ShaderProgram.h" +#include "Framebuffer.h" class World { @@ -24,6 +26,7 @@ public: PointLight * getPointLights() { return pointLights; } void draw(glm::mat4 viewProjMatrix, glm::vec3 viewPosition); + void calculateShadows(ShaderProgram *shaderProgram); private: @@ -31,8 +34,13 @@ private: std::vector entities; + // Lights DirectionalLight directionalLight; PointLight pointLights[NUM_POINT_LIGHTS]; //SpotLight spotLight; + // Shadows + const int SHADOW_RES = 1024; + DepthMap depthMapFBO; + };