#include #include #include #include #include #include #include #include #include #include #include #include #include #include "Shader.h" #include "Camera.h" #include "Framebuffer.h" #include "Model.h" #include "DebugColors.h" #include "config.h" // in cmake build directory (need to run configure.sh first) #if _WIN32 #include #endif #define WINDOW_NAME "6. Parallax Mapping" #define TEXTURES_DIR REPO_ROOT "/textures/" #define MODELS_DIR REPO_ROOT "/models/" #define SHADERS_DIR SOURCE_DIR "/shaders/" #define _IsUnused __attribute__((__unused__)) // linux only using namespace std; typedef unsigned int uint; // Global Constants // ... // Global Variables GLFWwindow* window; int WINDOW_WIDTH = 800; int WINDOW_HEIGHT = 600; Camera myCamera(glm::vec3(0.0f, 0.0f, 3.0f)); float deltaTime = 0.0f; float lastFrame = 0.0f; float lastX = 400; float lastY = 300; bool firstmouse = true; /* pointer to Framebuffer object that is used for screenshot */ /* if NULL default framebuffer is used */ Framebuffer *screenshot_FBO_ptr = NULL; uint8_t init(void); void framebuffersize_callback(GLFWwindow* window, int width, int height); void mouse_callback(GLFWwindow* window, double xpos, double ypos); void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); void proccessInput(GLFWwindow* window); unsigned int load_texture(const char* path, bool flip = true, bool sRGB = true, GLint wrapS = GL_REPEAT, GLint wrapT = GL_REPEAT); unsigned int load_cubemap(vector faces); void draw_cube(void); void draw_floor(void); void draw_quad(void); void draw_scene(const Shader* shader, bool lightCube); Shader* shader = NULL; Shader* quadShader = NULL; Shader* basicShader = NULL; glm::vec3 lightPos(0.0f); glm::vec3 lightColor(1.0f, 1.0f, 1.0f); bool cullFaces = false; bool normalMapping = false; bool parallaxMapping = false; GLint polygonMode = GL_FILL; int main(int argc, char** argv) { #if _WIN32 SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING); #endif if (init() != 0) return -1; shader = new Shader(SHADERS_DIR "shader.vert", SHADERS_DIR "shader.frag"); quadShader = new Shader(SHADERS_DIR "quadShader.vert", SHADERS_DIR "quadShader.frag"); basicShader = new Shader(SHADERS_DIR "basicShader.vert", SHADERS_DIR "basicShader.frag"); if (!shader->Program || !quadShader->Program || !basicShader->Program) { std::cerr << DC_ERROR " Could not create shader programs!" << std::endl; std::cerr << DC_INFO " Exiting...\n"; return -2; } MSFramebuffer fbOffScreen(WINDOW_WIDTH, WINDOW_HEIGHT, 4); if (fbOffScreen.ID == 0) return -1; screenshot_FBO_ptr = &fbOffScreen; glEnable(GL_DEPTH_TEST); cullFaces = false; //glEnable(GL_MULTISAMPLE); /* ------------------ MAIN loop ------------------ */ while (!glfwWindowShouldClose(window)) { float currentFrame = (float)glfwGetTime(); deltaTime = currentFrame - lastFrame; // cas jak dlouho trval posledni frame lastFrame = currentFrame; // cas kdy zacal tento frame // input ... proccessInput(window); // rendering commands here ... glEnable(GL_DEPTH_TEST); if (cullFaces) glEnable(GL_CULL_FACE); // 1. Render pass: render to fbOffscreen framebuffer glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); glPolygonMode(GL_FRONT_AND_BACK, polygonMode); fbOffScreen.Use(); fbOffScreen.clearBuffers(0.006f, 0.006f, 0.006f, 1.0f); shader->Use(); draw_scene(shader, false); // 2. Render pass: render quad on screen glBindFramebuffer(GL_FRAMEBUFFER, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); quadShader->Use(); quadShader->setInt("texture0", 0); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, fbOffScreen.getColorBuffer()); draw_quad(); //glDisable(GL_FRAMEBUFFER_SRGB); // check and calls events and swap the buffers glfwSwapBuffers(window); glfwPollEvents(); } glfwTerminate(); delete(shader); delete(quadShader); delete(basicShader); return 0; } uint8_t init(void) { // init of glfw window glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_NAME, NULL, NULL); if (window == NULL) { cerr << DC_ERROR " Failed to create glfw window" << endl; glfwTerminate(); return 1; } glfwMakeContextCurrent(window); glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); // init of GLAD if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { cerr << DC_ERROR " Failed to initialize GLAD" << endl; } glfwSetFramebufferSizeCallback(window, framebuffersize_callback); glfwSetCursorPosCallback(window, mouse_callback); glfwSetScrollCallback(window, scroll_callback); return 0; } void framebuffersize_callback(GLFWwindow* window, int width, int height) { glViewport(0, 0, width, height); WINDOW_HEIGHT = height; WINDOW_WIDTH = width; } void proccessInput(GLFWwindow* window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) // Escape glfwSetWindowShouldClose(window, true); if (glfwGetKey(window, GLFW_KEY_F1) == GLFW_PRESS) // F1 { if (polygonMode != GL_FILL) { std::cout << DC_INFO << " Polygon mode: " << DC_YELLOW << "fill" << DC_DEFAULT << "\n"; polygonMode = GL_FILL; } } else if (glfwGetKey(window, GLFW_KEY_F2) == GLFW_PRESS) // F2 { if (polygonMode != GL_LINE) { std::cout << DC_INFO << " Polygon mode: " << DC_YELLOW << "line" << DC_DEFAULT << "\n"; polygonMode = GL_LINE; } } if (glfwGetKey(window, GLFW_KEY_F3) == GLFW_PRESS) // F3 { std::string path; if (screenshot_FBO_ptr == NULL) path = Framebuffer::screenshot_defaultFBO(WINDOW_WIDTH, WINDOW_HEIGHT); else path = screenshot_FBO_ptr->screenshot(); std::this_thread::sleep_for(std::chrono::seconds(1)); std::cout << DC_INFO << " Screenshot saved to '" DC_MAGNETA << path << DC_DEFAULT "'\n"; } //if (glfwGetKey(window, GLFW_KEY_F4) == GLFW_PRESS); // F4 if (glfwGetKey(window, GLFW_KEY_1) == GLFW_PRESS) // 1 { if (!normalMapping) { std::cout << DC_INFO << " Normal mapping: " << DC_GREEN << "on" << DC_DEFAULT << "\n"; normalMapping = true; } } else if (glfwGetKey(window, GLFW_KEY_2) == GLFW_PRESS) // 2 { if (normalMapping) { std::cout << DC_INFO << " Normal mapping: " << DC_RED << "off" << DC_DEFAULT << "\n"; normalMapping = false; } } if (glfwGetKey(window, GLFW_KEY_3) == GLFW_PRESS) { if (!parallaxMapping) { std::cout << DC_INFO << " Parallax mapping: " << DC_GREEN << "on" << DC_DEFAULT << "\n"; parallaxMapping = true; } } else if (glfwGetKey(window, GLFW_KEY_4) == GLFW_PRESS) { if (parallaxMapping) { std::cout << DC_INFO << " Parallax mapping: " << DC_RED << "off" << DC_DEFAULT << "\n"; parallaxMapping = false; } } /* -------------------- Movement -------------------- */ if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) // w myCamera.ProccessKeyboard(CAM_FORWARD, deltaTime); if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) // S myCamera.ProccessKeyboard(CAM_BACKWARD, deltaTime); if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) // D myCamera.ProccessKeyboard(CAM_RIGHT, deltaTime); if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) // A myCamera.ProccessKeyboard(CAM_LEFT, deltaTime); if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) // Left-shift myCamera.ProccessKeyboard(CAM_DOWN, deltaTime); if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) // Space myCamera.ProccessKeyboard(CAM_UP, deltaTime); } void mouse_callback(GLFWwindow* window, double xpos, double ypos) { if (firstmouse) { lastX = (float)xpos; lastY = (float)ypos; firstmouse = false; } float xoffset = (float)xpos - lastX; float yoffset = lastY - (float)ypos; lastX = (float)xpos; lastY = (float)ypos; myCamera.ProccessMouse(xoffset, yoffset); } void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) { myCamera.ProccessScroll((float)yoffset); } unsigned int load_texture(const char* path, bool flip, bool sRGB, GLint wrapS, GLint wrapT) { unsigned int texture = 0; int width, height, nrChannels, format, intFormat; stbi_set_flip_vertically_on_load(flip); unsigned char* data = stbi_load(path, &width, &height, &nrChannels, 0); // load image to the array of bytes (char = 1 byte) switch (nrChannels) { case 4: format = GL_RGBA; if (sRGB) intFormat = GL_SRGB_ALPHA; else intFormat = GL_RGBA; break; case 3: format = GL_RGB; if (sRGB) intFormat = GL_SRGB; else intFormat = GL_RGB; break; case 2: format = intFormat = GL_RED; break; default: format = intFormat = GL_RGB; break; } if (data) // data != NULL { glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, intFormat, width, height, 0, format, GL_UNSIGNED_BYTE, data); // generates texture glGenerateMipmap(GL_TEXTURE_2D); } else { cerr << DC_WARNING " Could not load texture '" << path << "'\n"; } stbi_image_free(data); glBindTexture(GL_TEXTURE_2D, 0); return texture; } unsigned int load_cubemap(vector faces) { unsigned int textureID; glGenTextures(1, &textureID); glBindTexture(GL_TEXTURE_CUBE_MAP, textureID); int width, height, nrChannels, format; for (size_t i = 0; i < faces.size(); i++) { unsigned char* data = stbi_load(faces[i].c_str(), &width, &height, &nrChannels, 0); switch (nrChannels) { case 4: format = GL_RGBA; break; case 3: format = GL_RGB; break; case 2: format = GL_RED; break; default: format = GL_RGB; break; } if (data) { glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + static_cast(i), 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data); } else { std::cerr << DC_INFO " Failed to load cubemap texture at " << faces[i] << std::endl; } stbi_image_free(data); }; glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); return textureID; } unsigned int cubeVAO = 0, cubeVBO = 0; void draw_cube(void) { if (cubeVBO == 0 || cubeVAO == 0) { float cubeVertices[] = { // 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); glBindVertexArray(cubeVAO); glBindBuffer(GL_ARRAY_BUFFER, cubeVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), cubeVertices, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (const void*)0); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (const void*)(6 * sizeof(float))); glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (const void*)(3 * sizeof(float))); for (int i = 0; i < 3; i++) glEnableVertexAttribArray(i); glBindVertexArray(0); } glBindVertexArray(cubeVAO); glDrawArrays(GL_TRIANGLES, 0, 36); glBindVertexArray(0); } unsigned int floorVAO = 0, floorVBO = 0; void draw_floor(void) { if (floorVAO == 0 || floorVBO == 0) { float floorVertices[] = { // positions // normals // texcoords 25.0f, -0.5f, 25.0f, 0.0f, 1.0f, 0.0f, 25.0f, 0.0f, -25.0f, -0.5f, 25.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, -25.0f, -0.5f, -25.0f, 0.0f, 1.0f, 0.0f, 0.0f, 25.0f, 25.0f, -0.5f, 25.0f, 0.0f, 1.0f, 0.0f, 25.0f, 0.0f, -25.0f, -0.5f, -25.0f, 0.0f, 1.0f, 0.0f, 0.0f, 25.0f, 25.0f, -0.5f, -25.0f, 0.0f, 1.0f, 0.0f, 25.0f, 25.0f }; glGenVertexArrays(1, &floorVAO); glGenBuffers(1, &floorVBO); glBindVertexArray(floorVAO); glBindBuffer(GL_ARRAY_BUFFER, floorVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(floorVertices), floorVertices, GL_STATIC_DRAW); glEnableVertexAttribArray(0); // aPos glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (const void*)0); glEnableVertexAttribArray(1); // aTexCoord glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (const void*)(6 * sizeof(float))); glEnableVertexAttribArray(2); // aNormal glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (const void*)(3 * sizeof(float))); glBindVertexArray(0); } glBindVertexArray(floorVAO); glDrawArrays(GL_TRIANGLES, 0, 6); glBindVertexArray(0); } unsigned int quadVAO = 0, quadVBO = 0; void draw_quad(void) { if (quadVAO == 0 || quadVBO == 0) { //Tangent space calculations glm::vec3 pos1(-1.0f, 1.0f, 0.0f); glm::vec3 pos2(-1.0f, -1.0f, 0.0f); glm::vec3 pos3(1.0f, -1.0f, 0.0f); glm::vec3 pos4(1.0f, 1.0f, 0.0f); // texture coordinates glm::vec2 uv1(0.0f, 1.0f); glm::vec2 uv2(0.0f, 0.0f); glm::vec2 uv3(1.0f, 0.0f); glm::vec2 uv4(1.0f, 1.0f); // normal vector glm::vec3 nm(0.0f, 0.0f, 1.0f); // calculate tangent/bitangent vectors of both triangles glm::vec3 tangent1, bitangent1; glm::vec3 tangent2, bitangent2; // triangle 1 // ---------- glm::vec3 edge1 = pos2 - pos1; glm::vec3 edge2 = pos3 - pos1; glm::vec2 deltaUV1 = uv2 - uv1; glm::vec2 deltaUV2 = uv3 - uv1; float f = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV2.x * deltaUV1.y); tangent1.x = f * (deltaUV2.y * edge1.x - deltaUV1.y * edge2.x); tangent1.y = f * (deltaUV2.y * edge1.y - deltaUV1.y * edge2.y); tangent1.z = f * (deltaUV2.y * edge1.z - deltaUV1.y * edge2.z); bitangent1.x = f * (-deltaUV2.x * edge1.x + deltaUV1.x * edge2.x); bitangent1.y = f * (-deltaUV2.x * edge1.y + deltaUV1.x * edge2.y); bitangent1.z = f * (-deltaUV2.x * edge1.z + deltaUV1.x * edge2.z); // triangle 2 // ---------- edge1 = pos3 - pos1; edge2 = pos4 - pos1; deltaUV1 = uv3 - uv1; deltaUV2 = uv4 - uv1; f = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV2.x * deltaUV1.y); tangent2.x = f * (deltaUV2.y * edge1.x - deltaUV1.y * edge2.x); tangent2.y = f * (deltaUV2.y * edge1.y - deltaUV1.y * edge2.y); tangent2.z = f * (deltaUV2.y * edge1.z - deltaUV1.y * edge2.z); bitangent2.x = f * (-deltaUV2.x * edge1.x + deltaUV1.x * edge2.x); bitangent2.y = f * (-deltaUV2.x * edge1.y + deltaUV1.x * edge2.y); bitangent2.z = f * (-deltaUV2.x * edge1.z + deltaUV1.x * edge2.z); float quadVertices[] = { // positions // normal // texcoords // tangent // bitangent pos1.x, pos1.y, pos1.z, nm.x, nm.y, nm.z, uv1.x, uv1.y, tangent1.x, tangent1.y, tangent1.z, bitangent1.x, bitangent1.y, bitangent1.z, pos2.x, pos2.y, pos2.z, nm.x, nm.y, nm.z, uv2.x, uv2.y, tangent1.x, tangent1.y, tangent1.z, bitangent1.x, bitangent1.y, bitangent1.z, pos3.x, pos3.y, pos3.z, nm.x, nm.y, nm.z, uv3.x, uv3.y, tangent1.x, tangent1.y, tangent1.z, bitangent1.x, bitangent1.y, bitangent1.z, pos1.x, pos1.y, pos1.z, nm.x, nm.y, nm.z, uv1.x, uv1.y, tangent2.x, tangent2.y, tangent2.z, bitangent2.x, bitangent2.y, bitangent2.z, pos3.x, pos3.y, pos3.z, nm.x, nm.y, nm.z, uv3.x, uv3.y, tangent2.x, tangent2.y, tangent2.z, bitangent2.x, bitangent2.y, bitangent2.z, pos4.x, pos4.y, pos4.z, nm.x, nm.y, nm.z, uv4.x, uv4.y, tangent2.x, tangent2.y, tangent2.z, bitangent2.x, bitangent2.y, bitangent2.z }; // configure 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); // Vertex positions glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(float), (void*)0); glEnableVertexAttribArray(1); // Vertex normals glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(float), (void*)(3 * sizeof(float))); glEnableVertexAttribArray(2); // Vertex texture coordinates glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 14 * sizeof(float), (void*)(6 * sizeof(float))); glEnableVertexAttribArray(3); // Vertex tangent glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(float), (void*)(8 * sizeof(float))); glEnableVertexAttribArray(4); // Vertex bitangent glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(float), (void*)(11 * sizeof(float))); } glBindVertexArray(quadVAO); glDrawArrays(GL_TRIANGLES, 0, 6); glBindVertexArray(0); } unsigned int brick_texture = 0, brick_texture_normal = 0, brick_texture_height = 0; void draw_scene(const Shader* shader, bool lightCube) { if (brick_texture == 0) // flipV sRGB brick_texture = load_texture(TEXTURES_DIR "brickwall2/brickwall2.jpg", true, true); if (brick_texture_normal == 0) brick_texture_normal = load_texture(TEXTURES_DIR "brickwall2/brickwall2_normal.jpg", true, false); if (brick_texture_height == 0) brick_texture_height = load_texture(TEXTURES_DIR "brickwall2/brickwall2_height.jpg", true, false); if (!brick_texture || !brick_texture_normal || !brick_texture_height) { std::cout << DC_ERROR " Could not load needed textures. Exiting..." DC_DEFAULT << std::endl; exit(EXIT_FAILURE); } glm::mat4 model(1.0f); glm::mat4 view = myCamera.getViewMatrix(); glm::mat4 projection = glm::perspective(glm::radians(myCamera.FOV), WINDOW_WIDTH / (float)WINDOW_HEIGHT, 0.1f, 300.0f); shader->Use(); shader->setMat4("projection", projection); shader->setMat4("view", view); // Lighting float tim = (float)glfwGetTime(); lightPos = glm::vec3(0.0f, 0.0f, 1.5f); shader->setVec3("light.position", lightPos); shader->setVec3("viewPos", myCamera.Position); shader->setVec3("light.ambient", glm::vec3(0.005f)); shader->setVec3("light.diffuse", 0.9f * lightColor); shader->setVec3("light.specular", 1.0f * lightColor); shader->setInt("material.texture_diffuse0", 0); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, brick_texture); shader->setInt("material.texture_normal0", 1); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, brick_texture_normal); shader->setInt("material.texture_height0", 2); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, brick_texture_height); if (cullFaces) glEnable(GL_CULL_FACE); model = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -0.5f)); model = glm::scale(model, glm::vec3(1.0f)); //model = glm::rotate(model, tim * 0.5f, glm::vec3(0.0f, 0.0f, 1.0f)); shader->setMat4("model", model); shader->setMat3("normalMatrix", glm::transpose(glm::inverse(model))); shader->setBool("normalMapping", normalMapping); shader->setBool("parallaxMapping", parallaxMapping); shader->setFloat("height_scale", 0.15f); draw_quad(); if (lightCube) { basicShader->Use(); model = glm::translate(glm::mat4(1.0f), lightPos); model = glm::scale(model, glm::vec3(0.05f)); basicShader->setMat4("PVM", projection * view * model); basicShader->setVec3("Color", lightColor); draw_cube(); } }