int main(int argc, char* argv[]) { if(argc < 5) { std::cout << "Usage: " << argv[0] << " originalMeshOBJ flattenedMeshOBJ textureImage flattenedImage" << std::endl; return EXIT_FAILURE; } char* originalMeshName = argv[1]; char* flattenedMeshName = argv[2]; char* textureImageName = argv[3]; char* flattenedImageName = argv[4]; cv::Mat textureImage = cv::imread(textureImageName); int width, height; width = textureImage.cols; height = textureImage.rows; textureImage.release(); // std::cout << "Width: " << width << std::endl // << "Height: " << height << std::endl; GLFWwindow* window; GLinit(&window, width, height); // int maxSize; // const GLubyte* version; // glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize); // std::cout << "Max texture size: " << maxSize << std::endl; // version = glGetString(GL_VERSION); // std::cout << "Version: " << version << std::endl; // Create Vertex Array Object GLuint vao; glGenVertexArrays(1, &vao); glBindVertexArray(vao); // Create a Vertex Buffer Object and copy the vertex data to it GLuint vbo; glGenBuffers(1, &vbo); GLfloat vertices[] = { // coord, color, texcoord -1.0f, 1.0f, 0.0f, 0.0f, // Top-left 1.0f, 1.0f, 1.0f, 0.0f, // Top-right 1.0f, -1.0f, 1.0f, 1.0f, // Bottom-right -1.0f, -1.0f, 0.0f, 1.0f // Bottom-left }; glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); GLuint ebo; glGenBuffers(1, &ebo); GLuint elements[] = { 0, 1, 2, 2, 3, 0 }; glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW); GLuint frameBuffer; glGenFramebuffers(1, &frameBuffer); glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer); GLuint texColorBuffer; glGenTextures(1, &texColorBuffer); glBindTexture(GL_TEXTURE_2D, texColorBuffer); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texColorBuffer, 0); GLuint vertexShader, fragmentShader, shaderProgram; createShaderProgram(vertexSource, fragmentSource, vertexShader, fragmentShader, shaderProgram); specifyScreenVertexAttributes(shaderProgram); cv::Mat img; img.create(height, width, CV_8UC3); GLuint red, blue, green; loadTextures(textureImageName, red, blue, green); // Set texture background color // float color[] = { 1.0f, 0.0f, 0.0f, 1.0f }; // glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color); // Clear the screen to black glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); // Draw glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); glTexToCVmat(img, width, height); // glDeleteTextures(1, &tex); cv::imwrite(flattenedImageName, img); // Swap buffers glfwSwapBuffers(window); glDeleteProgram(shaderProgram); glDeleteShader(fragmentShader); glDeleteShader(vertexShader); glDeleteBuffers(1, &ebo); glDeleteBuffers(1, &vbo); glDeleteVertexArrays(1, &vao); glDeleteFramebuffers(1, &frameBuffer); glfwTerminate(); return 0; }
int main() { GLFWwindow* window; const int WIDTH = 800, HEIGHT = 600; char* WINDOW_NAME = "OpenGL - basic stuff"; initContext(); window = glfwCreateWindow(WIDTH, HEIGHT, WINDOW_NAME, nullptr, nullptr); glfwMakeContextCurrent(window); glfwSetKeyCallback(window, key_callback); glfwSetCursorPosCallback(window, mouse_callback); glfwSetScrollCallback(window, scroll_callback); //glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); initGLEW(); // Create VAOs GLuint vaoCube, vaoQuad, vaoLight; glGenVertexArrays(1, &vaoCube); glGenVertexArrays(1, &vaoQuad); glGenVertexArrays(1, &vaoLight); // Load vertex data GLuint vboCube, vboQuad; glGenBuffers(1, &vboCube); glGenBuffers(1, &vboQuad); glBindBuffer(GL_ARRAY_BUFFER, vboCube); glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), cubeVertices, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, vboQuad); glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), quadVertices, GL_STATIC_DRAW); // Create shader programs GLuint sceneVertexShader, sceneFragmentShader, sceneShaderProgram; createShaderProgram(readShaderFile("basic.vert"), readShaderFile("basic.frag"), sceneVertexShader, sceneFragmentShader, sceneShaderProgram); GLuint screenVertexShader, screenFragmentShader, screenShaderProgram; createShaderProgram(readShaderFile("basic_screen.vert"), readShaderFile("basic_screen.frag"), screenVertexShader, screenFragmentShader, screenShaderProgram); // Specify the layout of the vertex data glBindVertexArray(vaoCube); glBindBuffer(GL_ARRAY_BUFFER, vboCube); specifySceneVertexAttributes(sceneShaderProgram); glBindVertexArray(vaoQuad); glBindBuffer(GL_ARRAY_BUFFER, vboQuad); specifyScreenVertexAttributes(screenShaderProgram); glBindVertexArray(vaoLight); glBindBuffer(GL_ARRAY_BUFFER, vboCube); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0); // Note that we skip over the other data in our buffer object (we don't need the normals/textures, only positions). glEnableVertexAttribArray(0); glBindVertexArray(0); // Load textures GLuint diffuseMap = loadTextureMap("container2.png"); GLuint specularMap = loadTextureMap("container2_specular.png"); glUseProgram(sceneShaderProgram); glUniform1i(glGetUniformLocation(sceneShaderProgram, "texKitten"), 0); glUniform1i(glGetUniformLocation(sceneShaderProgram, "texPuppy"), 1); glUseProgram(screenShaderProgram); glUniform1i(glGetUniformLocation(screenShaderProgram, "texFramebuffer"), 0); GLint uniModel = glGetUniformLocation(sceneShaderProgram, "model"); // Create frame buffer GLuint frameBuffer; glGenFramebuffers(1, &frameBuffer); glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer); // Create texture to hold color buffer GLuint texColorBuffer; glGenTextures(1, &texColorBuffer); glBindTexture(GL_TEXTURE_2D, texColorBuffer); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 800, 600, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texColorBuffer, 0); // Create Renderbuffer Object to hold depth and stencil buffers GLuint rboDepthStencil; glGenRenderbuffers(1, &rboDepthStencil); glBindRenderbuffer(GL_RENDERBUFFER, rboDepthStencil); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 800, 600); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rboDepthStencil); glm::mat4 viewMatrix = glm::lookAt( glm::vec3(2.5f, 2.5f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)); GLint uniView = glGetUniformLocation(sceneShaderProgram, "view"); glUniformMatrix4fv(uniView, 1, GL_FALSE, glm::value_ptr(viewMatrix)); glm::mat4 projMatrix = glm::perspective(camera.Zoom, (float)WIDTH / (float)HEIGHT, 0.1f, 100.0f); GLint uniProj = glGetUniformLocation(sceneShaderProgram, "proj"); glUniformMatrix4fv(uniProj, 1, GL_FALSE, glm::value_ptr(projMatrix)); GLint uniColor = glGetUniformLocation(sceneShaderProgram, "overrideColor"); GLint timer = glGetUniformLocation(sceneShaderProgram, "timer"); while (!glfwWindowShouldClose(window)) { GLfloat currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; glfwPollEvents(); Do_Movement(); // Bind our framebuffer and draw 3D scene(spinning cube) glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer); glBindVertexArray(vaoCube); glEnable(GL_DEPTH_TEST); glUseProgram(sceneShaderProgram); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texKitten); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, texPuppy); // Clear the screen to white glClearColor(.2f, .2f, .2f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); GLfloat time = (GLfloat)glfwGetTime(); glUniform1f(timer, time); time = 0; viewMatrix = camera.GetViewMatrix(); projMatrix = glm::perspective(camera.Zoom, (float)WIDTH / (float)HEIGHT, 0.1f, 100.0f); glm::mat4 modelMatrix; modelMatrix = glm::rotate(modelMatrix, time * 100, glm::vec3(0.0f, 0.0f, 1.0f)); glUniformMatrix4fv(uniModel, 1, GL_FALSE, glm::value_ptr(modelMatrix)); glUniformMatrix4fv(uniView, 1, GL_FALSE, glm::value_ptr(viewMatrix)); glUniformMatrix4fv(uniProj, 1, GL_FALSE, glm::value_ptr(projMatrix)); // CUBE glDrawArrays(GL_TRIANGLES, 0, 36); glEnable(GL_STENCIL_TEST); // FLOOR /*glStencilFunc(GL_ALWAYS, 1, 0xFF); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); glStencilMask(0xFF); glDepthMask(GL_FALSE); glClear(GL_STENCIL_BUFFER_BIT); glDrawArrays(GL_TRIANGLES, 36, 6); // CUBE REFLECTION glStencilFunc(GL_EQUAL, 1, 0xFF); glStencilMask(0x00); glDepthMask(GL_TRUE); modelMatrix = glm::scale(glm::translate(modelMatrix, glm::vec3(0, 0, -1)), glm::vec3(1, 1, -1)); glUniformMatrix4fv(uniModel, 1, GL_FALSE, glm::value_ptr(modelMatrix)); glUniform3f(uniColor, 0.3f, 0.3f, 0.3f); glUniform3f(uniColor, 0.3f, 0.3f, 0.3f); glDrawArrays(GL_TRIANGLES, 0, 36); glUniform3f(uniColor, 1.0f, 1.0f, 1.0f);*/ glDisable(GL_STENCIL_TEST); // Bind default framebuffer and draw contents of our framebuffer glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindVertexArray(vaoQuad); glDisable(GL_DEPTH_TEST); glUseProgram(screenShaderProgram); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texColorBuffer); glDrawArrays(GL_TRIANGLES, 0, 6); glfwSwapBuffers(window); } glDeleteRenderbuffers(1, &rboDepthStencil); glDeleteTextures(1, &texColorBuffer); glDeleteFramebuffers(1, &frameBuffer); glDeleteTextures(1, &texKitten); glDeleteTextures(1, &texPuppy); glDeleteProgram(screenShaderProgram); glDeleteShader(screenFragmentShader); glDeleteShader(screenVertexShader); glDeleteProgram(sceneShaderProgram); glDeleteShader(sceneFragmentShader); glDeleteShader(sceneVertexShader); glDeleteBuffers(1, &vboCube); glDeleteBuffers(1, &vboQuad); glDeleteVertexArrays(1, &vaoCube); glDeleteVertexArrays(1, &vaoQuad); glfwTerminate(); }
int main(int argc, char *argv[]) { auto t_start = std::chrono::high_resolution_clock::now(); GLfloat directionx, directiony, directionz; directionx = 0.0f; directiony = 0.0f; directionz = 1.0f; GLboolean quit = GL_FALSE; GLenum errorValue; // Initialize SDL if (SDL_Init(SDL_INIT_VIDEO) < 0) { std::cerr << "SDL video initialization failed! Error: " << SDL_GetError() << std::endl; quit = GL_TRUE; SDL_Delay(5000); } SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); SDL_Window* window = SDL_CreateWindow("OpenGL tutorial", 100, 100, width, height, SDL_WINDOW_OPENGL); SDL_GLContext context = SDL_GL_CreateContext(window); // Initialize GLEW glewExperimental = GL_TRUE; glewInit(); // Error checking errorValue = glGetError(); if (errorValue != 0) { std::cerr << "GL_Error after GLEW init: " << errorValue << std::endl; } // Create Vertex Array Objects, don't bind yet /* VAOs are used to store all of the links between the vertex attributes and VBOs with raw vertex data. Since VBOs are just containers for the raw data that the graphics card reads and manipulates, the meaning and usage of the data has to be specified for each VBO & shader program. This might be quite cumbersome, if many shader programs are used, since the layout of the attributes would have to be specified every time. This is wheree VAOs come in: they can be used to store the links between VBO and the specified attributes. This way, a new VAO can be bound for each different shader program, which can then be changed easily at will by just calling glUseProgram(shaderProg1);. The graphics card then knows how to use the raw data in the VBO, since its usage and meaning has been specified beforehand and the links between VBOs and attributes has been saved to the VAO. As soon as VAO has been bound, all glVertexAttribPointer calls store the information to that VAO. */ GLuint vaoCube, vaoQuad; glGenVertexArrays(1, &vaoCube); glGenVertexArrays(1, &vaoQuad); // Create a Vertex Buffer Objects and upload vertex data /* VBOs are used to upload the vertex data to the graphics card. glGenBuffers(); creates a VBO, which can then be made active by binding it with glBindBuffer();. When the VBO has been set as active by binding it, the vertex data can be loaded to it with glBufferData();. Note that VBO/OpenGL doesn't know what the data means or is used for, it's just raw data. The usage of the data has to be specified, meaning which indices in the data correspond to which attribute (pos, color, texcoord, etc.). */ GLuint vboCube, vboQuad; glGenBuffers(1, &vboCube); glGenBuffers(1, &vboQuad); glBindBuffer(GL_ARRAY_BUFFER, vboCube); glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), cubeVertices, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, vboQuad); glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), quadVertices, GL_STATIC_DRAW); // Error checking errorValue = glGetError(); if (errorValue != 0) { std::cerr << "GL_Error after VBOs: " << errorValue << std::endl; } // Generate shader programs GLuint sceneVertexShader, sceneFragmentShader, sceneShaderProgram; createShaderprogram(sceneVertexSource, sceneFragmentSource, sceneVertexShader, sceneFragmentShader, sceneShaderProgram); GLuint screenVertexShader, screenFragmentShader, screenShaderProgram; createShaderprogram(screenVertexSource, screenFragmentSource, screenVertexShader, screenFragmentShader, screenShaderProgram); // Error checking errorValue = glGetError(); if (errorValue != 0) { std::cerr << "GL_Error after generating shader programs: " << errorValue << std::endl; } // Specify the layout of the vertex data (bind vertex arrays) /* Since OpenGL doesn't know how the attributes of the vertices are specified in the arrays containing the vertex information (position, color, texture coordinates), they need to be specified by the user. Each attribute also saves the VBO that's been bound to the current GL_ARRAY_BUFFER. This means different VBOs can be used for each attribute if so desired. Only calls after a VAO has been bound will "stick" to it. As soon as VAO has been bound, all glVertexAttribPointer calls store the information to that VAO. See more complete explanation of VAO above. */ glBindVertexArray(vaoCube); glBindBuffer(GL_ARRAY_BUFFER, vboCube); specifySceneVertexAttributes(sceneShaderProgram); glBindVertexArray(vaoQuad); glBindBuffer(GL_ARRAY_BUFFER, vboQuad); specifyScreenVertexAttributes(screenShaderProgram); // Error checking errorValue = glGetError(); if (errorValue != 0) { std::cerr << "GL_Error after specifying the layout of vertex data: " << errorValue << std::endl; } // Load textures GLuint texKitten = loadTexture("sample.png"); GLuint texPuppy = loadTexture("sample2.png"); glUseProgram(sceneShaderProgram); glUniform1i(glGetUniformLocation(sceneShaderProgram, "texKitten"), 0); glUniform1i(glGetUniformLocation(sceneShaderProgram, "texPuppy"), 1); glUseProgram(screenShaderProgram); glUniform1i(glGetUniformLocation(screenShaderProgram, "texFramebuffer"), 0); GLint uniModel = glGetUniformLocation(sceneShaderProgram, "model"); // Error checking errorValue = glGetError(); if (errorValue != 0) { std::cerr << "GL_Error after loading textures: " << errorValue << std::endl; } // Create frame buffer GLuint frameBuffer; glGenFramebuffers(1, &frameBuffer); glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer); // Error checking errorValue = glGetError(); if (errorValue != 0) { std::cerr << "GL_Error after creating a frame buffer: " << errorValue << std::endl; } // Create texture to hold color buffer GLuint texColorBuffer; glGenTextures(1, &texColorBuffer); glBindTexture(GL_TEXTURE_2D, texColorBuffer); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texColorBuffer, 0); // Error checking errorValue = glGetError(); if (errorValue != 0) { std::cerr << "GL_Error after color buffer texture creation: " << errorValue << std::endl; } // Create Renderbuffer Object to hold depth and stencil buffers GLuint rboDepthStencil; glGenRenderbuffers(1, &rboDepthStencil); glBindRenderbuffer(GL_RENDERBUFFER, rboDepthStencil); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rboDepthStencil); // Error checking errorValue = glGetError(); if (errorValue != 0) { std::cerr << "GL_Error after RBO: " << errorValue << std::endl; } /* Set up projection: View matrix: First vector gives the position of the camera Second vector gives the point where the camera is centered or looking at Third vector defines "up", here up is the z-axis, xy-plane is the "ground" */ glm::mat4 view = glm::lookAt( glm::vec3(2.5f, 2.5f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f) ); glUseProgram(sceneShaderProgram); GLint uniView = glGetUniformLocation(sceneShaderProgram, "view"); glUniformMatrix4fv(uniView, 1, GL_FALSE, glm::value_ptr(view)); // Projection matrix glm::mat4 proj = glm::perspective(glm::radians(45.0f), GLfloat(width) / GLfloat(height), 1.0f, 10.0f); GLint uniProj = glGetUniformLocation(sceneShaderProgram, "proj"); glUniformMatrix4fv(uniProj, 1, GL_FALSE, glm::value_ptr(proj)); GLint uniColor = glGetUniformLocation(sceneShaderProgram, "overrideColor"); // Final error check will write errors (if any are encountered at this point) to file GLint status, status2, status3, status4, OpenGLError; OpenGLError = glGetError(); GLenum frameBufferStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); glGetShaderiv(sceneVertexShader, GL_COMPILE_STATUS, &status); glGetShaderiv(sceneFragmentShader, GL_COMPILE_STATUS, &status2); glGetShaderiv(screenVertexShader, GL_COMPILE_STATUS, &status3); glGetShaderiv(screenFragmentShader, GL_COMPILE_STATUS, &status4); if ( OpenGLError != 0 || status == 0 || status2 == 0 || status3 == 0 || status4 == 0 || frameBufferStatus != GL_FRAMEBUFFER_COMPLETE) { char buffer1[512], buffer2[512], buffer3[512], buffer4[512]; glGetShaderInfoLog(sceneVertexShader, 512, NULL, buffer1); glGetShaderInfoLog(sceneFragmentShader, 512, NULL, buffer2); glGetShaderInfoLog(screenVertexShader, 512, NULL, buffer3); glGetShaderInfoLog(screenFragmentShader, 512, NULL, buffer4); std::ofstream errorOutput; GLchar* errorOutFilename = "shader_errors.txt"; errorOutput.open(errorOutFilename); errorOutput << "GL_Error: " << OpenGLError << "\n Scene vertex shader status: " << status << "\n Scene vertex shader log: " << buffer1 << "\n Scene fragment shader status: " << status2 << "\n Scene fragment shader log: " << buffer2 << "\n Screen vertex shader status: " << status3 << "\n Screen vertex shader log: " << buffer3 << "\n Screen fragment shader status: " << status4 << "\n Screen fragment shader log: " << buffer4 << "\n Frame buffer status: " << frameBufferStatus << "\n OpenGL version: " << glGetString(GL_VERSION); errorOutput.close(); std::cerr << "An error has occured with shaders or frame buffer! See " << errorOutFilename << " for more info!\n Terminating program in 10s!" << std::endl; SDL_Delay(10000); quit = GL_TRUE; } SDL_Event e; while (!quit) { while (SDL_PollEvent(&e) != 0) { if (e.type == SDL_QUIT) { quit = GL_TRUE; } else if (e.type == SDL_KEYDOWN) { switch (e.key.keysym.sym) { case SDLK_RETURN: directionx = 1.0f; directiony = 0.0f; directionz = 0.0f; break; case SDLK_SPACE: directionx = 0.0f; directiony = 1.0f; directionz = 0.0f; break; case SDLK_LCTRL: directionx = 0.0f; directiony = 0.0f; directionz = 1.0f; default: directionx = 0.0f; directiony = 0.0f; directionz = 1.0f; break; } } } // Bind framebuffer and draw 3D scene glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer); glBindVertexArray(vaoCube); glEnable(GL_DEPTH_TEST); glUseProgram(sceneShaderProgram); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texKitten); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, texPuppy); // Clear screen to greenish glClearColor(0.15f, 0.7f, 0.5f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Calculate transformation auto t_now = std::chrono::high_resolution_clock::now(); float time = std::chrono::duration_cast<std::chrono::duration<float>>(t_now - t_start).count(); glm::mat4 model; model = glm::rotate(model, time * glm::radians(180.f), glm::vec3(directionx, directiony, directionz)); glUniformMatrix4fv(uniModel, 1, GL_FALSE, glm::value_ptr(model)); // Draw cube glDrawArrays(GL_TRIANGLES, 0, 36); glEnable(GL_STENCIL_TEST); // Draw floor glStencilFunc(GL_ALWAYS, 1, 0xFF); // Set any stencil to 1 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); glStencilMask(0xFF); // Write to stencil buffer glDepthMask(GL_FALSE); // Don't write to depth buffer glClear(GL_STENCIL_BUFFER_BIT); // Clear stencil buffer (0 by default) glDrawArrays(GL_TRIANGLES, 36, 6); // Draw cube reflection glStencilFunc(GL_EQUAL, 1, 0xFF); // Pass test if stencil value is 1 glStencilMask(0x00); // Don't write anything to stencil buffer glDepthMask(GL_TRUE); // Write to depth buffer model = glm::scale(glm::translate(model, glm::vec3(0, 0, -1)), glm::vec3(1, 1, -1)); glUniformMatrix4fv(uniModel, 1, GL_FALSE, glm::value_ptr(model)); glUniform3f(uniColor, 0.3f, 0.3f, 0.3f); glDrawArrays(GL_TRIANGLES, 0, 36); glUniform3f(uniColor, 1.0f, 1.0f, 1.0f); glDisable(GL_STENCIL_TEST); // Bind default framebuffer and draw contents of our framebuffer glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindVertexArray(vaoQuad); glDisable(GL_DEPTH_TEST); glUseProgram(screenShaderProgram); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texColorBuffer); glDrawArrays(GL_TRIANGLES, 0, 6); // Swap buffers SDL_GL_SwapWindow(window); } glDeleteRenderbuffers(1, &rboDepthStencil); glDeleteTextures(1, &texColorBuffer); glDeleteFramebuffers(1, &frameBuffer); glDeleteTextures(1, &texKitten); glDeleteTextures(1, &texPuppy); glDeleteProgram(screenShaderProgram); glDeleteShader(screenFragmentShader); glDeleteShader(screenVertexShader); glDeleteProgram(sceneShaderProgram); glDeleteShader(sceneFragmentShader); glDeleteShader(sceneVertexShader); glDeleteBuffers(1, &vboCube); glDeleteBuffers(1, &vboQuad); glDeleteVertexArrays(1, &vaoCube); glDeleteVertexArrays(1, &vaoQuad); SDL_GL_DeleteContext(context); SDL_Quit(); return 0; }