From 4d5aed34ac08a7cb46e98cab26bea723c6d7b569 Mon Sep 17 00:00:00 2001 From: Joey de Vries Date: Mon, 24 Apr 2017 20:55:39 +0200 Subject: [PATCH] Code re-work: deferred shading. --- .../8.1.deferred_light_box.vs | 8 +- .../8.1.deferred_shading.fs | 51 +- .../8.1.deferred_shading.vs | 8 +- .../8.1.deferred_shading/8.1.g_buffer.fs | 8 +- .../8.1.deferred_shading/8.1.g_buffer.vs | 15 +- .../8.1.deferred_shading/deferred_shading.cpp | 654 +++++++++-------- .../8.2.deferred_shading.fs | 28 +- .../8.2.deferred_shading.vs | 8 +- .../deferred_shading_volumes.cpp | 662 +++++++++--------- 9 files changed, 693 insertions(+), 749 deletions(-) diff --git a/src/5.advanced_lighting/8.1.deferred_shading/8.1.deferred_light_box.vs b/src/5.advanced_lighting/8.1.deferred_shading/8.1.deferred_light_box.vs index 2aa17c1..4552a55 100644 --- a/src/5.advanced_lighting/8.1.deferred_shading/8.1.deferred_light_box.vs +++ b/src/5.advanced_lighting/8.1.deferred_shading/8.1.deferred_light_box.vs @@ -1,7 +1,7 @@ #version 330 core -layout (location = 0) in vec3 position; -layout (location = 1) in vec3 normal; -layout (location = 2) in vec2 texCoords; +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec3 aNormal; +layout (location = 2) in vec2 aTexCoords; uniform mat4 projection; uniform mat4 view; @@ -9,5 +9,5 @@ uniform mat4 model; void main() { - gl_Position = projection * view * model * vec4(position, 1.0f); + gl_Position = projection * view * model * vec4(aPos, 1.0); } \ No newline at end of file diff --git a/src/5.advanced_lighting/8.1.deferred_shading/8.1.deferred_shading.fs b/src/5.advanced_lighting/8.1.deferred_shading/8.1.deferred_shading.fs index 8053f81..fabee28 100644 --- a/src/5.advanced_lighting/8.1.deferred_shading/8.1.deferred_shading.fs +++ b/src/5.advanced_lighting/8.1.deferred_shading/8.1.deferred_shading.fs @@ -1,5 +1,6 @@ #version 330 core out vec4 FragColor; + in vec2 TexCoords; uniform sampler2D gPosition; @@ -12,55 +13,37 @@ struct Light { float Linear; float Quadratic; - float Radius; }; const int NR_LIGHTS = 32; uniform Light lights[NR_LIGHTS]; uniform vec3 viewPos; -uniform int draw_mode; - void main() { - // Retrieve data from gbuffer + // retrieve data from gbuffer vec3 FragPos = texture(gPosition, TexCoords).rgb; vec3 Normal = texture(gNormal, TexCoords).rgb; vec3 Diffuse = texture(gAlbedoSpec, TexCoords).rgb; float Specular = texture(gAlbedoSpec, TexCoords).a; - // Then calculate lighting as usual + // then calculate lighting as usual vec3 lighting = Diffuse * 0.1; // hard-coded ambient component vec3 viewDir = normalize(viewPos - FragPos); for(int i = 0; i < NR_LIGHTS; ++i) { - // Calculate distance between light source and current fragment + // diffuse + vec3 lightDir = normalize(lights[i].Position - FragPos); + vec3 diffuse = max(dot(Normal, lightDir), 0.0) * Diffuse * lights[i].Color; + // specular + vec3 halfwayDir = normalize(lightDir + viewDir); + float spec = pow(max(dot(Normal, halfwayDir), 0.0), 16.0); + vec3 specular = lights[i].Color * spec * Specular; + // attenuation float distance = length(lights[i].Position - FragPos); - if(distance < lights[i].Radius) - { - // Diffuse - vec3 lightDir = normalize(lights[i].Position - FragPos); - vec3 diffuse = max(dot(Normal, lightDir), 0.0) * Diffuse * lights[i].Color; - // Specular - vec3 halfwayDir = normalize(lightDir + viewDir); - float spec = pow(max(dot(Normal, halfwayDir), 0.0), 16.0); - vec3 specular = lights[i].Color * spec * Specular; - // Attenuation - float attenuation = 1.0 / (1.0 + lights[i].Linear * distance + lights[i].Quadratic * distance * distance); - diffuse *= attenuation; - specular *= attenuation; - lighting += diffuse + specular; - } - } - - // Based on which of the 1-5 keys we pressed, show final result or intermediate g-buffer textures - if(draw_mode == 1) - FragColor = vec4(lighting, 1.0); - else if(draw_mode == 2) - FragColor = vec4(FragPos, 1.0); - else if(draw_mode == 3) - FragColor = vec4(Normal, 1.0); - else if(draw_mode == 4) - FragColor = vec4(Diffuse, 1.0); - else if(draw_mode == 5) - FragColor = vec4(vec3(Specular), 1.0); + float attenuation = 1.0 / (1.0 + lights[i].Linear * distance + lights[i].Quadratic * distance * distance); + diffuse *= attenuation; + specular *= attenuation; + lighting += diffuse + specular; + } + FragColor = vec4(lighting, 1.0); } diff --git a/src/5.advanced_lighting/8.1.deferred_shading/8.1.deferred_shading.vs b/src/5.advanced_lighting/8.1.deferred_shading/8.1.deferred_shading.vs index 819c18d..9f93e29 100644 --- a/src/5.advanced_lighting/8.1.deferred_shading/8.1.deferred_shading.vs +++ b/src/5.advanced_lighting/8.1.deferred_shading/8.1.deferred_shading.vs @@ -1,11 +1,11 @@ #version 330 core -layout (location = 0) in vec3 position; -layout (location = 1) in vec2 texCoords; +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec2 aTexCoords; out vec2 TexCoords; void main() { - gl_Position = vec4(position, 1.0f); - TexCoords = texCoords; + TexCoords = aTexCoords; + gl_Position = vec4(aPos, 1.0); } \ No newline at end of file diff --git a/src/5.advanced_lighting/8.1.deferred_shading/8.1.g_buffer.fs b/src/5.advanced_lighting/8.1.deferred_shading/8.1.g_buffer.fs index 8564a06..0bcc927 100644 --- a/src/5.advanced_lighting/8.1.deferred_shading/8.1.g_buffer.fs +++ b/src/5.advanced_lighting/8.1.deferred_shading/8.1.g_buffer.fs @@ -12,12 +12,12 @@ uniform sampler2D texture_specular1; void main() { - // Store the fragment position vector in the first gbuffer texture + // store the fragment position vector in the first gbuffer texture gPosition = FragPos; - // Also store the per-fragment normals into the gbuffer + // also store the per-fragment normals into the gbuffer gNormal = normalize(Normal); - // And the diffuse per-fragment color + // and the diffuse per-fragment color gAlbedoSpec.rgb = texture(texture_diffuse1, TexCoords).rgb; - // Store specular intensity in gAlbedoSpec's alpha component + // store specular intensity in gAlbedoSpec's alpha component gAlbedoSpec.a = texture(texture_specular1, TexCoords).r; } \ No newline at end of file diff --git a/src/5.advanced_lighting/8.1.deferred_shading/8.1.g_buffer.vs b/src/5.advanced_lighting/8.1.deferred_shading/8.1.g_buffer.vs index 4659151..ecd2b9e 100644 --- a/src/5.advanced_lighting/8.1.deferred_shading/8.1.g_buffer.vs +++ b/src/5.advanced_lighting/8.1.deferred_shading/8.1.g_buffer.vs @@ -1,7 +1,7 @@ #version 330 core -layout (location = 0) in vec3 position; -layout (location = 1) in vec3 normal; -layout (location = 2) in vec2 texCoords; +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec3 aNormal; +layout (location = 2) in vec2 aTexCoords; out vec3 FragPos; out vec2 TexCoords; @@ -13,11 +13,12 @@ uniform mat4 projection; void main() { - vec4 worldPos = model * vec4(position, 1.0f); + vec4 worldPos = model * vec4(aPos, 1.0); FragPos = worldPos.xyz; - gl_Position = projection * view * worldPos; - TexCoords = texCoords; + TexCoords = aTexCoords; mat3 normalMatrix = transpose(inverse(mat3(model))); - Normal = normalMatrix * normal; + Normal = normalMatrix * aNormal; + + gl_Position = projection * view * worldPos; } \ No newline at end of file diff --git a/src/5.advanced_lighting/8.1.deferred_shading/deferred_shading.cpp b/src/5.advanced_lighting/8.1.deferred_shading/deferred_shading.cpp index f3bf8f7..2e8d68b 100644 --- a/src/5.advanced_lighting/8.1.deferred_shading/deferred_shading.cpp +++ b/src/5.advanced_lighting/8.1.deferred_shading/deferred_shading.cpp @@ -1,441 +1,425 @@ -// GLEW -#define GLEW_STATIC -#include - -// GLFW +#include #include -// GL includes -#include -#include -#include - -// GLM Mathemtics #include #include #include -// Other Libs -#include #include +#include +#include +#include -// Properties -const GLuint SCR_WIDTH = 800, SCR_HEIGHT = 600; +#include -// Function prototypes -void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode); -void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); +void framebuffer_size_callback(GLFWwindow* window, int width, int height); void mouse_callback(GLFWwindow* window, double xpos, double ypos); -void Do_Movement(); -GLuint loadTexture(GLchar const * path); -void RenderCube(); -void RenderQuad(); +void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); +void processInput(GLFWwindow *window); +unsigned int loadTexture(const char *path, bool gammaCorrection); +void renderQuad(); +void renderCube(); -// Camera +// settings +const unsigned int SCR_WIDTH = 1280; +const unsigned int SCR_HEIGHT = 720; + +// camera Camera camera(glm::vec3(0.0f, 0.0f, 5.0f)); +float lastX = (float)SCR_WIDTH / 2.0; +float lastY = (float)SCR_HEIGHT / 2.0; +bool firstMouse = true; -// Delta -GLfloat deltaTime = 0.0f; -GLfloat lastFrame = 0.0f; +// timing +float deltaTime = 0.0f; +float lastFrame = 0.0f; -// Options -GLuint draw_mode = 1; -GLboolean wireframe = false; - -// 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); + // glfw: initialize and configure + // ------------------------------ + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - 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); - - // Options - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); - - // Initialize GLEW to setup the OpenGL Function pointers - glewExperimental = GL_TRUE; - glewInit(); - - // Define the viewport dimensions - glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT); - - // Setup some OpenGL options - glEnable(GL_DEPTH_TEST); - - // Setup and compile our shaders - Shader shaderGeometryPass("g_buffer.vs", "g_buffer.frag"); - Shader shaderLightingPass("deferred_shading.vs", "deferred_shading.frag"); - Shader shaderLightBox("deferred_light_box.vs", "deferred_light_box.frag"); - - // Set samplers - shaderLightingPass.Use(); - glUniform1i(glGetUniformLocation(shaderLightingPass.Program, "gPosition"), 0); - glUniform1i(glGetUniformLocation(shaderLightingPass.Program, "gNormal"), 1); - glUniform1i(glGetUniformLocation(shaderLightingPass.Program, "gAlbedoSpec"), 2); - - // Models - Model cyborg(FileSystem::getPath("resources/objects/nanosuit/nanosuit.obj").c_str()); - std::vector objectPositions; - objectPositions.push_back(glm::vec3(-3.0, -3.0, -3.0)); - objectPositions.push_back(glm::vec3(0.0, -3.0, -3.0)); - objectPositions.push_back(glm::vec3(3.0, -3.0, -3.0)); - objectPositions.push_back(glm::vec3(-3.0, -3.0, 0.0)); - objectPositions.push_back(glm::vec3(0.0, -3.0, 0.0)); - objectPositions.push_back(glm::vec3(3.0, -3.0, 0.0)); - objectPositions.push_back(glm::vec3(-3.0, -3.0, 3.0)); - objectPositions.push_back(glm::vec3(0.0, -3.0, 3.0)); - objectPositions.push_back(glm::vec3(3.0, -3.0, 3.0)); - // - Colors - const GLuint NR_LIGHTS = 32; - std::vector lightPositions; - std::vector lightColors; - srand(13); - for (GLuint i = 0; i < NR_LIGHTS; i++) + // glfw window creation + // -------------------- + GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL); + glfwMakeContextCurrent(window); + if (window == NULL) { - // Calculate slightly random offsets - GLfloat xPos = ((rand() % 100) / 100.0) * 6.0 - 3.0; - GLfloat yPos = ((rand() % 100) / 100.0) * 6.0 - 4.0; - GLfloat zPos = ((rand() % 100) / 100.0) * 6.0 - 3.0; - lightPositions.push_back(glm::vec3(xPos, yPos, zPos)); - // Also calculate random color - GLfloat rColor = ((rand() % 100) / 200.0f) + 0.5; // Between 0.5 and 1.0 - GLfloat gColor = ((rand() % 100) / 200.0f) + 0.5; // Between 0.5 and 1.0 - GLfloat bColor = ((rand() % 100) / 200.0f) + 0.5; // Between 0.5 and 1.0 - lightColors.push_back(glm::vec3(rColor, gColor, bColor)); + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + return -1; + } + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + glfwSetCursorPosCallback(window, mouse_callback); + glfwSetScrollCallback(window, scroll_callback); + + // tell GLFW to capture our mouse + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + + // glad: load all OpenGL function pointers + // --------------------------------------- + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "Failed to initialize GLAD" << std::endl; + return -1; } - // Set up G-Buffer - // 3 textures: - // 1. Positions (RGB) - // 2. Color (RGB) + Specular (A) - // 3. Normals (RGB) - GLuint gBuffer; + // configure global opengl state + // ----------------------------- + glEnable(GL_DEPTH_TEST); + + // build and compile shaders + // ------------------------- + Shader shaderGeometryPass("8.1.g_buffer.vs", "8.1.g_buffer.fs"); + Shader shaderLightingPass("8.1.deferred_shading.vs", "8.1.deferred_shading.fs"); + Shader shaderLightBox("8.1.deferred_light_box.vs", "8.1.deferred_light_box.fs"); + + // load models + // ----------- + Model nanosuit(FileSystem::getPath("resources/objects/nanosuit/nanosuit.obj")); + std::vector objectPositions; + objectPositions.push_back(glm::vec3(-3.0, -3.0, -3.0)); + objectPositions.push_back(glm::vec3( 0.0, -3.0, -3.0)); + objectPositions.push_back(glm::vec3( 3.0, -3.0, -3.0)); + objectPositions.push_back(glm::vec3(-3.0, -3.0, 0.0)); + objectPositions.push_back(glm::vec3( 0.0, -3.0, 0.0)); + objectPositions.push_back(glm::vec3( 3.0, -3.0, 0.0)); + objectPositions.push_back(glm::vec3(-3.0, -3.0, 3.0)); + objectPositions.push_back(glm::vec3( 0.0, -3.0, 3.0)); + objectPositions.push_back(glm::vec3( 3.0, -3.0, 3.0)); + + + // configure g-buffer framebuffer + // ------------------------------ + unsigned int gBuffer; glGenFramebuffers(1, &gBuffer); glBindFramebuffer(GL_FRAMEBUFFER, gBuffer); - GLuint gPosition, gNormal, gAlbedoSpec; - // - Position color buffer + unsigned int gPosition, gNormal, gAlbedoSpec; + // position color buffer glGenTextures(1, &gPosition); glBindTexture(GL_TEXTURE_2D, gPosition); - 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_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gPosition, 0); - // - Normal color buffer + 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_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gPosition, 0); + // normal color buffer glGenTextures(1, &gNormal); glBindTexture(GL_TEXTURE_2D, gNormal); 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_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, gNormal, 0); - // - Color + Specular color buffer + // color + specular color buffer glGenTextures(1, &gAlbedoSpec); glBindTexture(GL_TEXTURE_2D, gAlbedoSpec); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, gAlbedoSpec, 0); - // - Tell OpenGL which color attachments we'll use (of this framebuffer) for rendering - GLuint attachments[3] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 }; + // tell OpenGL which color attachments we'll use (of this framebuffer) for rendering + unsigned int attachments[3] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 }; glDrawBuffers(3, attachments); - // - 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); - // - Finally check if framebuffer is complete - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - std::cout << "Framebuffer not complete!" << std::endl; - glBindFramebuffer(GL_FRAMEBUFFER, 0); + // create and attach depth buffer (renderbuffer) + unsigned int 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); + // finally check if framebuffer is complete + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + std::cout << "Framebuffer not complete!" << std::endl; + glBindFramebuffer(GL_FRAMEBUFFER, 0); - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + // lighting info + // ------------- + const unsigned int NR_LIGHTS = 32; + std::vector lightPositions; + std::vector lightColors; + srand(13); + for (unsigned int i = 0; i < NR_LIGHTS; i++) + { + // calculate slightly random offsets + float xPos = ((rand() % 100) / 100.0) * 6.0 - 3.0; + float yPos = ((rand() % 100) / 100.0) * 6.0 - 4.0; + float zPos = ((rand() % 100) / 100.0) * 6.0 - 3.0; + lightPositions.push_back(glm::vec3(xPos, yPos, zPos)); + // also calculate random color + float rColor = ((rand() % 100) / 200.0f) + 0.5; // between 0.5 and 1.0 + float gColor = ((rand() % 100) / 200.0f) + 0.5; // between 0.5 and 1.0 + float bColor = ((rand() % 100) / 200.0f) + 0.5; // between 0.5 and 1.0 + lightColors.push_back(glm::vec3(rColor, gColor, bColor)); + } - // Game loop - while (!glfwWindowShouldClose(window)) - { - // Set frame time - GLfloat currentFrame = glfwGetTime(); - deltaTime = currentFrame - lastFrame; - lastFrame = currentFrame; + // shader configuration + // -------------------- + shaderLightingPass.use(); + shaderLightingPass.setInt("gPosition", 0); + shaderLightingPass.setInt("gNormal", 1); + shaderLightingPass.setInt("gAlbedoSpec", 2); - // Check and call events - glfwPollEvents(); - Do_Movement(); + // render loop + // ----------- + while (!glfwWindowShouldClose(window)) + { + // per-frame time logic + // -------------------- + float currentFrame = glfwGetTime(); + deltaTime = currentFrame - lastFrame; + lastFrame = currentFrame; - glPolygonMode(GL_FRONT_AND_BACK, wireframe ? GL_LINE : GL_FILL); + // input + // ----- + processInput(window); - // 1. Geometry Pass: render scene's geometry/color data into gbuffer - glBindFramebuffer(GL_FRAMEBUFFER, gBuffer); - 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; - shaderGeometryPass.Use(); - glUniformMatrix4fv(glGetUniformLocation(shaderGeometryPass.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); - glUniformMatrix4fv(glGetUniformLocation(shaderGeometryPass.Program, "view"), 1, GL_FALSE, glm::value_ptr(view)); - for (GLuint i = 0; i < objectPositions.size(); i++) - { - model = glm::mat4(); + // render + // ------ + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // 1. geometry pass: render scene's geometry/color data into gbuffer + // ----------------------------------------------------------------- + glBindFramebuffer(GL_FRAMEBUFFER, gBuffer); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f); + glm::mat4 view = camera.GetViewMatrix(); + glm::mat4 model; + shaderGeometryPass.use(); + shaderGeometryPass.setMat4("projection", projection); + shaderGeometryPass.setMat4("view", view); + for (unsigned int i = 0; i < objectPositions.size(); i++) + { + model = glm::mat4(); model = glm::translate(model, objectPositions[i]); model = glm::scale(model, glm::vec3(0.25f)); - glUniformMatrix4fv(glGetUniformLocation(shaderGeometryPass.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); - cyborg.Draw(shaderGeometryPass); - } + shaderGeometryPass.setMat4("model", model); + nanosuit.Draw(shaderGeometryPass); + } glBindFramebuffer(GL_FRAMEBUFFER, 0); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - - - // 2. Lighting Pass: calculate lighting by iterating over a screen filled quad pixel-by-pixel using the gbuffer's content. + // 2. lighting pass: calculate lighting by iterating over a screen filled quad pixel-by-pixel using the gbuffer's content. + // ----------------------------------------------------------------------------------------------------------------------- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - shaderLightingPass.Use(); + shaderLightingPass.use(); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, gPosition); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, gNormal); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, gAlbedoSpec); - // Also send light relevant uniforms - for (GLuint i = 0; i < lightPositions.size(); i++) + // send light relevant uniforms + for (unsigned int i = 0; i < lightPositions.size(); i++) { - glUniform3fv(glGetUniformLocation(shaderLightingPass.Program, ("lights[" + std::to_string(i) + "].Position").c_str()), 1, &lightPositions[i][0]); - glUniform3fv(glGetUniformLocation(shaderLightingPass.Program, ("lights[" + std::to_string(i) + "].Color").c_str()), 1, &lightColors[i][0]); - // Update attenuation parameters and calculate radius - const GLfloat constant = 1.0; // Note that we don't send this to the shader, we assume it is always 1.0 (in our case) - const GLfloat linear = 0.7; - const GLfloat quadratic = 1.8; - glUniform1f(glGetUniformLocation(shaderLightingPass.Program, ("lights[" + std::to_string(i) + "].Linear").c_str()), linear); - glUniform1f(glGetUniformLocation(shaderLightingPass.Program, ("lights[" + std::to_string(i) + "].Quadratic").c_str()), quadratic); - // Then calculate radius of light volume/sphere - const GLfloat lightThreshold = 5.0; // 5 / 256 - const GLfloat maxBrightness = std::fmaxf(std::fmaxf(lightColors[i].r, lightColors[i].g), lightColors[i].b); - GLfloat radius = (-linear + static_cast(std::sqrt(linear * linear - 4 * quadratic * (constant - (256.0 / lightThreshold) * maxBrightness)))) / (2 * quadratic); - glUniform1f(glGetUniformLocation(shaderLightingPass.Program, ("lights[" + std::to_string(i) + "].Radius").c_str()), radius); + shaderLightingPass.setVec3("lights[" + std::to_string(i) + "].Position", lightPositions[i]); + shaderLightingPass.setVec3("lights[" + std::to_string(i) + "].Color", lightColors[i]); + // update attenuation parameters and calculate radius + const float constant = 1.0; // note that we don't send this to the shader, we assume it is always 1.0 (in our case) + const float linear = 0.7; + const float quadratic = 1.8; + shaderLightingPass.setFloat("lights[" + std::to_string(i) + "].Linear", linear); + shaderLightingPass.setFloat("lights[" + std::to_string(i) + "].Quadratic", quadratic); } - glUniform3fv(glGetUniformLocation(shaderLightingPass.Program, "viewPos"), 1, &camera.Position[0]); - glUniform1i(glGetUniformLocation(shaderLightingPass.Program, "draw_mode"), draw_mode); - RenderQuad(); + shaderLightingPass.setVec3("viewPos", camera.Position); + // finally render quad + renderQuad(); - // 2.5. Copy content of geometry's depth buffer to default framebuffer's depth buffer + // 2.5. copy content of geometry's depth buffer to default framebuffer's depth buffer + // ---------------------------------------------------------------------------------- glBindFramebuffer(GL_READ_FRAMEBUFFER, gBuffer); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); // Write to default framebuffer - // blit to default framebuffer. Note that this may or may not work as the internal formats of both the FBO and default framebuffer have to match. - // the internal formats are implementation defined. This works on all of my systems, but if it doesn't on yours you'll likely have to write to the - // depth buffer in another stage (or somehow see to match the default framebuffer's internal format with the FBO's internal format). + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); // write to default framebuffer + // blit to default framebuffer. Note that this may or may not work as the internal formats of both the FBO and default framebuffer have to match. + // the internal formats are implementation defined. This works on all of my systems, but if it doesn't on yours you'll likely have to write to the + // depth buffer in another shader stage (or somehow see to match the default framebuffer's internal format with the FBO's internal format). glBlitFramebuffer(0, 0, SCR_WIDTH, SCR_HEIGHT, 0, 0, SCR_WIDTH, SCR_HEIGHT, GL_DEPTH_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_FRAMEBUFFER, 0); - // 3. Render lights on top of scene, by blitting - shaderLightBox.Use(); - glUniformMatrix4fv(glGetUniformLocation(shaderLightBox.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); - glUniformMatrix4fv(glGetUniformLocation(shaderLightBox.Program, "view"), 1, GL_FALSE, glm::value_ptr(view)); - for (GLuint i = 0; i < lightPositions.size(); i++) + // 3. render lights on top of scene + // -------------------------------- + shaderLightBox.use(); + shaderLightBox.setMat4("projection", projection); + shaderLightBox.setMat4("view", view); + for (unsigned int i = 0; i < lightPositions.size(); i++) { model = glm::mat4(); model = glm::translate(model, lightPositions[i]); - model = glm::scale(model, glm::vec3(0.25f)); - glUniformMatrix4fv(glGetUniformLocation(shaderLightBox.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); - glUniform3fv(glGetUniformLocation(shaderLightBox.Program, "lightColor"), 1, &lightColors[i][0]); - RenderCube(); + model = glm::scale(model, glm::vec3(0.125f)); + shaderLightBox.setMat4("model", model); + shaderLightBox.setVec3("lightColor", lightColors[i]); + renderCube(); } - // Swap the buffers - glfwSwapBuffers(window); - } - glfwTerminate(); - return 0; + // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) + // ------------------------------------------------------------------------------- + glfwSwapBuffers(window); + glfwPollEvents(); + } + + 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() +// renderCube() renders a 1x1 3D cube in NDC. +// ------------------------------------------------- +unsigned int cubeVAO = 0; +unsigned int cubeVBO = 0; +void renderCube() { - 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) + // 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 + float vertices[] = { + // back face + -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, // bottom-left + 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, // top-right + 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, // bottom-right + 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, // top-right + -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, // bottom-left + -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, // top-left + // front face + -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom-left + 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, // bottom-right + 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // top-right + 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // top-right + -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // top-left + -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom-left + // left face + -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-right + -1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-left + -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-left + -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-left + -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom-right + -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-right + // right face + 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-left + 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-right + 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-right + 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-right + 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-left + 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom-left + // bottom face + -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, // top-right + 1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f, // top-left + 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, // bottom-left + 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, // bottom-left + -1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, // bottom-right + -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, // top-right + // top face + -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // top-left + 1.0f, 1.0f , 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom-right + 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, // top-right + 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom-right + -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // top-left + -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f // bottom-left }; glGenVertexArrays(1, &cubeVAO); glGenBuffers(1, &cubeVBO); - // Fill buffer + // fill buffer glBindBuffer(GL_ARRAY_BUFFER, cubeVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); - // Link vertex attributes + // link vertex attributes glBindVertexArray(cubeVAO); glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0); glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float))); glEnableVertexAttribArray(2); - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat))); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float))); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); } - // Render Cube + // render Cube glBindVertexArray(cubeVAO); glDrawArrays(GL_TRIANGLES, 0, 36); glBindVertexArray(0); } -bool keys[1024]; -bool keysPressed[1024]; -// Moves/alters the camera positions based on user input -void Do_Movement() + +// renderQuad() renders a 1x1 XY quad in NDC +// ----------------------------------------- +unsigned int quadVAO = 0; +unsigned int quadVBO; +void renderQuad() { - // 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_1]) - draw_mode = 1; - if (keys[GLFW_KEY_2]) - draw_mode = 2; - if (keys[GLFW_KEY_3]) - draw_mode = 3; - if (keys[GLFW_KEY_4]) - draw_mode = 4; - if (keys[GLFW_KEY_5]) - draw_mode = 5; - - if (keys[GLFW_KEY_Z] && !keysPressed[GLFW_KEY_Z]) + if (quadVAO == 0) { - wireframe = !wireframe; - keysPressed[GLFW_KEY_Z] = true; + float 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(float), (void*)0); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); } + glBindVertexArray(quadVAO); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glBindVertexArray(0); } -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) +// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly +// --------------------------------------------------------------------------------------------------------- +void processInput(GLFWwindow *window) { - if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) - glfwSetWindowShouldClose(window, GL_TRUE); + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); - if (key >= 0 && key <= 1024) - { - if (action == GLFW_PRESS) - keys[key] = true; - else if (action == GLFW_RELEASE) - { - keys[key] = false; - keysPressed[key] = false; - } - } + float cameraSpeed = 2.5 * deltaTime; + if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) + camera.ProcessKeyboard(FORWARD, deltaTime); + if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) + camera.ProcessKeyboard(BACKWARD, deltaTime); + if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) + camera.ProcessKeyboard(LEFT, deltaTime); + if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) + camera.ProcessKeyboard(RIGHT, deltaTime); } +// glfw: whenever the window size changed (by OS or user resize) this callback function executes +// --------------------------------------------------------------------------------------------- +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + // make sure the viewport matches the new window dimensions; note that width and + // height will be significantly larger than specified on retina displays. + glViewport(0, 0, width, height); +} + + +// glfw: whenever the mouse moves, this callback is called +// ------------------------------------------------------- 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; + float xoffset = xpos - lastX; + float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top - lastX = xpos; - lastY = ypos; + lastX = xpos; + lastY = ypos; - camera.ProcessMouseMovement(xoffset, yoffset); + camera.ProcessMouseMovement(xoffset, yoffset); } +// glfw: whenever the mouse scroll wheel scrolls, this callback is called +// ---------------------------------------------------------------------- void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) { - camera.ProcessMouseScroll(yoffset); -} + camera.ProcessMouseScroll(yoffset); +} \ No newline at end of file diff --git a/src/5.advanced_lighting/8.2.deferred_shading_volumes/8.2.deferred_shading.fs b/src/5.advanced_lighting/8.2.deferred_shading_volumes/8.2.deferred_shading.fs index 8053f81..325ba22 100644 --- a/src/5.advanced_lighting/8.2.deferred_shading_volumes/8.2.deferred_shading.fs +++ b/src/5.advanced_lighting/8.2.deferred_shading_volumes/8.2.deferred_shading.fs @@ -1,5 +1,6 @@ #version 330 core out vec4 FragColor; + in vec2 TexCoords; uniform sampler2D gPosition; @@ -18,49 +19,36 @@ const int NR_LIGHTS = 32; uniform Light lights[NR_LIGHTS]; uniform vec3 viewPos; -uniform int draw_mode; - void main() { - // Retrieve data from gbuffer + // retrieve data from gbuffer vec3 FragPos = texture(gPosition, TexCoords).rgb; vec3 Normal = texture(gNormal, TexCoords).rgb; vec3 Diffuse = texture(gAlbedoSpec, TexCoords).rgb; float Specular = texture(gAlbedoSpec, TexCoords).a; - // Then calculate lighting as usual + // then calculate lighting as usual vec3 lighting = Diffuse * 0.1; // hard-coded ambient component vec3 viewDir = normalize(viewPos - FragPos); for(int i = 0; i < NR_LIGHTS; ++i) { - // Calculate distance between light source and current fragment + // calculate distance between light source and current fragment float distance = length(lights[i].Position - FragPos); if(distance < lights[i].Radius) { - // Diffuse + // diffuse vec3 lightDir = normalize(lights[i].Position - FragPos); vec3 diffuse = max(dot(Normal, lightDir), 0.0) * Diffuse * lights[i].Color; - // Specular + // specular vec3 halfwayDir = normalize(lightDir + viewDir); float spec = pow(max(dot(Normal, halfwayDir), 0.0), 16.0); vec3 specular = lights[i].Color * spec * Specular; - // Attenuation + // attenuation float attenuation = 1.0 / (1.0 + lights[i].Linear * distance + lights[i].Quadratic * distance * distance); diffuse *= attenuation; specular *= attenuation; lighting += diffuse + specular; } } - - // Based on which of the 1-5 keys we pressed, show final result or intermediate g-buffer textures - if(draw_mode == 1) - FragColor = vec4(lighting, 1.0); - else if(draw_mode == 2) - FragColor = vec4(FragPos, 1.0); - else if(draw_mode == 3) - FragColor = vec4(Normal, 1.0); - else if(draw_mode == 4) - FragColor = vec4(Diffuse, 1.0); - else if(draw_mode == 5) - FragColor = vec4(vec3(Specular), 1.0); + FragColor = vec4(lighting, 1.0); } diff --git a/src/5.advanced_lighting/8.2.deferred_shading_volumes/8.2.deferred_shading.vs b/src/5.advanced_lighting/8.2.deferred_shading_volumes/8.2.deferred_shading.vs index 819c18d..9f93e29 100644 --- a/src/5.advanced_lighting/8.2.deferred_shading_volumes/8.2.deferred_shading.vs +++ b/src/5.advanced_lighting/8.2.deferred_shading_volumes/8.2.deferred_shading.vs @@ -1,11 +1,11 @@ #version 330 core -layout (location = 0) in vec3 position; -layout (location = 1) in vec2 texCoords; +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec2 aTexCoords; out vec2 TexCoords; void main() { - gl_Position = vec4(position, 1.0f); - TexCoords = texCoords; + TexCoords = aTexCoords; + gl_Position = vec4(aPos, 1.0); } \ No newline at end of file diff --git a/src/5.advanced_lighting/8.2.deferred_shading_volumes/deferred_shading_volumes.cpp b/src/5.advanced_lighting/8.2.deferred_shading_volumes/deferred_shading_volumes.cpp index f3bf8f7..a520dc9 100644 --- a/src/5.advanced_lighting/8.2.deferred_shading_volumes/deferred_shading_volumes.cpp +++ b/src/5.advanced_lighting/8.2.deferred_shading_volumes/deferred_shading_volumes.cpp @@ -1,441 +1,429 @@ -// GLEW -#define GLEW_STATIC -#include - -// GLFW +#include #include -// GL includes -#include -#include -#include - -// GLM Mathemtics #include #include #include -// Other Libs -#include #include +#include +#include +#include -// Properties -const GLuint SCR_WIDTH = 800, SCR_HEIGHT = 600; +#include -// Function prototypes -void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode); -void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); +void framebuffer_size_callback(GLFWwindow* window, int width, int height); void mouse_callback(GLFWwindow* window, double xpos, double ypos); -void Do_Movement(); -GLuint loadTexture(GLchar const * path); -void RenderCube(); -void RenderQuad(); +void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); +void processInput(GLFWwindow *window); +unsigned int loadTexture(const char *path, bool gammaCorrection); +void renderQuad(); +void renderCube(); -// Camera +// settings +const unsigned int SCR_WIDTH = 1280; +const unsigned int SCR_HEIGHT = 720; + +// camera Camera camera(glm::vec3(0.0f, 0.0f, 5.0f)); +float lastX = (float)SCR_WIDTH / 2.0; +float lastY = (float)SCR_HEIGHT / 2.0; +bool firstMouse = true; -// Delta -GLfloat deltaTime = 0.0f; -GLfloat lastFrame = 0.0f; +// timing +float deltaTime = 0.0f; +float lastFrame = 0.0f; -// Options -GLuint draw_mode = 1; -GLboolean wireframe = false; - -// 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); + // glfw: initialize and configure + // ------------------------------ + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - 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); - - // Options - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); - - // Initialize GLEW to setup the OpenGL Function pointers - glewExperimental = GL_TRUE; - glewInit(); - - // Define the viewport dimensions - glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT); - - // Setup some OpenGL options - glEnable(GL_DEPTH_TEST); - - // Setup and compile our shaders - Shader shaderGeometryPass("g_buffer.vs", "g_buffer.frag"); - Shader shaderLightingPass("deferred_shading.vs", "deferred_shading.frag"); - Shader shaderLightBox("deferred_light_box.vs", "deferred_light_box.frag"); - - // Set samplers - shaderLightingPass.Use(); - glUniform1i(glGetUniformLocation(shaderLightingPass.Program, "gPosition"), 0); - glUniform1i(glGetUniformLocation(shaderLightingPass.Program, "gNormal"), 1); - glUniform1i(glGetUniformLocation(shaderLightingPass.Program, "gAlbedoSpec"), 2); - - // Models - Model cyborg(FileSystem::getPath("resources/objects/nanosuit/nanosuit.obj").c_str()); - std::vector objectPositions; - objectPositions.push_back(glm::vec3(-3.0, -3.0, -3.0)); - objectPositions.push_back(glm::vec3(0.0, -3.0, -3.0)); - objectPositions.push_back(glm::vec3(3.0, -3.0, -3.0)); - objectPositions.push_back(glm::vec3(-3.0, -3.0, 0.0)); - objectPositions.push_back(glm::vec3(0.0, -3.0, 0.0)); - objectPositions.push_back(glm::vec3(3.0, -3.0, 0.0)); - objectPositions.push_back(glm::vec3(-3.0, -3.0, 3.0)); - objectPositions.push_back(glm::vec3(0.0, -3.0, 3.0)); - objectPositions.push_back(glm::vec3(3.0, -3.0, 3.0)); - // - Colors - const GLuint NR_LIGHTS = 32; - std::vector lightPositions; - std::vector lightColors; - srand(13); - for (GLuint i = 0; i < NR_LIGHTS; i++) + // glfw window creation + // -------------------- + GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL); + glfwMakeContextCurrent(window); + if (window == NULL) { - // Calculate slightly random offsets - GLfloat xPos = ((rand() % 100) / 100.0) * 6.0 - 3.0; - GLfloat yPos = ((rand() % 100) / 100.0) * 6.0 - 4.0; - GLfloat zPos = ((rand() % 100) / 100.0) * 6.0 - 3.0; - lightPositions.push_back(glm::vec3(xPos, yPos, zPos)); - // Also calculate random color - GLfloat rColor = ((rand() % 100) / 200.0f) + 0.5; // Between 0.5 and 1.0 - GLfloat gColor = ((rand() % 100) / 200.0f) + 0.5; // Between 0.5 and 1.0 - GLfloat bColor = ((rand() % 100) / 200.0f) + 0.5; // Between 0.5 and 1.0 - lightColors.push_back(glm::vec3(rColor, gColor, bColor)); + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + return -1; + } + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + glfwSetCursorPosCallback(window, mouse_callback); + glfwSetScrollCallback(window, scroll_callback); + + // tell GLFW to capture our mouse + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + + // glad: load all OpenGL function pointers + // --------------------------------------- + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "Failed to initialize GLAD" << std::endl; + return -1; } - // Set up G-Buffer - // 3 textures: - // 1. Positions (RGB) - // 2. Color (RGB) + Specular (A) - // 3. Normals (RGB) - GLuint gBuffer; + // configure global opengl state + // ----------------------------- + glEnable(GL_DEPTH_TEST); + + // build and compile shaders + // ------------------------- + Shader shaderGeometryPass("8.1.g_buffer.vs", "8.1.g_buffer.fs"); + Shader shaderLightingPass("8.2.deferred_shading.vs", "8.2.deferred_shading.fs"); + Shader shaderLightBox("8.1.deferred_light_box.vs", "8.1.deferred_light_box.fs"); + + // load models + // ----------- + Model nanosuit(FileSystem::getPath("resources/objects/nanosuit/nanosuit.obj")); + std::vector objectPositions; + objectPositions.push_back(glm::vec3(-3.0, -3.0, -3.0)); + objectPositions.push_back(glm::vec3( 0.0, -3.0, -3.0)); + objectPositions.push_back(glm::vec3( 3.0, -3.0, -3.0)); + objectPositions.push_back(glm::vec3(-3.0, -3.0, 0.0)); + objectPositions.push_back(glm::vec3( 0.0, -3.0, 0.0)); + objectPositions.push_back(glm::vec3( 3.0, -3.0, 0.0)); + objectPositions.push_back(glm::vec3(-3.0, -3.0, 3.0)); + objectPositions.push_back(glm::vec3( 0.0, -3.0, 3.0)); + objectPositions.push_back(glm::vec3( 3.0, -3.0, 3.0)); + + + // configure g-buffer framebuffer + // ------------------------------ + unsigned int gBuffer; glGenFramebuffers(1, &gBuffer); glBindFramebuffer(GL_FRAMEBUFFER, gBuffer); - GLuint gPosition, gNormal, gAlbedoSpec; - // - Position color buffer + unsigned int gPosition, gNormal, gAlbedoSpec; + // position color buffer glGenTextures(1, &gPosition); glBindTexture(GL_TEXTURE_2D, gPosition); - 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_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gPosition, 0); - // - Normal color buffer + 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_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gPosition, 0); + // normal color buffer glGenTextures(1, &gNormal); glBindTexture(GL_TEXTURE_2D, gNormal); 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_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, gNormal, 0); - // - Color + Specular color buffer + // color + specular color buffer glGenTextures(1, &gAlbedoSpec); glBindTexture(GL_TEXTURE_2D, gAlbedoSpec); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, gAlbedoSpec, 0); - // - Tell OpenGL which color attachments we'll use (of this framebuffer) for rendering - GLuint attachments[3] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 }; + // tell OpenGL which color attachments we'll use (of this framebuffer) for rendering + unsigned int attachments[3] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 }; glDrawBuffers(3, attachments); - // - 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); - // - Finally check if framebuffer is complete - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - std::cout << "Framebuffer not complete!" << std::endl; - glBindFramebuffer(GL_FRAMEBUFFER, 0); + // create and attach depth buffer (renderbuffer) + unsigned int 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); + // finally check if framebuffer is complete + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + std::cout << "Framebuffer not complete!" << std::endl; + glBindFramebuffer(GL_FRAMEBUFFER, 0); - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + // lighting info + // ------------- + const unsigned int NR_LIGHTS = 32; + std::vector lightPositions; + std::vector lightColors; + srand(13); + for (unsigned int i = 0; i < NR_LIGHTS; i++) + { + // calculate slightly random offsets + float xPos = ((rand() % 100) / 100.0) * 6.0 - 3.0; + float yPos = ((rand() % 100) / 100.0) * 6.0 - 4.0; + float zPos = ((rand() % 100) / 100.0) * 6.0 - 3.0; + lightPositions.push_back(glm::vec3(xPos, yPos, zPos)); + // also calculate random color + float rColor = ((rand() % 100) / 200.0f) + 0.5; // between 0.5 and 1.0 + float gColor = ((rand() % 100) / 200.0f) + 0.5; // between 0.5 and 1.0 + float bColor = ((rand() % 100) / 200.0f) + 0.5; // between 0.5 and 1.0 + lightColors.push_back(glm::vec3(rColor, gColor, bColor)); + } - // Game loop - while (!glfwWindowShouldClose(window)) - { - // Set frame time - GLfloat currentFrame = glfwGetTime(); - deltaTime = currentFrame - lastFrame; - lastFrame = currentFrame; + // shader configuration + // -------------------- + shaderLightingPass.use(); + shaderLightingPass.setInt("gPosition", 0); + shaderLightingPass.setInt("gNormal", 1); + shaderLightingPass.setInt("gAlbedoSpec", 2); - // Check and call events - glfwPollEvents(); - Do_Movement(); + // render loop + // ----------- + while (!glfwWindowShouldClose(window)) + { + // per-frame time logic + // -------------------- + float currentFrame = glfwGetTime(); + deltaTime = currentFrame - lastFrame; + lastFrame = currentFrame; - glPolygonMode(GL_FRONT_AND_BACK, wireframe ? GL_LINE : GL_FILL); + // input + // ----- + processInput(window); - // 1. Geometry Pass: render scene's geometry/color data into gbuffer - glBindFramebuffer(GL_FRAMEBUFFER, gBuffer); - 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; - shaderGeometryPass.Use(); - glUniformMatrix4fv(glGetUniformLocation(shaderGeometryPass.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); - glUniformMatrix4fv(glGetUniformLocation(shaderGeometryPass.Program, "view"), 1, GL_FALSE, glm::value_ptr(view)); - for (GLuint i = 0; i < objectPositions.size(); i++) - { - model = glm::mat4(); - model = glm::translate(model, objectPositions[i]); - model = glm::scale(model, glm::vec3(0.25f)); - glUniformMatrix4fv(glGetUniformLocation(shaderGeometryPass.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); - cyborg.Draw(shaderGeometryPass); - } + // render + // ------ + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // 1. geometry pass: render scene's geometry/color data into gbuffer + // ----------------------------------------------------------------- + glBindFramebuffer(GL_FRAMEBUFFER, gBuffer); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f); + glm::mat4 view = camera.GetViewMatrix(); + glm::mat4 model; + shaderGeometryPass.use(); + shaderGeometryPass.setMat4("projection", projection); + shaderGeometryPass.setMat4("view", view); + for (unsigned int i = 0; i < objectPositions.size(); i++) + { + model = glm::mat4(); + model = glm::translate(model, objectPositions[i]); + model = glm::scale(model, glm::vec3(0.25f)); + shaderGeometryPass.setMat4("model", model); + nanosuit.Draw(shaderGeometryPass); + } glBindFramebuffer(GL_FRAMEBUFFER, 0); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - - - // 2. Lighting Pass: calculate lighting by iterating over a screen filled quad pixel-by-pixel using the gbuffer's content. + // 2. lighting pass: calculate lighting by iterating over a screen filled quad pixel-by-pixel using the gbuffer's content. + // ----------------------------------------------------------------------------------------------------------------------- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - shaderLightingPass.Use(); + shaderLightingPass.use(); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, gPosition); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, gNormal); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, gAlbedoSpec); - // Also send light relevant uniforms - for (GLuint i = 0; i < lightPositions.size(); i++) + // send light relevant uniforms + for (unsigned int i = 0; i < lightPositions.size(); i++) { - glUniform3fv(glGetUniformLocation(shaderLightingPass.Program, ("lights[" + std::to_string(i) + "].Position").c_str()), 1, &lightPositions[i][0]); - glUniform3fv(glGetUniformLocation(shaderLightingPass.Program, ("lights[" + std::to_string(i) + "].Color").c_str()), 1, &lightColors[i][0]); - // Update attenuation parameters and calculate radius - const GLfloat constant = 1.0; // Note that we don't send this to the shader, we assume it is always 1.0 (in our case) - const GLfloat linear = 0.7; - const GLfloat quadratic = 1.8; - glUniform1f(glGetUniformLocation(shaderLightingPass.Program, ("lights[" + std::to_string(i) + "].Linear").c_str()), linear); - glUniform1f(glGetUniformLocation(shaderLightingPass.Program, ("lights[" + std::to_string(i) + "].Quadratic").c_str()), quadratic); - // Then calculate radius of light volume/sphere - const GLfloat lightThreshold = 5.0; // 5 / 256 - const GLfloat maxBrightness = std::fmaxf(std::fmaxf(lightColors[i].r, lightColors[i].g), lightColors[i].b); - GLfloat radius = (-linear + static_cast(std::sqrt(linear * linear - 4 * quadratic * (constant - (256.0 / lightThreshold) * maxBrightness)))) / (2 * quadratic); - glUniform1f(glGetUniformLocation(shaderLightingPass.Program, ("lights[" + std::to_string(i) + "].Radius").c_str()), radius); + shaderLightingPass.setVec3("lights[" + std::to_string(i) + "].Position", lightPositions[i]); + shaderLightingPass.setVec3("lights[" + std::to_string(i) + "].Color", lightColors[i]); + // update attenuation parameters and calculate radius + const float constant = 1.0; // note that we don't send this to the shader, we assume it is always 1.0 (in our case) + const float linear = 0.7; + const float quadratic = 1.8; + shaderLightingPass.setFloat("lights[" + std::to_string(i) + "].Linear", linear); + shaderLightingPass.setFloat("lights[" + std::to_string(i) + "].Quadratic", quadratic); + // then calculate radius of light volume/sphere + const float maxBrightness = std::fmaxf(std::fmaxf(lightColors[i].r, lightColors[i].g), lightColors[i].b); + float radius = (-linear + std::sqrtf(linear * linear - 4 * quadratic * (constant - (256.0f / 5.0f) * maxBrightness))) / (2.0f * quadratic); + shaderLightingPass.setFloat("lights[" + std::to_string(i) + "].Radius", radius); } - glUniform3fv(glGetUniformLocation(shaderLightingPass.Program, "viewPos"), 1, &camera.Position[0]); - glUniform1i(glGetUniformLocation(shaderLightingPass.Program, "draw_mode"), draw_mode); - RenderQuad(); + shaderLightingPass.setVec3("viewPos", camera.Position); + // finally render quad + renderQuad(); - // 2.5. Copy content of geometry's depth buffer to default framebuffer's depth buffer + // 2.5. copy content of geometry's depth buffer to default framebuffer's depth buffer + // ---------------------------------------------------------------------------------- glBindFramebuffer(GL_READ_FRAMEBUFFER, gBuffer); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); // Write to default framebuffer - // blit to default framebuffer. Note that this may or may not work as the internal formats of both the FBO and default framebuffer have to match. - // the internal formats are implementation defined. This works on all of my systems, but if it doesn't on yours you'll likely have to write to the - // depth buffer in another stage (or somehow see to match the default framebuffer's internal format with the FBO's internal format). + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); // write to default framebuffer + // blit to default framebuffer. Note that this may or may not work as the internal formats of both the FBO and default framebuffer have to match. + // the internal formats are implementation defined. This works on all of my systems, but if it doesn't on yours you'll likely have to write to the + // depth buffer in another shader stage (or somehow see to match the default framebuffer's internal format with the FBO's internal format). glBlitFramebuffer(0, 0, SCR_WIDTH, SCR_HEIGHT, 0, 0, SCR_WIDTH, SCR_HEIGHT, GL_DEPTH_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_FRAMEBUFFER, 0); - // 3. Render lights on top of scene, by blitting - shaderLightBox.Use(); - glUniformMatrix4fv(glGetUniformLocation(shaderLightBox.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); - glUniformMatrix4fv(glGetUniformLocation(shaderLightBox.Program, "view"), 1, GL_FALSE, glm::value_ptr(view)); - for (GLuint i = 0; i < lightPositions.size(); i++) + // 3. render lights on top of scene + // -------------------------------- + shaderLightBox.use(); + shaderLightBox.setMat4("projection", projection); + shaderLightBox.setMat4("view", view); + for (unsigned int i = 0; i < lightPositions.size(); i++) { model = glm::mat4(); model = glm::translate(model, lightPositions[i]); - model = glm::scale(model, glm::vec3(0.25f)); - glUniformMatrix4fv(glGetUniformLocation(shaderLightBox.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); - glUniform3fv(glGetUniformLocation(shaderLightBox.Program, "lightColor"), 1, &lightColors[i][0]); - RenderCube(); + model = glm::scale(model, glm::vec3(0.125f)); + shaderLightBox.setMat4("model", model); + shaderLightBox.setVec3("lightColor", lightColors[i]); + renderCube(); } - // Swap the buffers - glfwSwapBuffers(window); - } - glfwTerminate(); - return 0; + // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) + // ------------------------------------------------------------------------------- + glfwSwapBuffers(window); + glfwPollEvents(); + } + + 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() +// renderCube() renders a 1x1 3D cube in NDC. +// ------------------------------------------------- +unsigned int cubeVAO = 0; +unsigned int cubeVBO = 0; +void renderCube() { - 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) + // 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 + float vertices[] = { + // back face + -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, // bottom-left + 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, // top-right + 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, // bottom-right + 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, // top-right + -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, // bottom-left + -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, // top-left + // front face + -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom-left + 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, // bottom-right + 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // top-right + 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // top-right + -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // top-left + -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom-left + // left face + -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-right + -1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-left + -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-left + -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-left + -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom-right + -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-right + // right face + 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-left + 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-right + 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-right + 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-right + 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-left + 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom-left + // bottom face + -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, // top-right + 1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f, // top-left + 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, // bottom-left + 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, // bottom-left + -1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, // bottom-right + -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, // top-right + // top face + -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // top-left + 1.0f, 1.0f , 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom-right + 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, // top-right + 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom-right + -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // top-left + -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f // bottom-left }; glGenVertexArrays(1, &cubeVAO); glGenBuffers(1, &cubeVBO); - // Fill buffer + // fill buffer glBindBuffer(GL_ARRAY_BUFFER, cubeVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); - // Link vertex attributes + // link vertex attributes glBindVertexArray(cubeVAO); glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0); glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float))); glEnableVertexAttribArray(2); - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat))); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float))); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); } - // Render Cube + // render Cube glBindVertexArray(cubeVAO); glDrawArrays(GL_TRIANGLES, 0, 36); glBindVertexArray(0); } -bool keys[1024]; -bool keysPressed[1024]; -// Moves/alters the camera positions based on user input -void Do_Movement() + +// renderQuad() renders a 1x1 XY quad in NDC +// ----------------------------------------- +unsigned int quadVAO = 0; +unsigned int quadVBO; +void renderQuad() { - // 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_1]) - draw_mode = 1; - if (keys[GLFW_KEY_2]) - draw_mode = 2; - if (keys[GLFW_KEY_3]) - draw_mode = 3; - if (keys[GLFW_KEY_4]) - draw_mode = 4; - if (keys[GLFW_KEY_5]) - draw_mode = 5; - - if (keys[GLFW_KEY_Z] && !keysPressed[GLFW_KEY_Z]) + if (quadVAO == 0) { - wireframe = !wireframe; - keysPressed[GLFW_KEY_Z] = true; + float 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(float), (void*)0); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); } + glBindVertexArray(quadVAO); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glBindVertexArray(0); } -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) +// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly +// --------------------------------------------------------------------------------------------------------- +void processInput(GLFWwindow *window) { - if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) - glfwSetWindowShouldClose(window, GL_TRUE); + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); - if (key >= 0 && key <= 1024) - { - if (action == GLFW_PRESS) - keys[key] = true; - else if (action == GLFW_RELEASE) - { - keys[key] = false; - keysPressed[key] = false; - } - } + float cameraSpeed = 2.5 * deltaTime; + if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) + camera.ProcessKeyboard(FORWARD, deltaTime); + if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) + camera.ProcessKeyboard(BACKWARD, deltaTime); + if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) + camera.ProcessKeyboard(LEFT, deltaTime); + if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) + camera.ProcessKeyboard(RIGHT, deltaTime); } +// glfw: whenever the window size changed (by OS or user resize) this callback function executes +// --------------------------------------------------------------------------------------------- +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + // make sure the viewport matches the new window dimensions; note that width and + // height will be significantly larger than specified on retina displays. + glViewport(0, 0, width, height); +} + + +// glfw: whenever the mouse moves, this callback is called +// ------------------------------------------------------- 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; + float xoffset = xpos - lastX; + float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top - lastX = xpos; - lastY = ypos; + lastX = xpos; + lastY = ypos; - camera.ProcessMouseMovement(xoffset, yoffset); + camera.ProcessMouseMovement(xoffset, yoffset); } +// glfw: whenever the mouse scroll wheel scrolls, this callback is called +// ---------------------------------------------------------------------- void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) { - camera.ProcessMouseScroll(yoffset); -} + camera.ProcessMouseScroll(yoffset); +} \ No newline at end of file