diff --git a/src/5.advanced_lighting/5.parallax_mapping/parallax_mapping.cpp b/src/5.advanced_lighting/5.parallax_mapping/parallax_mapping.cpp index 693c4b5..95dcb8b 100644 --- a/src/5.advanced_lighting/5.parallax_mapping/parallax_mapping.cpp +++ b/src/5.advanced_lighting/5.parallax_mapping/parallax_mapping.cpp @@ -115,8 +115,8 @@ int main() glUniformMatrix4fv(glGetUniformLocation(shader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view)); glUniformMatrix4fv(glGetUniformLocation(shader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); // Render normal-mapped quad - glm::mat4 model; - model = glm::rotate(model, (GLfloat)glfwGetTime() * -10, glm::normalize(glm::vec3(1.0, 0.0, 1.0))); // Rotates the quad to show parallax mapping works in all directions + glm::mat4 model; + //model = glm::rotate(model, (GLfloat)glfwGetTime() * -10, glm::normalize(glm::vec3(1.0, 0.0, 1.0))); // Rotates the quad to show parallax mapping works in all directions glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); glUniform3fv(glGetUniformLocation(shader.Program, "lightPos"), 1, &lightPos[0]); glUniform3fv(glGetUniformLocation(shader.Program, "viewPos"), 1, &camera.Position[0]); @@ -282,9 +282,9 @@ void Do_Movement() // Change parallax height scale if (keys[GLFW_KEY_Q]) - height_scale -= 0.001; + height_scale -= 0.05 * deltaTime; else if (keys[GLFW_KEY_E]) - height_scale += 0.001; + height_scale += 0.05 * deltaTime; // Enable/disable parallax mapping if (keys[GLFW_KEY_SPACE] && !keysPressed[GLFW_KEY_SPACE]) diff --git a/src/5.advanced_lighting/5.parallax_mapping/parallax_mapping.frag b/src/5.advanced_lighting/5.parallax_mapping/parallax_mapping.frag index d5444cc..e13f05b 100644 --- a/src/5.advanced_lighting/5.parallax_mapping/parallax_mapping.frag +++ b/src/5.advanced_lighting/5.parallax_mapping/parallax_mapping.frag @@ -22,8 +22,8 @@ vec2 ParallaxMapping(vec2 texCoords, vec3 viewDir) // return texCoords - viewDir.xy * (height * height_scale); // number of depth layers - const float minLayers = 10; - const float maxLayers = 20; + const float minLayers = 8; + const float maxLayers = 32; float numLayers = mix(maxLayers, minLayers, abs(dot(vec3(0.0, 0.0, 1.0), viewDir))); // calculate the size of each layer float layerDepth = 1.0 / numLayers; diff --git a/src/5.advanced_lighting/6.hdr/hdr.cpp b/src/5.advanced_lighting/6.hdr/hdr.cpp index b51efb8..c80532d 100644 --- a/src/5.advanced_lighting/6.hdr/hdr.cpp +++ b/src/5.advanced_lighting/6.hdr/hdr.cpp @@ -1,6 +1,3 @@ -// Std. Includes -#include - // GLEW #define GLEW_STATIC #include @@ -21,7 +18,7 @@ #include // Properties -GLuint screenWidth = 800, screenHeight = 600; +const GLuint SCR_WIDTH = 800, SCR_HEIGHT = 600; // Function prototypes void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode); @@ -29,16 +26,24 @@ void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); void mouse_callback(GLFWwindow* window, double xpos, double ypos); void Do_Movement(); GLuint loadTexture(GLchar* path); +void RenderScene(Shader &shader); +void RenderCube(); +void RenderQuad(); // Camera -Camera camera(glm::vec3(0.0f, 0.0f, 3.0f)); -bool keys[1024]; -GLfloat lastX = 400, lastY = 300; -bool firstMouse = true; +Camera camera(glm::vec3(0.0f, 0.0f, 5.0f)); +// Delta GLfloat deltaTime = 0.0f; GLfloat lastFrame = 0.0f; +// Options +GLboolean hdr = true; // Change with 'Space' +GLfloat exposure = 1.0f; // Change with Q and E + +// Global variables +GLuint woodTexture; + // The MAIN function, from here we start our application and run our Game loop int main() { @@ -49,7 +54,7 @@ int main() glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); - GLFWwindow* window = glfwCreateWindow(screenWidth, screenHeight, "LearnOpenGL", nullptr, nullptr); // Windowed + GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", nullptr, nullptr); // Windowed glfwMakeContextCurrent(window); // Set the required callback functions @@ -65,103 +70,59 @@ int main() glewInit(); // Define the viewport dimensions - glViewport(0, 0, screenWidth, screenHeight); + glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT); // Setup some OpenGL options glEnable(GL_DEPTH_TEST); - // glDepthFunc(GL_ALWAYS); // Set to always pass the depth test (same effect as glDisable(GL_DEPTH_TEST)) // Setup and compile our shaders - Shader shader("depth_testing.vs", "depth_testing.frag"); + Shader shader("lighting.vs", "lighting.frag"); + Shader hdrShader("hdr.vs", "hdr.frag"); - #pragma region "object_initialization" - // Set the object data (buffers, vertex attributes) - GLfloat cubeVertices[] = { - // Positions // Texture Coords - -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, - 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, - 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, - -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, - - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, - -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - - -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - - -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - 0.5f, -0.5f, -0.5f, 1.0f, 1.0f, - 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, - 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - - -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, - 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, - -0.5f, 0.5f, -0.5f, 0.0f, 1.0f - }; - GLfloat planeVertices[] = { - // Positions // Texture Coords (note we set these higher than 1 that together with GL_REPEAT as texture wrapping mode will cause the floor texture to repeat) - 5.0f, -0.5f, 5.0f, 2.0f, 0.0f, - -5.0f, -0.5f, 5.0f, 0.0f, 0.0f, - -5.0f, -0.5f, -5.0f, 0.0f, 2.0f, - - 5.0f, -0.5f, 5.0f, 2.0f, 0.0f, - -5.0f, -0.5f, -5.0f, 0.0f, 2.0f, - 5.0f, -0.5f, -5.0f, 2.0f, 2.0f - }; - // Setup cube VAO - GLuint cubeVAO, cubeVBO; - glGenVertexArrays(1, &cubeVAO); - glGenBuffers(1, &cubeVBO); - glBindVertexArray(cubeVAO); - glBindBuffer(GL_ARRAY_BUFFER, cubeVBO); - glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), &cubeVertices, GL_STATIC_DRAW); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0); - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); - glBindVertexArray(0); - // Setup plane VAO - GLuint planeVAO, planeVBO; - glGenVertexArrays(1, &planeVAO); - glGenBuffers(1, &planeVBO); - glBindVertexArray(planeVAO); - glBindBuffer(GL_ARRAY_BUFFER, planeVBO); - glBufferData(GL_ARRAY_BUFFER, sizeof(planeVertices), &planeVertices, GL_STATIC_DRAW); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0); - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); - glBindVertexArray(0); + // Light sources + // - Positions + std::vector lightPositions; + lightPositions.push_back(glm::vec3(0.0f, 0.0f, 49.5f)); // back light + lightPositions.push_back(glm::vec3(-1.4f, -1.9f, 9.0f)); + lightPositions.push_back(glm::vec3(0.0f, -1.8f, 4.0f)); + lightPositions.push_back(glm::vec3(0.8f, -1.7f, 6.0f)); + // - Colors + std::vector lightColors; + lightColors.push_back(glm::vec3(200.0f, 200.0f, 200.0f)); + lightColors.push_back(glm::vec3(0.1f, 0.0f, 0.0f)); + lightColors.push_back(glm::vec3(0.0f, 0.0f, 0.2f)); + lightColors.push_back(glm::vec3(0.0f, 0.1f, 0.0f)); // Load textures - GLuint cubeTexture = loadTexture("../../../resources/textures/marble.jpg"); - GLuint floorTexture = loadTexture("../../../resources/textures/metal.png"); - #pragma endregion + woodTexture = loadTexture("../../../resources/textures/wood.png"); + + // Set up floating point framebuffer to render scene to + GLuint hdrFBO; + glGenFramebuffers(1, &hdrFBO); + // - Create floating point color buffer + GLuint colorBuffer; + glGenTextures(1, &colorBuffer); + glBindTexture(GL_TEXTURE_2D, colorBuffer); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGB, GL_FLOAT, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + // - Create depth buffer (renderbuffer) + GLuint rboDepth; + glGenRenderbuffers(1, &rboDepth); + glBindRenderbuffer(GL_RENDERBUFFER, rboDepth); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, SCR_WIDTH, SCR_HEIGHT); + // - Attach buffers + glBindFramebuffer(GL_FRAMEBUFFER, hdrFBO); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBuffer, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboDepth); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + std::cout << "Framebuffer not complete!" << std::endl; + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glClearColor(0.1f, 0.1f, 0.1f, 1.0f); // Game loop - while(!glfwWindowShouldClose(window)) + while (!glfwWindowShouldClose(window)) { // Set frame time GLfloat currentFrame = glfwGetTime(); @@ -172,35 +133,43 @@ int main() glfwPollEvents(); Do_Movement(); - // Clear the colorbuffer - glClearColor(0.1f, 0.1f, 0.1f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + // 1. Render scene into floating point framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, hdrFBO); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glm::mat4 projection = glm::perspective(camera.Zoom, (GLfloat)SCR_WIDTH / (GLfloat)SCR_HEIGHT, 0.1f, 100.0f); + glm::mat4 view = camera.GetViewMatrix(); + glm::mat4 model; + shader.Use(); + glUniformMatrix4fv(glGetUniformLocation(shader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); + glUniformMatrix4fv(glGetUniformLocation(shader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view)); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, woodTexture); + // - set lighting uniforms + for (GLuint i = 0; i < lightPositions.size(); i++) + { + glUniform3fv(glGetUniformLocation(shader.Program, ("lights[" + std::to_string(i) + "].Position").c_str()), 1, &lightPositions[i][0]); + glUniform3fv(glGetUniformLocation(shader.Program, ("lights[" + std::to_string(i) + "].Color").c_str()), 1, &lightColors[i][0]); + } + glUniform3fv(glGetUniformLocation(shader.Program, "viewPos"), 1, &camera.Position[0]); + // - render tunnel + model = glm::mat4(); + model = glm::translate(model, glm::vec3(0.0f, 0.0f, 25.0)); + model = glm::scale(model, glm::vec3(5.0f, 5.0f, 55.0f)); + glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); + glUniform1i(glGetUniformLocation(shader.Program, "inverse_normals"), GL_TRUE); + RenderCube(); + glBindFramebuffer(GL_FRAMEBUFFER, 0); - // Draw objects - shader.Use(); - glm::mat4 model; - glm::mat4 view = camera.GetViewMatrix(); - glm::mat4 projection = glm::perspective(camera.Zoom, (float)screenWidth/(float)screenHeight, 0.1f, 100.0f); - glUniformMatrix4fv(glGetUniformLocation(shader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view)); - glUniformMatrix4fv(glGetUniformLocation(shader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); - // Cubes - glBindVertexArray(cubeVAO); - glBindTexture(GL_TEXTURE_2D, cubeTexture); // We omit the glActiveTexture part since TEXTURE0 is already the default active texture unit. (sampler used in fragment is set to 0 as well as default) - model = glm::translate(model, glm::vec3(-1.0f, 0.0f, -1.0f)); - glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); - glDrawArrays(GL_TRIANGLES, 0, 36); - model = glm::mat4(); - model = glm::translate(model, glm::vec3(2.0f, 0.0f, 0.0f)); - glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); - glDrawArrays(GL_TRIANGLES, 0, 36); - // Floor - glBindVertexArray(planeVAO); - glBindTexture(GL_TEXTURE_2D, floorTexture); - model = glm::mat4(); - glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); - glDrawArrays(GL_TRIANGLES, 0, 6); - glBindVertexArray(0); + // 2. Now render floating point color buffer to 2D quad and tonemap HDR colors to default framebuffer's (clamped) color range + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + hdrShader.Use(); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, colorBuffer); + glUniform1i(glGetUniformLocation(hdrShader.Program, "hdr"), hdr); + glUniform1f(glGetUniformLocation(hdrShader.Program, "exposure"), exposure); + RenderQuad(); + std::cout << "exposure: " << exposure << std::endl; // Swap the buffers glfwSwapBuffers(window); @@ -210,63 +179,189 @@ int main() return 0; } + +// RenderQuad() Renders a 1x1 quad in NDC, best used for framebuffer color targets +// and post-processing effects. +GLuint quadVAO = 0; +GLuint quadVBO; +void RenderQuad() +{ + if (quadVAO == 0) + { + GLfloat quadVertices[] = { + // Positions // Texture Coords + -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, + -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, + 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, + }; + // Setup plane VAO + glGenVertexArrays(1, &quadVAO); + glGenBuffers(1, &quadVBO); + glBindVertexArray(quadVAO); + glBindBuffer(GL_ARRAY_BUFFER, quadVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); + } + glBindVertexArray(quadVAO); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glBindVertexArray(0); +} + +// RenderCube() Renders a 1x1 3D cube in NDC. +GLuint cubeVAO = 0; +GLuint cubeVBO = 0; +void RenderCube() +{ + // Initialize (if necessary) + if (cubeVAO == 0) + { + GLfloat vertices[] = { + // Back face + -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, // Bottom-left + 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, // top-right + 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, // bottom-right + 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, // top-right + -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, // bottom-left + -0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,// top-left + // Front face + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom-left + 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, // bottom-right + 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // top-right + 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // top-right + -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // top-left + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom-left + // Left face + -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-right + -0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-left + -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-left + -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-left + -0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom-right + -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-right + // Right face + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-left + 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-right + 0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-right + 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-right + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-left + 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom-left + // Bottom face + -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, // top-right + 0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f, // top-left + 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,// bottom-left + 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, // bottom-left + -0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, // bottom-right + -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, // top-right + // Top face + -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,// top-left + 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom-right + 0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, // top-right + 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom-right + -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,// top-left + -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f // bottom-left + }; + glGenVertexArrays(1, &cubeVAO); + glGenBuffers(1, &cubeVBO); + // Fill buffer + glBindBuffer(GL_ARRAY_BUFFER, cubeVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + // Link vertex attributes + glBindVertexArray(cubeVAO); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); + glEnableVertexAttribArray(2); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat))); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); + } + // Render Cube + glBindVertexArray(cubeVAO); + glDrawArrays(GL_TRIANGLES, 0, 36); + glBindVertexArray(0); +} + // This function loads a texture from file. Note: texture loading functions like these are usually // managed by a 'Resource Manager' that manages all resources (like textures, models, audio). // For learning purposes we'll just define it as a utility function. GLuint loadTexture(GLchar* path) { - //Generate texture ID and load texture data + // Generate texture ID and load texture data GLuint textureID; glGenTextures(1, &textureID); - int width,height; + int width, height; unsigned char* image = SOIL_load_image(path, &width, &height, 0, SOIL_LOAD_RGB); // Assign texture to ID glBindTexture(GL_TEXTURE_2D, textureID); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image); - glGenerateMipmap(GL_TEXTURE_2D); + glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image); + glGenerateMipmap(GL_TEXTURE_2D); // Parameters - 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_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + 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_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, 0); SOIL_free_image_data(image); return textureID; } -#pragma region "User input" - +bool keys[1024]; +bool keysPressed[1024]; // Moves/alters the camera positions based on user input void Do_Movement() { // Camera controls - if(keys[GLFW_KEY_W]) + if (keys[GLFW_KEY_W]) camera.ProcessKeyboard(FORWARD, deltaTime); - if(keys[GLFW_KEY_S]) + if (keys[GLFW_KEY_S]) camera.ProcessKeyboard(BACKWARD, deltaTime); - if(keys[GLFW_KEY_A]) + if (keys[GLFW_KEY_A]) camera.ProcessKeyboard(LEFT, deltaTime); - if(keys[GLFW_KEY_D]) + if (keys[GLFW_KEY_D]) camera.ProcessKeyboard(RIGHT, deltaTime); + + if (keys[GLFW_KEY_SPACE] && !keysPressed[GLFW_KEY_SPACE]) + { + hdr = !hdr; + keysPressed[GLFW_KEY_SPACE] = true; + } + + // Change parallax height scale + if (keys[GLFW_KEY_Q]) + exposure -= 0.5 * deltaTime; + else if (keys[GLFW_KEY_E]) + exposure += 0.5 * deltaTime; } +GLfloat lastX = 400, lastY = 300; +bool firstMouse = true; // Is called whenever a key is pressed/released via GLFW void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) { - if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) + if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) glfwSetWindowShouldClose(window, GL_TRUE); - if(action == GLFW_PRESS) - keys[key] = true; - else if(action == GLFW_RELEASE) - keys[key] = false; + if (key >= 0 && key <= 1024) + { + if (action == GLFW_PRESS) + keys[key] = true; + else if (action == GLFW_RELEASE) + { + keys[key] = false; + keysPressed[key] = false; + } + } } void mouse_callback(GLFWwindow* window, double xpos, double ypos) { - if(firstMouse) + if (firstMouse) { lastX = xpos; lastY = ypos; @@ -274,17 +369,15 @@ void mouse_callback(GLFWwindow* window, double xpos, double ypos) } GLfloat xoffset = xpos - lastX; - GLfloat yoffset = lastY - ypos; - + GLfloat yoffset = lastY - ypos; + lastX = xpos; lastY = ypos; camera.ProcessMouseMovement(xoffset, yoffset); -} +} void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) { camera.ProcessMouseScroll(yoffset); -} - -#pragma endregion \ No newline at end of file +} \ No newline at end of file diff --git a/src/5.advanced_lighting/6.hdr/hdr.frag b/src/5.advanced_lighting/6.hdr/hdr.frag index 5f3992f..7c901b8 100644 --- a/src/5.advanced_lighting/6.hdr/hdr.frag +++ b/src/5.advanced_lighting/6.hdr/hdr.frag @@ -1,16 +1,28 @@ #version 330 core out vec4 color; +in vec2 TexCoords; -float LinearizeDepth(float depth) // Note that this ranges from [0,1] instead of up to 'far plane distance' since we divide by 'far' -{ - float near = 0.1; - float far = 100.0; - float z = depth * 2.0 - 1.0; // Back to NDC - return (2.0 * near) / (far + near - z * (far - near)); -} +uniform sampler2D hdrBuffer; +uniform bool hdr; +uniform float exposure; void main() { - float depth = LinearizeDepth(gl_FragCoord.z); - color = vec4(vec3(depth), 1.0f); + const float gamma = 2.2; + vec3 hdrColor = texture(hdrBuffer, TexCoords).rgb; + if(hdr) + { + // reinhard + // vec3 result = hdrColor / (hdrColor + vec3(1.0)); + // exposure + vec3 result = vec3(1.0) - exp(-hdrColor * exposure); + // also gamma correct while we're at it + result = pow(result, vec3(1.0 / gamma)); + color = vec4(result, 1.0f); + } + else + { + vec3 result = pow(hdrColor, vec3(1.0 / gamma)); + color = vec4(result, 1.0); + } } \ No newline at end of file diff --git a/src/5.advanced_lighting/6.hdr/hdr.vs b/src/5.advanced_lighting/6.hdr/hdr.vs index 3abdaa6..819c18d 100644 --- a/src/5.advanced_lighting/6.hdr/hdr.vs +++ b/src/5.advanced_lighting/6.hdr/hdr.vs @@ -4,12 +4,8 @@ layout (location = 1) in vec2 texCoords; out vec2 TexCoords; -uniform mat4 model; -uniform mat4 view; -uniform mat4 projection; - void main() { - gl_Position = projection * view * model * vec4(position, 1.0f); + gl_Position = vec4(position, 1.0f); TexCoords = texCoords; } \ No newline at end of file diff --git a/src/5.advanced_lighting/6.hdr/lighting.frag b/src/5.advanced_lighting/6.hdr/lighting.frag new file mode 100644 index 0000000..8cf2e67 --- /dev/null +++ b/src/5.advanced_lighting/6.hdr/lighting.frag @@ -0,0 +1,41 @@ +#version 330 core +out vec4 FragColor; + +in VS_OUT { + vec3 FragPos; + vec3 Normal; + vec2 TexCoords; +} fs_in; + +struct Light { + vec3 Position; + vec3 Color; +}; + +uniform Light lights[16]; +uniform sampler2D diffuseTexture; +uniform vec3 viewPos; + +void main() +{ + vec3 color = texture(diffuseTexture, fs_in.TexCoords).rgb; + vec3 normal = normalize(fs_in.Normal); + // Ambient + vec3 ambient = 0.0 * color; + // Lighting + vec3 lighting = vec3(0.0f); + for(int i = 0; i < 16; i++) + { + // Diffuse + vec3 lightDir = normalize(lights[i].Position - fs_in.FragPos); + float diff = max(dot(lightDir, normal), 0.0); + vec3 diffuse = lights[i].Color * diff * color; + vec3 result = diffuse; + // Attenuation (use quadratic as we have gamma correction) + float distance = length(fs_in.FragPos - lights[i].Position); + result *= 1.0 / (distance * distance); + lighting += result; + + } + FragColor = vec4(ambient + lighting, 1.0f); +} \ No newline at end of file diff --git a/src/5.advanced_lighting/6.hdr/lighting.vs b/src/5.advanced_lighting/6.hdr/lighting.vs new file mode 100644 index 0000000..bb012d7 --- /dev/null +++ b/src/5.advanced_lighting/6.hdr/lighting.vs @@ -0,0 +1,28 @@ +#version 330 core +layout (location = 0) in vec3 position; +layout (location = 1) in vec3 normal; +layout (location = 2) in vec2 texCoords; + +out VS_OUT { + vec3 FragPos; + vec3 Normal; + vec2 TexCoords; +} vs_out; + +uniform mat4 projection; +uniform mat4 view; +uniform mat4 model; + +uniform bool inverse_normals; + +void main() +{ + gl_Position = projection * view * model * vec4(position, 1.0f); + vs_out.FragPos = vec3(model * vec4(position, 1.0)); + vs_out.TexCoords = texCoords; + + vec3 n = inverse_normals ? -normal : normal; + + mat3 normalMatrix = transpose(inverse(mat3(model))); + vs_out.Normal = normalize(normalMatrix * n); +} \ No newline at end of file diff --git a/src/5.advanced_lighting/7.bloom/bloom.cpp b/src/5.advanced_lighting/7.bloom/bloom.cpp index b51efb8..afa7bfb 100644 --- a/src/5.advanced_lighting/7.bloom/bloom.cpp +++ b/src/5.advanced_lighting/7.bloom/bloom.cpp @@ -1,6 +1,3 @@ -// Std. Includes -#include - // GLEW #define GLEW_STATIC #include @@ -21,7 +18,7 @@ #include // Properties -GLuint screenWidth = 800, screenHeight = 600; +const GLuint SCR_WIDTH = 800, SCR_HEIGHT = 600; // Function prototypes void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode); @@ -29,185 +26,361 @@ void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); void mouse_callback(GLFWwindow* window, double xpos, double ypos); void Do_Movement(); GLuint loadTexture(GLchar* path); +void RenderScene(Shader &shader); +void RenderCube(); +void RenderQuad(); // Camera -Camera camera(glm::vec3(0.0f, 0.0f, 3.0f)); -bool keys[1024]; -GLfloat lastX = 400, lastY = 300; -bool firstMouse = true; +Camera camera(glm::vec3(0.0f, 0.0f, 5.0f)); +// Delta GLfloat deltaTime = 0.0f; GLfloat lastFrame = 0.0f; +// Options +GLboolean bloom = true; // Change with 'Space' +GLfloat exposure = 1.0f; // Change with Q and E + // The MAIN function, from here we start our application and run our Game loop int main() { - // Init GLFW - glfwInit(); - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); + // Init GLFW + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); - GLFWwindow* window = glfwCreateWindow(screenWidth, screenHeight, "LearnOpenGL", nullptr, nullptr); // Windowed - glfwMakeContextCurrent(window); + GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", nullptr, nullptr); // Windowed + glfwMakeContextCurrent(window); - // Set the required callback functions - glfwSetKeyCallback(window, key_callback); - glfwSetCursorPosCallback(window, mouse_callback); - glfwSetScrollCallback(window, scroll_callback); + // Set the required callback functions + glfwSetKeyCallback(window, key_callback); + glfwSetCursorPosCallback(window, mouse_callback); + glfwSetScrollCallback(window, scroll_callback); - // Options - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + // Options + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); - // Initialize GLEW to setup the OpenGL Function pointers - glewExperimental = GL_TRUE; - glewInit(); + // Initialize GLEW to setup the OpenGL Function pointers + glewExperimental = GL_TRUE; + glewInit(); - // Define the viewport dimensions - glViewport(0, 0, screenWidth, screenHeight); + // Define the viewport dimensions + glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT); - // Setup some OpenGL options - glEnable(GL_DEPTH_TEST); - // glDepthFunc(GL_ALWAYS); // Set to always pass the depth test (same effect as glDisable(GL_DEPTH_TEST)) + // Setup some OpenGL options + glEnable(GL_DEPTH_TEST); - // Setup and compile our shaders - Shader shader("depth_testing.vs", "depth_testing.frag"); + // Setup and compile our shaders + Shader shader("bloom.vs", "bloom.frag"); + Shader shaderLight("bloom.vs", "light_box.frag"); + Shader shaderBlur("blur.vs", "blur.frag"); + Shader shaderBloomFinal("bloom_final.vs", "bloom_final.frag"); - #pragma region "object_initialization" - // Set the object data (buffers, vertex attributes) - GLfloat cubeVertices[] = { - // Positions // Texture Coords - -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, - 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, - 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, - -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, + // Set samplers + shaderBloomFinal.Use(); + glUniform1i(glGetUniformLocation(shaderBloomFinal.Program, "scene"), 0); + glUniform1i(glGetUniformLocation(shaderBloomFinal.Program, "bloomBlur"), 1); - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, - -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + // Light sources + // - Positions + std::vector lightPositions; + lightPositions.push_back(glm::vec3(0.0f, 0.5f, 1.5f)); // back light + lightPositions.push_back(glm::vec3(-4.0f, 0.5f, -3.0f)); + lightPositions.push_back(glm::vec3(3.0f, 0.5f, 1.0f)); + lightPositions.push_back(glm::vec3(-.8f, 2.4f, -1.0f)); + // - Colors + std::vector lightColors; + lightColors.push_back(glm::vec3(5.0f, 5.0f, 5.0f)); + lightColors.push_back(glm::vec3(5.5f, 0.0f, 0.0f)); + lightColors.push_back(glm::vec3(0.0f, 0.0f, 15.0f)); + lightColors.push_back(glm::vec3(0.0f, 1.5f, 0.0f)); - -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + // Load textures + GLuint woodTexture = loadTexture("../../../resources/textures/wood.png"); + GLuint containerTexture = loadTexture("../../../resources/textures/container2.png"); - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + // Set up floating point framebuffer to render scene to + GLuint hdrFBO; + glGenFramebuffers(1, &hdrFBO); + glBindFramebuffer(GL_FRAMEBUFFER, hdrFBO); + // - Create 2 floating point color buffers (1 for normal rendering, other for brightness treshold values) + GLuint colorBuffers[2]; + glGenTextures(2, colorBuffers); + for (GLuint i = 0; i < 2; i++) + { + glBindTexture(GL_TEXTURE_2D, colorBuffers[i]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGB, GL_FLOAT, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // We clamp to the edge as the blur filter would otherwise sample repeated texture values! + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + // attach texture to framebuffer + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, colorBuffers[i], 0); + } + // - Create and attach depth buffer (renderbuffer) + GLuint rboDepth; + glGenRenderbuffers(1, &rboDepth); + glBindRenderbuffer(GL_RENDERBUFFER, rboDepth); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, SCR_WIDTH, SCR_HEIGHT); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboDepth); + // - Tell OpenGL which color attachments we'll use (of this framebuffer) for rendering + GLuint attachments[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; + glDrawBuffers(2, attachments); + // - Finally check if framebuffer is complete + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + std::cout << "Framebuffer not complete!" << std::endl; + glBindFramebuffer(GL_FRAMEBUFFER, 0); - -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - 0.5f, -0.5f, -0.5f, 1.0f, 1.0f, - 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, - 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + // Ping pong framebuffer for blurring + GLuint pingpongFBO[2]; + GLuint pingpongColorbuffers[2]; + glGenFramebuffers(2, pingpongFBO); + glGenTextures(2, pingpongColorbuffers); + for (GLuint i = 0; i < 2; i++) + { + glBindFramebuffer(GL_FRAMEBUFFER, pingpongFBO[i]); + glBindTexture(GL_TEXTURE_2D, pingpongColorbuffers[i]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGB, GL_FLOAT, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // We clamp to the edge as the blur filter would otherwise sample repeated texture values! + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, pingpongColorbuffers[i], 0); + // Also check if framebuffers are complete (no need for depth buffer) + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + std::cout << "Framebuffer not complete!" << std::endl; + } - -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, - 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, - -0.5f, 0.5f, -0.5f, 0.0f, 1.0f - }; - GLfloat planeVertices[] = { - // Positions // Texture Coords (note we set these higher than 1 that together with GL_REPEAT as texture wrapping mode will cause the floor texture to repeat) - 5.0f, -0.5f, 5.0f, 2.0f, 0.0f, - -5.0f, -0.5f, 5.0f, 0.0f, 0.0f, - -5.0f, -0.5f, -5.0f, 0.0f, 2.0f, + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - 5.0f, -0.5f, 5.0f, 2.0f, 0.0f, - -5.0f, -0.5f, -5.0f, 0.0f, 2.0f, - 5.0f, -0.5f, -5.0f, 2.0f, 2.0f - }; - // Setup cube VAO - GLuint cubeVAO, cubeVBO; - glGenVertexArrays(1, &cubeVAO); - glGenBuffers(1, &cubeVBO); - glBindVertexArray(cubeVAO); - glBindBuffer(GL_ARRAY_BUFFER, cubeVBO); - glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), &cubeVertices, GL_STATIC_DRAW); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0); - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); - glBindVertexArray(0); - // Setup plane VAO - GLuint planeVAO, planeVBO; - glGenVertexArrays(1, &planeVAO); - glGenBuffers(1, &planeVBO); - glBindVertexArray(planeVAO); - glBindBuffer(GL_ARRAY_BUFFER, planeVBO); - glBufferData(GL_ARRAY_BUFFER, sizeof(planeVertices), &planeVertices, GL_STATIC_DRAW); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0); - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); - glBindVertexArray(0); + // Game loop + while (!glfwWindowShouldClose(window)) + { + // Set frame time + GLfloat currentFrame = glfwGetTime(); + deltaTime = currentFrame - lastFrame; + lastFrame = currentFrame; - // Load textures - GLuint cubeTexture = loadTexture("../../../resources/textures/marble.jpg"); - GLuint floorTexture = loadTexture("../../../resources/textures/metal.png"); - #pragma endregion + // Check and call events + glfwPollEvents(); + Do_Movement(); - // Game loop - while(!glfwWindowShouldClose(window)) - { - // Set frame time - GLfloat currentFrame = glfwGetTime(); - deltaTime = currentFrame - lastFrame; - lastFrame = currentFrame; + // 1. Render scene into floating point framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, hdrFBO); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glm::mat4 projection = glm::perspective(camera.Zoom, (GLfloat)SCR_WIDTH / (GLfloat)SCR_HEIGHT, 0.1f, 100.0f); + glm::mat4 view = camera.GetViewMatrix(); + glm::mat4 model; + shader.Use(); + glUniformMatrix4fv(glGetUniformLocation(shader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); + glUniformMatrix4fv(glGetUniformLocation(shader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view)); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, woodTexture); + // - set lighting uniforms + for (GLuint i = 0; i < lightPositions.size(); i++) + { + glUniform3fv(glGetUniformLocation(shader.Program, ("lights[" + std::to_string(i) + "].Position").c_str()), 1, &lightPositions[i][0]); + glUniform3fv(glGetUniformLocation(shader.Program, ("lights[" + std::to_string(i) + "].Color").c_str()), 1, &lightColors[i][0]); + } + glUniform3fv(glGetUniformLocation(shader.Program, "viewPos"), 1, &camera.Position[0]); + // - create one large cube that acts as the floor + model = glm::mat4(); + model = glm::translate(model, glm::vec3(0.0f, -1.0f, 0.0)); + model = glm::scale(model, glm::vec3(25.0f, 1.0f, 25.0f)); + glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); + RenderCube(); + // - then create multiple cubes as the scenery + glBindTexture(GL_TEXTURE_2D, containerTexture); + model = glm::mat4(); + model = glm::translate(model, glm::vec3(0.0f, 1.5f, 0.0)); + glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); + RenderCube(); + model = glm::mat4(); + model = glm::translate(model, glm::vec3(2.0f, 0.0f, 1.0)); + glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); + RenderCube(); + model = glm::mat4(); + model = glm::translate(model, glm::vec3(-1.0f, -1.0f, 2.0)); + model = glm::rotate(model, 60.0f, glm::normalize(glm::vec3(1.0, 0.0, 1.0))); + model = glm::scale(model, glm::vec3(2.0)); + glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); + RenderCube(); + model = glm::mat4(); + model = glm::translate(model, glm::vec3(0.0f, 2.7f, 4.0)); + model = glm::rotate(model, 23.0f, glm::normalize(glm::vec3(1.0, 0.0, 1.0))); + model = glm::scale(model, glm::vec3(2.5)); + glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); + RenderCube(); + model = glm::mat4(); + model = glm::translate(model, glm::vec3(-2.0f, 1.0f, -3.0)); + model = glm::rotate(model, 124.0f, glm::normalize(glm::vec3(1.0, 0.0, 1.0))); + model = glm::scale(model, glm::vec3(2.0)); + glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); + RenderCube(); + RenderCube(); + model = glm::mat4(); + model = glm::translate(model, glm::vec3(-3.0f, 0.0f, 0.0)); + glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); + RenderCube(); + // - finally show all the light sources as bright cubes + shaderLight.Use(); + glUniformMatrix4fv(glGetUniformLocation(shaderLight.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); + glUniformMatrix4fv(glGetUniformLocation(shaderLight.Program, "view"), 1, GL_FALSE, glm::value_ptr(view)); - // Check and call events - glfwPollEvents(); - Do_Movement(); + for (GLuint i = 0; i < lightPositions.size(); i++) + { + model = glm::mat4(); + model = glm::translate(model, glm::vec3(lightPositions[i])); + model = glm::scale(model, glm::vec3(0.5f)); + glUniformMatrix4fv(glGetUniformLocation(shaderLight.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); + glUniform3fv(glGetUniformLocation(shaderLight.Program, "lightColor"), 1, &lightColors[i][0]); + RenderCube(); + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); - // Clear the colorbuffer - glClearColor(0.1f, 0.1f, 0.1f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + // 2. Blur bright fragments w/ two-pass Gaussian Blur + GLboolean horizontal = true, first_iteration = true; + GLuint amount = 10; + shaderBlur.Use(); + for (GLuint i = 0; i < amount; i++) + { + glBindFramebuffer(GL_FRAMEBUFFER, pingpongFBO[horizontal]); + glUniform1i(glGetUniformLocation(shaderBlur.Program, "horizontal"), horizontal); + glBindTexture(GL_TEXTURE_2D, first_iteration ? colorBuffers[1] : pingpongColorbuffers[!horizontal]); // bind texture of other framebuffer (or scene if first iteration) + RenderQuad(); + horizontal = !horizontal; + if (first_iteration) + first_iteration = false; + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); - // Draw objects - shader.Use(); - glm::mat4 model; - glm::mat4 view = camera.GetViewMatrix(); - glm::mat4 projection = glm::perspective(camera.Zoom, (float)screenWidth/(float)screenHeight, 0.1f, 100.0f); - glUniformMatrix4fv(glGetUniformLocation(shader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view)); - glUniformMatrix4fv(glGetUniformLocation(shader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); - // Cubes - glBindVertexArray(cubeVAO); - glBindTexture(GL_TEXTURE_2D, cubeTexture); // We omit the glActiveTexture part since TEXTURE0 is already the default active texture unit. (sampler used in fragment is set to 0 as well as default) - model = glm::translate(model, glm::vec3(-1.0f, 0.0f, -1.0f)); - glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); - glDrawArrays(GL_TRIANGLES, 0, 36); - model = glm::mat4(); - model = glm::translate(model, glm::vec3(2.0f, 0.0f, 0.0f)); - glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); - glDrawArrays(GL_TRIANGLES, 0, 36); - // Floor - glBindVertexArray(planeVAO); - glBindTexture(GL_TEXTURE_2D, floorTexture); - model = glm::mat4(); - glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); - glDrawArrays(GL_TRIANGLES, 0, 6); - glBindVertexArray(0); + // 2. Now render floating point color buffer to 2D quad and tonemap HDR colors to default framebuffer's (clamped) color range + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + shaderBloomFinal.Use(); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, colorBuffers[0]); + //glBindTexture(GL_TEXTURE_2D, pingpongColorbuffers[!horizontal]); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, pingpongColorbuffers[!horizontal]); + glUniform1i(glGetUniformLocation(shaderBloomFinal.Program, "bloom"), bloom); + glUniform1f(glGetUniformLocation(shaderBloomFinal.Program, "exposure"), exposure); + RenderQuad(); - // Swap the buffers - glfwSwapBuffers(window); - } + // Swap the buffers + glfwSwapBuffers(window); + } - glfwTerminate(); - return 0; + glfwTerminate(); + return 0; +} + + +// RenderQuad() Renders a 1x1 quad in NDC, best used for framebuffer color targets +// and post-processing effects. +GLuint quadVAO = 0; +GLuint quadVBO; +void RenderQuad() +{ + if (quadVAO == 0) + { + GLfloat quadVertices[] = { + // Positions // Texture Coords + -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, + -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, + 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, + }; + // Setup plane VAO + glGenVertexArrays(1, &quadVAO); + glGenBuffers(1, &quadVBO); + glBindVertexArray(quadVAO); + glBindBuffer(GL_ARRAY_BUFFER, quadVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); + } + glBindVertexArray(quadVAO); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glBindVertexArray(0); +} + +// RenderCube() Renders a 1x1 3D cube in NDC. +GLuint cubeVAO = 0; +GLuint cubeVBO = 0; +void RenderCube() +{ + // Initialize (if necessary) + if (cubeVAO == 0) + { + GLfloat vertices[] = { + // Back face + -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, // Bottom-left + 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, // top-right + 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, // bottom-right + 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, // top-right + -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, // bottom-left + -0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,// top-left + // Front face + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom-left + 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, // bottom-right + 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // top-right + 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // top-right + -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // top-left + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom-left + // Left face + -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-right + -0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-left + -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-left + -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-left + -0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom-right + -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-right + // Right face + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-left + 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-right + 0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-right + 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-right + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-left + 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom-left + // Bottom face + -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, // top-right + 0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f, // top-left + 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,// bottom-left + 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, // bottom-left + -0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, // bottom-right + -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, // top-right + // Top face + -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,// top-left + 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom-right + 0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, // top-right + 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom-right + -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,// top-left + -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f // bottom-left + }; + glGenVertexArrays(1, &cubeVAO); + glGenBuffers(1, &cubeVBO); + // Fill buffer + glBindBuffer(GL_ARRAY_BUFFER, cubeVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + // Link vertex attributes + glBindVertexArray(cubeVAO); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); + glEnableVertexAttribArray(2); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat))); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); + } + // Render Cube + glBindVertexArray(cubeVAO); + glDrawArrays(GL_TRIANGLES, 0, 36); + glBindVertexArray(0); } // This function loads a texture from file. Note: texture loading functions like these are usually @@ -215,76 +388,94 @@ int main() // For learning purposes we'll just define it as a utility function. GLuint loadTexture(GLchar* path) { - //Generate texture ID and load texture data - GLuint textureID; - glGenTextures(1, &textureID); - int width,height; - unsigned char* image = SOIL_load_image(path, &width, &height, 0, SOIL_LOAD_RGB); - // Assign texture to ID - glBindTexture(GL_TEXTURE_2D, textureID); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image); - glGenerateMipmap(GL_TEXTURE_2D); + // Generate texture ID and load texture data + GLuint textureID; + glGenTextures(1, &textureID); + int width, height; + unsigned char* image = SOIL_load_image(path, &width, &height, 0, SOIL_LOAD_RGB); + // Assign texture to ID + glBindTexture(GL_TEXTURE_2D, textureID); + glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image); + glGenerateMipmap(GL_TEXTURE_2D); - // Parameters - 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_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glBindTexture(GL_TEXTURE_2D, 0); - SOIL_free_image_data(image); - return textureID; + // Parameters + 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_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glBindTexture(GL_TEXTURE_2D, 0); + SOIL_free_image_data(image); + return textureID; } -#pragma region "User input" - +bool keys[1024]; +bool keysPressed[1024]; // Moves/alters the camera positions based on user input void Do_Movement() { - // Camera controls - if(keys[GLFW_KEY_W]) - camera.ProcessKeyboard(FORWARD, deltaTime); - if(keys[GLFW_KEY_S]) - camera.ProcessKeyboard(BACKWARD, deltaTime); - if(keys[GLFW_KEY_A]) - camera.ProcessKeyboard(LEFT, deltaTime); - if(keys[GLFW_KEY_D]) - camera.ProcessKeyboard(RIGHT, deltaTime); + // Camera controls + if (keys[GLFW_KEY_W]) + camera.ProcessKeyboard(FORWARD, deltaTime); + if (keys[GLFW_KEY_S]) + camera.ProcessKeyboard(BACKWARD, deltaTime); + if (keys[GLFW_KEY_A]) + camera.ProcessKeyboard(LEFT, deltaTime); + if (keys[GLFW_KEY_D]) + camera.ProcessKeyboard(RIGHT, deltaTime); + + if (keys[GLFW_KEY_SPACE] && !keysPressed[GLFW_KEY_SPACE]) + { + bloom = !bloom; + keysPressed[GLFW_KEY_SPACE] = true; + } + + // Change parallax height scale + if (keys[GLFW_KEY_Q]) + exposure -= 0.5 * deltaTime; + else if (keys[GLFW_KEY_E]) + exposure += 0.5 * deltaTime; } +GLfloat lastX = 400, lastY = 300; +bool firstMouse = true; // Is called whenever a key is pressed/released via GLFW void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) { - if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) - glfwSetWindowShouldClose(window, GL_TRUE); + if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) + glfwSetWindowShouldClose(window, GL_TRUE); - if(action == GLFW_PRESS) - keys[key] = true; - else if(action == GLFW_RELEASE) - keys[key] = false; + if (key >= 0 && key <= 1024) + { + if (action == GLFW_PRESS) + keys[key] = true; + else if (action == GLFW_RELEASE) + { + keys[key] = false; + keysPressed[key] = false; + } + } } void mouse_callback(GLFWwindow* window, double xpos, double ypos) { - if(firstMouse) - { - lastX = xpos; - lastY = ypos; - firstMouse = false; - } + if (firstMouse) + { + lastX = xpos; + lastY = ypos; + firstMouse = false; + } - GLfloat xoffset = xpos - lastX; - GLfloat yoffset = lastY - ypos; - - lastX = xpos; - lastY = ypos; + GLfloat xoffset = xpos - lastX; + GLfloat yoffset = lastY - ypos; - camera.ProcessMouseMovement(xoffset, yoffset); -} + lastX = xpos; + lastY = ypos; + + camera.ProcessMouseMovement(xoffset, yoffset); +} void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) { - camera.ProcessMouseScroll(yoffset); -} - -#pragma endregion \ No newline at end of file + camera.ProcessMouseScroll(yoffset); +} \ No newline at end of file diff --git a/src/5.advanced_lighting/7.bloom/bloom.frag b/src/5.advanced_lighting/7.bloom/bloom.frag index 5f3992f..84a5c29 100644 --- a/src/5.advanced_lighting/7.bloom/bloom.frag +++ b/src/5.advanced_lighting/7.bloom/bloom.frag @@ -1,16 +1,49 @@ #version 330 core -out vec4 color; +layout (location = 0) out vec4 FragColor; +layout (location = 1) out vec4 BrightColor; -float LinearizeDepth(float depth) // Note that this ranges from [0,1] instead of up to 'far plane distance' since we divide by 'far' -{ - float near = 0.1; - float far = 100.0; - float z = depth * 2.0 - 1.0; // Back to NDC - return (2.0 * near) / (far + near - z * (far - near)); -} +in VS_OUT { + vec3 FragPos; + vec3 Normal; + vec2 TexCoords; +} fs_in; + +struct Light { + vec3 Position; + vec3 Color; +}; + +uniform Light lights[4]; +uniform sampler2D diffuseTexture; +uniform vec3 viewPos; void main() -{ - float depth = LinearizeDepth(gl_FragCoord.z); - color = vec4(vec3(depth), 1.0f); +{ + vec3 color = texture(diffuseTexture, fs_in.TexCoords).rgb; + vec3 normal = normalize(fs_in.Normal); + // Ambient + vec3 ambient = 0.0 * color; + // Lighting + vec3 lighting = vec3(0.0f); + vec3 viewDir = normalize(viewPos - fs_in.FragPos); + for(int i = 0; i < 4; i++) + { + // Diffuse + vec3 lightDir = normalize(lights[i].Position - fs_in.FragPos); + float diff = max(dot(lightDir, normal), 0.0); + vec3 result = lights[i].Color * diff * color; + // Attenuation (use quadratic as we have gamma correction) + float distance = length(fs_in.FragPos - lights[i].Position); + result *= 1.0 / (distance * distance); + lighting += result; + + } + vec3 result = ambient + lighting; + // Check whether result is higher than some threshold, if so, output as bloom threshold color + float brightness = dot(result, vec3(0.2126, 0.7152, 0.0722)); + if(brightness > 1.0) + BrightColor = vec4(result, 1.0); + // else + // BloomColor = vec4(0.0, 0.0, 0.0, 1.0); + FragColor = vec4(result, 1.0f); } \ No newline at end of file diff --git a/src/5.advanced_lighting/7.bloom/bloom.vs b/src/5.advanced_lighting/7.bloom/bloom.vs index 3abdaa6..400d350 100644 --- a/src/5.advanced_lighting/7.bloom/bloom.vs +++ b/src/5.advanced_lighting/7.bloom/bloom.vs @@ -1,15 +1,24 @@ #version 330 core layout (location = 0) in vec3 position; -layout (location = 1) in vec2 texCoords; +layout (location = 1) in vec3 normal; +layout (location = 2) in vec2 texCoords; -out vec2 TexCoords; +out VS_OUT { + vec3 FragPos; + vec3 Normal; + vec2 TexCoords; +} vs_out; -uniform mat4 model; -uniform mat4 view; uniform mat4 projection; +uniform mat4 view; +uniform mat4 model; void main() { gl_Position = projection * view * model * vec4(position, 1.0f); - TexCoords = texCoords; + vs_out.FragPos = vec3(model * vec4(position, 1.0)); + vs_out.TexCoords = texCoords; + + mat3 normalMatrix = transpose(inverse(mat3(model))); + vs_out.Normal = normalize(normalMatrix * normal); } \ No newline at end of file diff --git a/src/5.advanced_lighting/7.bloom/bloom_final.frag b/src/5.advanced_lighting/7.bloom/bloom_final.frag new file mode 100644 index 0000000..ee435c7 --- /dev/null +++ b/src/5.advanced_lighting/7.bloom/bloom_final.frag @@ -0,0 +1,22 @@ +#version 330 core +out vec4 FragColor; +in vec2 TexCoords; + +uniform sampler2D scene; +uniform sampler2D bloomBlur; +uniform bool bloom; +uniform float exposure; + +void main() +{ + const float gamma = 2.2; + vec3 hdrColor = texture(scene, TexCoords).rgb; + vec3 bloomColor = texture(bloomBlur, TexCoords).rgb; + if(bloom) + hdrColor += bloomColor; // additive blending + // tone mapping + vec3 result = vec3(1.0) - exp(-hdrColor * exposure); + // also gamma correct while we're at it + result = pow(result, vec3(1.0 / gamma)); + FragColor = vec4(result, 1.0f); +} \ No newline at end of file diff --git a/src/5.advanced_lighting/7.bloom/bloom_final.vs b/src/5.advanced_lighting/7.bloom/bloom_final.vs new file mode 100644 index 0000000..819c18d --- /dev/null +++ b/src/5.advanced_lighting/7.bloom/bloom_final.vs @@ -0,0 +1,11 @@ +#version 330 core +layout (location = 0) in vec3 position; +layout (location = 1) in vec2 texCoords; + +out vec2 TexCoords; + +void main() +{ + gl_Position = vec4(position, 1.0f); + TexCoords = texCoords; +} \ No newline at end of file diff --git a/src/5.advanced_lighting/7.bloom/blur.frag b/src/5.advanced_lighting/7.bloom/blur.frag new file mode 100644 index 0000000..7152ba4 --- /dev/null +++ b/src/5.advanced_lighting/7.bloom/blur.frag @@ -0,0 +1,31 @@ +#version 330 core +out vec4 FragColor; +in vec2 TexCoords; + +uniform sampler2D image; +uniform bool horizontal; + +uniform float weight[5] = float[] (0.2270270270, 0.1945945946, 0.1216216216, 0.0540540541, 0.0162162162); + +void main() +{ + vec2 tex_offset = 1.0 / textureSize(image, 0); // gets size of single texel + vec3 result = texture(image, TexCoords).rgb * weight[0]; + if(horizontal) + { + for(int i = 1; i < 5; ++i) + { + result += texture(image, TexCoords + vec2(tex_offset.x * i, 0.0)).rgb * weight[i]; + result += texture(image, TexCoords - vec2(tex_offset.x * i, 0.0)).rgb * weight[i]; + } + } + else + { + for(int i = 1; i < 5; ++i) + { + result += texture(image, TexCoords + vec2(0.0, tex_offset.y * i)).rgb * weight[i]; + result += texture(image, TexCoords - vec2(0.0, tex_offset.y * i)).rgb * weight[i]; + } + } + FragColor = vec4(result, 1.0); +} \ No newline at end of file diff --git a/src/5.advanced_lighting/7.bloom/blur.vs b/src/5.advanced_lighting/7.bloom/blur.vs new file mode 100644 index 0000000..819c18d --- /dev/null +++ b/src/5.advanced_lighting/7.bloom/blur.vs @@ -0,0 +1,11 @@ +#version 330 core +layout (location = 0) in vec3 position; +layout (location = 1) in vec2 texCoords; + +out vec2 TexCoords; + +void main() +{ + gl_Position = vec4(position, 1.0f); + TexCoords = texCoords; +} \ No newline at end of file diff --git a/src/5.advanced_lighting/7.bloom/light_box.frag b/src/5.advanced_lighting/7.bloom/light_box.frag new file mode 100644 index 0000000..fe654b9 --- /dev/null +++ b/src/5.advanced_lighting/7.bloom/light_box.frag @@ -0,0 +1,19 @@ +#version 330 core +layout (location = 0) out vec4 FragColor; +layout (location = 1) out vec4 BrightColor; + +in VS_OUT { + vec3 FragPos; + vec3 Normal; + vec2 TexCoords; +} fs_in; + +uniform vec3 lightColor; + +void main() +{ + FragColor = vec4(lightColor, 1.0); + float brightness = dot(FragColor.rgb, vec3(0.2126, 0.7152, 0.0722)); + if(brightness > 1.0) + BrightColor = vec4(FragColor.rgb, 1.0); +} \ No newline at end of file