From b5ea38f87fbe3ed74c0b2bd9b6f94dbfded8e9ea Mon Sep 17 00:00:00 2001 From: Joey de Vries Date: Fri, 26 May 2017 13:18:50 +0200 Subject: [PATCH] Update early PBR chapters to conform to new code standard. --- src/6.pbr/1.1.lighting/lighting.cpp | 360 +++++++++-------- .../lighting_textured.cpp | 364 +++++++++--------- .../ibl_specular_textured.cpp | 13 +- 3 files changed, 374 insertions(+), 363 deletions(-) diff --git a/src/6.pbr/1.1.lighting/lighting.cpp b/src/6.pbr/1.1.lighting/lighting.cpp index eb77c5d..7398e43 100644 --- a/src/6.pbr/1.1.lighting/lighting.cpp +++ b/src/6.pbr/1.1.lighting/lighting.cpp @@ -1,93 +1,87 @@ -// Std. Includes -#include - -// GLEW -#define GLEW_STATIC -#include - -// GLFW +#include #include +#include -// GL includes -#include -#include -#include - -// GLM Mathemtics #include #include #include -// Other Libs -#include #include +#include +#include +#include -// Properties -const GLuint SCR_WIDTH = 1280, SCR_HEIGHT = 720; +#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 RenderQuad(); +void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); +void processInput(GLFWwindow *window); +unsigned int loadTexture(const char *path); void renderSphere(); - // camera Camera camera(glm::vec3(0.0f, 0.0f, 3.0f)); +float lastX = 800.0f / 2.0; +float lastY = 600.0 / 2.0; +bool firstMouse = true; -// timing -GLfloat deltaTime = 0.0f; -GLfloat lastFrame = 0.0f; +float deltaTime = 0.0f; +float lastFrame = 0.0f; +// settings +const unsigned int SCR_WIDTH = 1280; +const unsigned int SCR_HEIGHT = 720; -// The MAIN function, from here we start our application and run our Game loop int main() { - // Init GLFW + // 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); glfwWindowHint(GLFW_SAMPLES, 4); - glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", nullptr, nullptr); // Windowed + // glfw window creation + // -------------------- + GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL); glfwMakeContextCurrent(window); - - // Set the required callback functions - glfwSetKeyCallback(window, key_callback); + if (window == NULL) + { + 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); - // Options + // tell GLFW to capture our mouse glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); - // Initialize GLEW to setup the OpenGL Function pointers - glewExperimental = GL_TRUE; - glewInit(); + // glad: load all OpenGL function pointers + // --------------------------------------- + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "Failed to initialize GLAD" << std::endl; + return -1; + } - // Define the viewport dimensions - glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT); - - // Setup some OpenGL options + // configure global opengl state + // ----------------------------- glEnable(GL_DEPTH_TEST); - // Setup and compile our shaders - Shader shader("pbr.vs", "pbr.frag"); + // build and compile shaders + // ------------------------- + Shader shader("1.1.pbr.vs", "1.1.pbr.fs"); - // set (constant) material properties - shader.Use(); - glUniform3f(glGetUniformLocation(shader.Program, "albedo"), 0.5f, 0.0f, 0.0f); - glUniform1f(glGetUniformLocation(shader.Program, "ao"), 1.0f); - - // projection setup - glm::mat4 projection = glm::perspective(camera.Zoom, (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f); - glUniformMatrix4fv(glGetUniformLocation(shader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); + shader.use(); + shader.setVec3("albedo", 0.5f, 0.0f, 0.0f); + shader.setFloat("ao", 1.0f); // lights + // ------ glm::vec3 lightPositions[] = { glm::vec3(-10.0f, 10.0f, 10.0f), glm::vec3( 10.0f, 10.0f, 10.0f), @@ -104,42 +98,47 @@ int main() int nrColumns = 7; float spacing = 2.5; + // initialize static shader uniforms before rendering + // -------------------------------------------------- + glm::mat4 projection = glm::perspective(camera.Zoom, (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f); + shader.use(); + shader.setMat4("projection", projection); - // Game loop + // render loop + // ----------- while (!glfwWindowShouldClose(window)) { - // set frame time - GLfloat currentFrame = glfwGetTime(); + // per-frame time logic + // -------------------- + float currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; - // check and call events - glfwPollEvents(); - Do_Movement(); + // input + // ----- + processInput(window); - // clear the colorbuffer + // render + // ------ glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // configure view matrix - shader.Use(); + shader.use(); glm::mat4 view = camera.GetViewMatrix(); - glUniformMatrix4fv(glGetUniformLocation(shader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view)); - - // setup relevant shader uniforms - glUniform3fv(glGetUniformLocation(shader.Program, "camPos"), 1, &camera.Position[0]); - glUniform1f(glGetUniformLocation(shader.Program, "exposure"), 1.0f); + shader.setMat4("view", view); + shader.setVec3("camPos", camera.Position); + shader.setFloat("exposure", 1.0f); // render rows*column number of spheres with varying metallic/roughness values scaled by rows and columns respectively glm::mat4 model; - for (int row = 0; row < nrRows; ++row) + for (unsigned int row = 0; row < nrRows; ++row) { - glUniform1f(glGetUniformLocation(shader.Program, "metallic"), (float)row / (float)nrRows); - for (int col = 0; col < nrColumns; ++col) + shader.setFloat("metallic", (float)row / (float)nrRows); + for (unsigned int col = 0; col < nrColumns; ++col) { // we clamp the roughness to 0.025 - 1.0 as perfectly smooth surfaces (roughness of 0.0) tend to look a bit off // on direct lighting. - glUniform1f(glGetUniformLocation(shader.Program, "roughness"), glm::clamp((float)col / (float)nrColumns, 0.05f, 1.0f)); + shader.setFloat("roughness", glm::clamp((float)col / (float)nrColumns, 0.05f, 1.0f)); model = glm::mat4(); model = glm::translate(model, glm::vec3( @@ -147,7 +146,7 @@ int main() (float)(row - (nrRows / 2)) * spacing, 0.0f )); - glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); + shader.setMat4("model", model); renderSphere(); } } @@ -157,25 +156,87 @@ int main() // keeps the codeprint small. for (unsigned int i = 0; i < sizeof(lightPositions) / sizeof(lightPositions[0]); ++i) { - glUniform3fv(glGetUniformLocation(shader.Program, ("lightPositions[" + std::to_string(i) + "]").c_str()), 1, &lightPositions[i][0]); - glUniform3fv(glGetUniformLocation(shader.Program, ("lightColors[" + std::to_string(i) + "]").c_str()), 1, &lightColors[i][0]); + glm::vec3 newPos = lightPositions[i] + glm::vec3(sin(glfwGetTime() * 5.0) * 5.0, 0.0, 0.0); + newPos = lightPositions[i]; + shader.setVec3("lightPositions[" + std::to_string(i) + "]", newPos); + shader.setVec3("lightColors[" + std::to_string(i) + "]", lightColors[i]); model = glm::mat4(); - model = glm::translate(model, lightPositions[i]); + model = glm::translate(model, newPos); model = glm::scale(model, glm::vec3(0.5f)); - glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); + shader.setMat4("model", model); renderSphere(); } - // Swap the buffers + // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) + // ------------------------------------------------------------------------------- glfwSwapBuffers(window); + glfwPollEvents(); } + // glfw: terminate, clearing all previously allocated GLFW resources. + // ------------------------------------------------------------------ glfwTerminate(); return 0; } -// renders (and builds if necessary) a sphere +// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly +// --------------------------------------------------------------------------------------------------------- +void processInput(GLFWwindow *window) +{ + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); + + 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; + } + + float xoffset = xpos - lastX; + float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top + + lastX = xpos; + lastY = ypos; + + 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); +} + +// renders (and builds at first invocation) a sphere +// ------------------------------------------------- unsigned int sphereVAO = 0; unsigned int indexCount; void renderSphere() @@ -191,8 +252,6 @@ void renderSphere() std::vector positions; std::vector uv; std::vector normals; - std::vector tangents; - std::vector bitangents; std::vector indices; const unsigned int X_SEGMENTS = 64; @@ -204,7 +263,7 @@ void renderSphere() { float xSegment = (float)x / (float)X_SEGMENTS; float ySegment = (float)y / (float)Y_SEGMENTS; - float xPos = std::cos(xSegment * 2.0f * PI) * std::sin(ySegment * PI); + float xPos = std::cos(xSegment * 2.0f * PI) * std::sin(ySegment * PI); float yPos = std::cos(ySegment * PI); float zPos = std::sin(xSegment * 2.0f * PI) * std::sin(ySegment * PI); @@ -236,6 +295,7 @@ void renderSphere() oddRow = !oddRow; } indexCount = indices.size(); + std::vector data; for (int i = 0; i < positions.size(); ++i) { @@ -253,18 +313,6 @@ void renderSphere() data.push_back(normals[i].y); data.push_back(normals[i].z); } - if (tangents.size() > 0) - { - data.push_back(tangents[i].x); - data.push_back(tangents[i].y); - data.push_back(tangents[i].z); - } - if (bitangents.size() > 0) - { - data.push_back(bitangents[i].x); - data.push_back(bitangents[i].y); - data.push_back(bitangents[i].z); - } } glBindVertexArray(sphereVAO); glBindBuffer(GL_ARRAY_BUFFER, vbo); @@ -273,102 +321,52 @@ void renderSphere() glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW); float stride = (3 + 2 + 3) * sizeof(float); glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, (void*)0); glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)(3 * sizeof(float))); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (void*)(3 * sizeof(float))); glEnableVertexAttribArray(2); - glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)(5 * sizeof(float))); + glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, stride, (void*)(5 * sizeof(float))); } glBindVertexArray(sphereVAO); glDrawElements(GL_TRIANGLE_STRIP, indexCount, GL_UNSIGNED_INT, 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 const * path) +// utility function for loading a 2D texture from file +// --------------------------------------------------- +unsigned int loadTexture(char const * path) { - //Generate texture ID and load texture data - GLuint textureID; + unsigned int 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); - // 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); + int width, height, nrComponents; + unsigned char *data = stbi_load(path, &width, &height, &nrComponents, 0); + if (data) + { + GLenum format; + if (nrComponents == 1) + format = GL_RED; + else if (nrComponents == 3) + format = GL_RGB; + else if (nrComponents == 4) + format = GL_RGBA; + + glBindTexture(GL_TEXTURE_2D, textureID); + glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + + 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); + + stbi_image_free(data); + } + else + { + std::cout << "Texture failed to load at path: " << path << std::endl; + stbi_image_free(data); + } + 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); -} - -// 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 >= 0 && key <= 1024) - { - if (action == GLFW_PRESS) - keys[key] = true; - else if (action == GLFW_RELEASE) - { - keys[key] = false; - keysPressed[key] = false; - } - } -} - -GLfloat lastX = 400, lastY = 300; -bool firstMouse = true; -// Moves/alters the camera positions based on user input -void mouse_callback(GLFWwindow* window, double xpos, double ypos) -{ - if (firstMouse) - { - lastX = xpos; - lastY = ypos; - firstMouse = false; - } - - GLfloat xoffset = xpos - lastX; - 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/6.pbr/1.2.lighting_textured/lighting_textured.cpp b/src/6.pbr/1.2.lighting_textured/lighting_textured.cpp index 93e251f..b48c8c1 100644 --- a/src/6.pbr/1.2.lighting_textured/lighting_textured.cpp +++ b/src/6.pbr/1.2.lighting_textured/lighting_textured.cpp @@ -1,138 +1,139 @@ -// Std. Includes -#include - -// GLEW -#define GLEW_STATIC -#include - -// GLFW +#include #include +#include -// GL includes -#include -#include -#include - -// GLM Mathemtics #include #include #include -// Other Libs -#include #include +#include +#include +#include -// Properties -const GLuint SCR_WIDTH = 1280, SCR_HEIGHT = 720; +#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 scroll_callback(GLFWwindow* window, double xoffset, double yoffset); +void processInput(GLFWwindow *window); +unsigned int loadTexture(const char *path); void renderSphere(); - // camera Camera camera(glm::vec3(0.0f, 0.0f, 3.0f)); +float lastX = 800.0f / 2.0; +float lastY = 600.0 / 2.0; +bool firstMouse = true; -// timing -GLfloat deltaTime = 0.0f; -GLfloat lastFrame = 0.0f; +float deltaTime = 0.0f; +float lastFrame = 0.0f; +// settings +const unsigned int SCR_WIDTH = 1280; +const unsigned int SCR_HEIGHT = 720; -// The MAIN function, from here we start our application and run our Game loop int main() { - // Init GLFW + // glfw: initialize and configure + // ------------------------------ glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_SAMPLES, 4); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_SAMPLES, 32); - glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); - GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", nullptr, nullptr); // Windowed + // glfw window creation + // -------------------- + GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL); glfwMakeContextCurrent(window); - - // Set the required callback functions - glfwSetKeyCallback(window, key_callback); + if (window == NULL) + { + 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); - // Options + // tell GLFW to capture our mouse glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); - // Initialize GLEW to setup the OpenGL Function pointers - glewExperimental = GL_TRUE; - glewInit(); + // glad: load all OpenGL function pointers + // --------------------------------------- + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "Failed to initialize GLAD" << std::endl; + return -1; + } - // Define the viewport dimensions - glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT); - - // Setup some OpenGL options + // configure global opengl state + // ----------------------------- glEnable(GL_DEPTH_TEST); - // load material textures - GLuint albedo = loadTexture(FileSystem::getPath("resources/textures/pbr/rusted_iron/albedo.png").c_str()); - GLuint normal = loadTexture(FileSystem::getPath("resources/textures/pbr/rusted_iron/normal.png").c_str()); - GLuint metallic = loadTexture(FileSystem::getPath("resources/textures/pbr/rusted_iron/metallic.png").c_str()); - GLuint roughness = loadTexture(FileSystem::getPath("resources/textures/pbr/rusted_iron/roughness.png").c_str()); - GLuint ao = loadTexture(FileSystem::getPath("resources/textures/pbr/rusted_iron/ao.png").c_str()); + // build and compile shaders + // ------------------------- + Shader shader("1.2.pbr.vs", "1.2.pbr.fs"); - // Setup and compile our shaders - Shader shader("pbr.vs", "pbr.frag"); + shader.use(); + shader.setInt("albedoMap", 0); + shader.setInt("normalMap", 1); + shader.setInt("metallicMap", 2); + shader.setInt("roughnessMap", 3); + shader.setInt("aoMap", 4); - // set material texture uniforms - shader.Use(); - glUniform1i(glGetUniformLocation(shader.Program, "albedoMap"), 0); - glUniform1i(glGetUniformLocation(shader.Program, "normalMap"), 1); - glUniform1i(glGetUniformLocation(shader.Program, "metallicMap"), 2); - glUniform1i(glGetUniformLocation(shader.Program, "roughnessMap"), 3); - glUniform1i(glGetUniformLocation(shader.Program, "aoMap"), 4); - - // projection setup - glm::mat4 projection = glm::perspective(camera.Zoom, (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f); - glUniformMatrix4fv(glGetUniformLocation(shader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); + // load PBR material textures + // -------------------------- + unsigned int albedo = loadTexture(FileSystem::getPath("resources/textures/pbr/rusted_iron/albedo.png").c_str()); + unsigned int normal = loadTexture(FileSystem::getPath("resources/textures/pbr/rusted_iron/normal.png").c_str()); + unsigned int metallic = loadTexture(FileSystem::getPath("resources/textures/pbr/rusted_iron/metallic.png").c_str()); + unsigned int roughness = loadTexture(FileSystem::getPath("resources/textures/pbr/rusted_iron/roughness.png").c_str()); + unsigned int ao = loadTexture(FileSystem::getPath("resources/textures/pbr/rusted_iron/ao.png").c_str()); // lights + // ------ glm::vec3 lightPositions[] = { - glm::vec3(0.0, 0.0f, 10.0f), + glm::vec3(0.0f, 0.0f, 10.0f), }; glm::vec3 lightColors[] = { - glm::vec3(150.0f, 150.0f, 150.0f) + glm::vec3(150.0f, 150.0f, 150.0f), }; - int nrRows = 7; + int nrRows = 7; int nrColumns = 7; float spacing = 2.5; + // initialize static shader uniforms before rendering + // -------------------------------------------------- + glm::mat4 projection = glm::perspective(camera.Zoom, (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f); + shader.use(); + shader.setMat4("projection", projection); - // Game loop + // render loop + // ----------- while (!glfwWindowShouldClose(window)) { - // set frame time - GLfloat currentFrame = glfwGetTime(); + // per-frame time logic + // -------------------- + float currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; - // check and call events - glfwPollEvents(); - Do_Movement(); + // input + // ----- + processInput(window); - // clear the colorbuffer + // render + // ------ glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // configure view matrix - shader.Use(); + shader.use(); glm::mat4 view = camera.GetViewMatrix(); - glUniformMatrix4fv(glGetUniformLocation(shader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view)); + shader.setMat4("view", view); + shader.setVec3("camPos", camera.Position); + shader.setFloat("exposure", 1.0f); - // setup relevant shader uniforms - glUniform3fv(glGetUniformLocation(shader.Program, "camPos"), 1, &camera.Position[0]); - - // set material glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, albedo); glActiveTexture(GL_TEXTURE1); @@ -146,17 +147,17 @@ int main() // render rows*column number of spheres with material properties defined by textures (they all have the same material properties) glm::mat4 model; - for (int row = 0; row < nrRows; ++row) + for (unsigned int row = 0; row < nrRows; ++row) { - for (int col = 0; col < nrColumns; ++col) + for (unsigned int col = 0; col < nrColumns; ++col) { model = glm::mat4(); model = glm::translate(model, glm::vec3( - (float)(col - (nrColumns / 2)) * spacing, - (float)(row - (nrRows / 2)) * spacing, + (float)(col - (nrColumns / 2)) * spacing, + (float)(row - (nrRows / 2)) * spacing, 0.0f )); - glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); + shader.setMat4("model", model); renderSphere(); } } @@ -168,26 +169,85 @@ int main() { glm::vec3 newPos = lightPositions[i] + glm::vec3(sin(glfwGetTime() * 5.0) * 5.0, 0.0, 0.0); newPos = lightPositions[i]; - glUniform3fv(glGetUniformLocation(shader.Program, ("lightPositions[" + std::to_string(i) + "]").c_str()), 1, &newPos[0]); - glUniform3fv(glGetUniformLocation(shader.Program, ("lightColors[" + std::to_string(i) + "]").c_str()), 1, &lightColors[i][0]); + shader.setVec3("lightPositions[" + std::to_string(i) + "]", newPos); + shader.setVec3("lightColors[" + std::to_string(i) + "]", lightColors[i]); model = glm::mat4(); model = glm::translate(model, newPos); model = glm::scale(model, glm::vec3(0.5f)); - glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); + shader.setMat4("model", model); renderSphere(); } - // Swap the buffers + // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) + // ------------------------------------------------------------------------------- glfwSwapBuffers(window); + glfwPollEvents(); } + // glfw: terminate, clearing all previously allocated GLFW resources. + // ------------------------------------------------------------------ glfwTerminate(); return 0; } +// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly +// --------------------------------------------------------------------------------------------------------- +void processInput(GLFWwindow *window) +{ + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); -// renders (and builds if necessary) a sphere + 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; + } + + float xoffset = xpos - lastX; + float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top + + lastX = xpos; + lastY = ypos; + + 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); +} + +// renders (and builds at first invocation) a sphere +// ------------------------------------------------- unsigned int sphereVAO = 0; unsigned int indexCount; void renderSphere() @@ -214,7 +274,7 @@ void renderSphere() { float xSegment = (float)x / (float)X_SEGMENTS; float ySegment = (float)y / (float)Y_SEGMENTS; - float xPos = std::cos(xSegment * 2.0f * PI) * std::sin(ySegment * PI); + float xPos = std::cos(xSegment * 2.0f * PI) * std::sin(ySegment * PI); float yPos = std::cos(ySegment * PI); float zPos = std::sin(xSegment * 2.0f * PI) * std::sin(ySegment * PI); @@ -272,102 +332,52 @@ void renderSphere() glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW); float stride = (3 + 2 + 3) * sizeof(float); glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, (void*)0); glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)(3 * sizeof(float))); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (void*)(3 * sizeof(float))); glEnableVertexAttribArray(2); - glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)(5 * sizeof(float))); + glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, stride, (void*)(5 * sizeof(float))); } glBindVertexArray(sphereVAO); glDrawElements(GL_TRIANGLE_STRIP, indexCount, GL_UNSIGNED_INT, 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 const * path) +// utility function for loading a 2D texture from file +// --------------------------------------------------- +unsigned int loadTexture(char const * path) { - //Generate texture ID and load texture data - GLuint textureID; + unsigned int 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); - // 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); + int width, height, nrComponents; + unsigned char *data = stbi_load(path, &width, &height, &nrComponents, 0); + if (data) + { + GLenum format; + if (nrComponents == 1) + format = GL_RED; + else if (nrComponents == 3) + format = GL_RGB; + else if (nrComponents == 4) + format = GL_RGBA; + + glBindTexture(GL_TEXTURE_2D, textureID); + glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + + 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); + + stbi_image_free(data); + } + else + { + std::cout << "Texture failed to load at path: " << path << std::endl; + stbi_image_free(data); + } + 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); -} - -// 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 >= 0 && key <= 1024) - { - if (action == GLFW_PRESS) - keys[key] = true; - else if (action == GLFW_RELEASE) - { - keys[key] = false; - keysPressed[key] = false; - } - } -} - -GLfloat lastX = 400, lastY = 300; -bool firstMouse = true; -// Moves/alters the camera positions based on user input -void mouse_callback(GLFWwindow* window, double xpos, double ypos) -{ - if (firstMouse) - { - lastX = xpos; - lastY = ypos; - firstMouse = false; - } - - GLfloat xoffset = xpos - lastX; - 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/6.pbr/2.2.2.ibl_specular_textured/ibl_specular_textured.cpp b/src/6.pbr/2.2.2.ibl_specular_textured/ibl_specular_textured.cpp index 9770d7e..f1de453 100644 --- a/src/6.pbr/2.2.2.ibl_specular_textured/ibl_specular_textured.cpp +++ b/src/6.pbr/2.2.2.ibl_specular_textured/ibl_specular_textured.cpp @@ -42,6 +42,7 @@ int main() glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_SAMPLES, 4); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // glfw window creation @@ -140,9 +141,9 @@ int main() // ------ glm::vec3 lightPositions[] = { glm::vec3(-10.0f, 10.0f, 10.0f), - glm::vec3(10.0f, 10.0f, 10.0f), + glm::vec3( 10.0f, 10.0f, 10.0f), glm::vec3(-10.0f, -10.0f, 10.0f), - glm::vec3(10.0f, -10.0f, 10.0f), + glm::vec3( 10.0f, -10.0f, 10.0f), }; glm::vec3 lightColors[] = { glm::vec3(300.0f, 300.0f, 300.0f), @@ -366,8 +367,10 @@ int main() backgroundShader.use(); backgroundShader.setMat4("projection", projection); - // then before rendering, configure the viewport to the actual screen dimensions - glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT); + // then before rendering, configure the viewport to the original framebuffer's screen dimensions + int scrWidth, scrHeight; + glfwGetFramebufferSize(window, &scrWidth, &scrHeight); + glViewport(0, 0, scrWidth, scrHeight); // render loop // ----------- @@ -388,7 +391,7 @@ int main() glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // render scene, supplying the convoluted irradiance map to the final shader. + // render scene, supplying the convoluted irradiance map to the final shader. // ------------------------------------------------------------------------------------------ pbrShader.use(); glm::mat4 model;