CP21:FRAMEBUFFER pipeline:
绘制一幅图,便于理解
这章我又被贴图单元迷惑了,经过理性的测试,发现一个Frag材质里只有一个贴图.那么绘制如下:
#version 450 core // INCOMING DATA layout ( location = 0 ) in vec4 v_position; // pos //layout ( location = 1 ) in vec3 v_normal; // norm layout ( location = 1 ) in vec2 v_texCoord; // st // define out data out vec2 f_TexCoord; // normal at world matrix, we direct from C++ calcalation out vec3 f_Normal; // to world matrix : mat3( transpose(inverse(model)) ) * v_normal; out vec3 f_Pos; // INCOMING THE MATRIX FROM CLIENT to transform the gl point position uniform mat4 model; uniform mat4 view; uniform mat4 projection; void main(){ // Transform the world matrix to view matrix gl_Position = projection * view * model * v_position; //f_Normal = mat3(transpose(inverse(model))) * v_normal; // f_Normal at world matrix f_TexCoord = v_texCoord; // out TexCoord f_Pos = vec3(model *v_position); // out fragment position }
#version 450 core // Final Color To export out vec4 FragColor; // from vert shader in vec3 f_Normal; in vec2 f_TexCoord; in vec3 f_Pos; // fragment position uniform sampler2D diffuse_map; void main() { vec4 df = texture(diffuse_map, f_TexCoord); FragColor = df; }
教程中用了个Quad 形状覆盖到整个窗口上的材质:
#version 450 core // INCOMING DATA layout (location = 0) in vec2 aPos; layout (location = 1) in vec2 aTexCoords; out vec2 TexCoords; void main() { TexCoords = aTexCoords; gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0); }
#version 450 core out vec4 FragColor; in vec2 TexCoords; uniform sampler2D screenTexture; void main() { vec3 col = texture2D(screenTexture, TexCoords).rgb; FragColor = vec4(col, 1.0); }
教程中所展示的: 不用贴图单元是完全可以的:
#define GLEW_STATIC // GLEW #include <GL/glew.h> #include <cstdlib> #undef GLFW_DLL // GLFW #include <GLFW/glfw3.h> #include <iostream> #include "ALG_LoadShader.h" #include "ALG_LoadTexture.h" #include "ALG_GLFWCamera.h" #include "ALG_FrameWindow.h" #include "ALG_ModelDelegate.h" #include "ALG_SceneDelegate.h" #include "ALG_DrawGrid.h" #include <cmath> #include "OGLHelper.h" #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> #include <map> using namespace AlgebraMaster; const unsigned int SRC_WIDTH = 1400; const unsigned int SRC_HEIGHT = 720; static LoadShader SurfaceShader; static LoadShader ScreenShader; void init(); void display(); void processInput(GLFWwindow *window); void framebuffer_size_callback(GLFWwindow* window, int width, int height); // framezize void mouse_callback(GLFWwindow* window, double xpos, double ypos); // Maya Alt+LeftMouse void scroll_callback(GLFWwindow *window, double xoffset, double yoffset); // camera static GLFWCamera *camera; static float lastX = float(SRC_WIDTH) / 2.0f; static float lastY = float(SRC_HEIGHT) / 2.0f; static bool firstMouse = true; static bool firstMiddowMouse = true; // timing static float deltaTime = 0.0f; // time between current frame and last frame static float lastFrame = 0.0f; // light define static glm::vec3 lightPos(0.0f, 4.0f,-2.0f); // Geometry static DrawGrid grid; static float cubeVertices[] = { // positions // texture Coords -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f }; static float planeVertices[] = { // positions // texture Coords 5.0f, -0.5f, 5.0f, 2.0f, 0.0f, -5.0f, -0.5f, 5.0f, 0.0f, 0.0f, -5.0f, -0.5f, -5.0f, 0.0f, 2.0f, 5.0f, -0.5f, 5.0f, 2.0f, 0.0f, -5.0f, -0.5f, -5.0f, 0.0f, 2.0f, 5.0f, -0.5f, -5.0f, 2.0f, 2.0f }; static float transparentVertices[] = { // positions // texture Coords (swapped y coordinates because texture is flipped upside down) 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, -0.5f, 0.0f, 0.0f, 1.0f, 1.0f, -0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 0.5f, 0.0f, 1.0f, 0.0f }; float quadVertices[] = { // vertex attributes for a quad that fills the entire screen in Normalized Device Coordinates. // positions // texCoords -1.0f, 1.0f, 0.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f }; // cube vao vbo static unsigned int cubeVAO,cubeVBO; static unsigned int planeVAO,planeVBO; static unsigned int quadVAO,quadVBO; static unsigned int FBO; // frame buffer object static unsigned int FBOTextureID; // texture attachment to FBO static unsigned int RBO; // render buffer object static LoadTexture cubeTex; static LoadTexture groundTex; void init(){ camera = new GLFWCamera; camera->pos.y = 1.0f; camera->pos.z = 4.0f; // GL depth zbuffer glEnable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); SurfaceShader.load("shaders/SurfaceShader.vert","shaders/SurfaceShader.frag"); ScreenShader.load("shaders/ScreenShader.vert","shaders/ScreenShader.frag"); glGenVertexArrays(1, &cubeVAO); glGenBuffers(1, &cubeVBO); glBindVertexArray(cubeVAO); glBindBuffer(GL_ARRAY_BUFFER, cubeVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), &cubeVertices, GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); CreateGeometryBuffer(planeVAO, planeVBO); glBufferData(GL_ARRAY_BUFFER,sizeof(planeVertices),&planeVertices, 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))); CreateGeometryBuffer(quadVAO, quadVBO); glBufferData(GL_ARRAY_BUFFER,sizeof(quadVertices),&quadVertices, GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float))); glBindVertexArray(0); cout << "cube VAO:" << cubeVAO <<endl; cubeTex.load("texture/marble.jpg"); groundTex.load("texture/metal.png"); // FBO with texture attchment glGenFramebuffers(1, &FBO); glBindFramebuffer(GL_FRAMEBUFFER, FBO); glGenTextures(1, &FBOTextureID); glBindTexture(GL_TEXTURE_2D, FBOTextureID); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SRC_WIDTH, SRC_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, FBOTextureID, 0); // render buffer object glGenRenderbuffers(1, &RBO); glBindRenderbuffer(GL_RENDERBUFFER, RBO); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, SRC_WIDTH, SRC_WIDTH); // use a single renderbuffer object for both a depth AND stencil buffer. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, RBO); // now actually attach it // now that we actually created the framebuffer and added all attachments we want to check if it is actually complete now if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << endl; glBindFramebuffer(GL_FRAMEBUFFER, 0); grid.initialize(); } // ----------- Render Loop ---------- void display(){ // per-frame time logic // -------------------- float currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; // bind to framebuffer and draw scene as we normally would to color texture glBindFramebuffer(GL_FRAMEBUFFER, FBO); glEnable(GL_DEPTH_TEST); // enable depth testing (is disabled for rendering screen-space quad) glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // object .vert settings glm::mat4 projection = glm::perspective(glm::radians(camera->fov),float(SRC_WIDTH) / float(SRC_HEIGHT),0.1f, 1000.0f); glm::mat4 view = camera->GetViewMatrix(); // object world transformation glm::mat4 model = glm::mat4(1.0f); grid.draw(projection,view); // render cube glBindTexture(GL_TEXTURE_2D,cubeTex.textureID); SurfaceShader.use(); SurfaceShader.setInt("diffuse_map", 0); SurfaceShader.setMat4("projection", projection); SurfaceShader.setMat4("view", view); model = glm::translate(model, glm::vec3(-1.0f, 0.0f, -1.0f)); SurfaceShader.setMat4("model", model); glBindVertexArray(cubeVAO); glDrawArrays(GL_TRIANGLES, 0, 36); model = glm::mat4(1.0f); model = glm::translate(model, glm::vec3(2.0f, 0.0f, 0.0f)); SurfaceShader.setMat4("model", model); glDrawArrays(GL_TRIANGLES, 0, 36); // floor glBindTexture(GL_TEXTURE_2D, groundTex.getTextureID()); SurfaceShader.setInt("diffuse_map", 0); glBindVertexArray(planeVAO); model = glm::mat4(1.0f); SurfaceShader.setMat4("model", model); glDrawArrays(GL_TRIANGLES, 0, 6); // now bind back to default framebuffer and draw a quad plane with the attached framebuffer color texture glBindFramebuffer(GL_FRAMEBUFFER, 0); // disable depth test so screen-space quad isn't discarded due to depth test. glDisable(GL_DEPTH_TEST); glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // set clear color to white (not really necessery actually, since we won't be able to see behind the quad anyways) glClear(GL_COLOR_BUFFER_BIT); ScreenShader.use(); ScreenShader.setInt("screenTexture",0 ); glBindVertexArray(quadVAO); glBindTexture(GL_TEXTURE_2D, FBOTextureID); glDrawArrays(GL_TRIANGLES, 0, 6); } int main() { glfwInit(); FrameWindow FrameWindow(SRC_WIDTH,SRC_HEIGHT); glfwSetFramebufferSizeCallback(FrameWindow.getWindow(), framebuffer_size_callback); glfwSetCursorPosCallback(FrameWindow.getWindow(),mouse_callback); glfwSetScrollCallback(FrameWindow.getWindow(), scroll_callback); init(); // RENDER-------------- //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); while(!glfwWindowShouldClose(FrameWindow.getWindow())){ processInput(FrameWindow.getWindow()); display(); glfwSwapBuffers(FrameWindow.getWindow()); glfwPollEvents(); } delete camera; glDeleteVertexArrays(1, &cubeVAO); glDeleteVertexArrays(1, &planeVAO); glDeleteVertexArrays(1, &quadVAO); glDeleteBuffers(1, &cubeVBO); glDeleteBuffers(1, &planeVBO); glDeleteBuffers(1, &quadVBO); return 0; } 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); } void processInput(GLFWwindow *window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(window, true); if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) camera->processKeyboardMove(deltaTime,GLFWCamera::FORWARD); if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) camera->processKeyboardMove(deltaTime,GLFWCamera::BACKWARD); if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) camera->processKeyboardMove(deltaTime,GLFWCamera::LEFT); if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) camera->processKeyboardMove(deltaTime,GLFWCamera::RIGHT); } // ROTATE VIEW DIR void mouse_callback(GLFWwindow* window, double xpos, double ypos){ int middow_mouse_state = glfwGetMouseButton(window,GLFW_MOUSE_BUTTON_MIDDLE); int mouse_state = glfwGetMouseButton(window,GLFW_MOUSE_BUTTON_LEFT); int key_state = glfwGetKey(window,GLFW_KEY_LEFT_ALT); // set up the camera view if( mouse_state == GLFW_PRESS && key_state== GLFW_PRESS) { 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->processMouseMove(xoffset,yoffset); } if (key_state == GLFW_RELEASE || mouse_state == GLFW_RELEASE){ firstMouse = true; } // Move Camera Position if( middow_mouse_state == GLFW_PRESS) { if (firstMiddowMouse){ lastX = xpos; lastY = ypos; firstMiddowMouse = false; } float xoffset = xpos - lastX; float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top lastX = xpos; lastY = ypos; camera->pos.x += xoffset*0.01f; camera->pos.y += yoffset*0.01f; } if ( middow_mouse_state == GLFW_RELEASE){ firstMiddowMouse = true; } } void scroll_callback(GLFWwindow *window, double xoffset, double yoffset){ camera->processFov(yoffset); }
观察下面的Render Cube 和 Render Floor 部分,因为材质只有一个diffuse_map,
虽然系统加载了2个贴图,但是每个贴图有个ID,所以:
只要在渲染立方体时候,绑定立方体的贴图ID
glBindTexture(GL_TEXTURE_2D,cubeTex.textureID);
SurfaceShader.setInt("diffuse_map", 0);
只要在渲染地面时候,绑定地面的贴图ID
glBindTexture(GL_TEXTURE_2D, groundTex.getTextureID());
SurfaceShader.setInt("diffuse_map", 0);
所以系统默认的贴图单元是:
glActiveTexture(GL_TEXTURE0)
现在我想强制使用贴图单元控制:
#define GLEW_STATIC // GLEW #include <GL/glew.h> #include <cstdlib> #undef GLFW_DLL // GLFW #include <GLFW/glfw3.h> #include <iostream> #include "ALG_LoadShader.h" #include "ALG_LoadTexture.h" #include "ALG_GLFWCamera.h" #include "ALG_FrameWindow.h" #include "ALG_ModelDelegate.h" #include "ALG_SceneDelegate.h" #include "ALG_DrawGrid.h" #include <cmath> #include "OGLHelper.h" #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> #include <map> using namespace AlgebraMaster; const unsigned int SRC_WIDTH = 1400; const unsigned int SRC_HEIGHT = 720; static LoadShader SurfaceShader; static LoadShader ScreenShader; void init(); void display(); void processInput(GLFWwindow *window); void framebuffer_size_callback(GLFWwindow* window, int width, int height); // framezize void mouse_callback(GLFWwindow* window, double xpos, double ypos); // Maya Alt+LeftMouse void scroll_callback(GLFWwindow *window, double xoffset, double yoffset); // camera static GLFWCamera *camera; static float lastX = float(SRC_WIDTH) / 2.0f; static float lastY = float(SRC_HEIGHT) / 2.0f; static bool firstMouse = true; static bool firstMiddowMouse = true; // timing static float deltaTime = 0.0f; // time between current frame and last frame static float lastFrame = 0.0f; // light define static glm::vec3 lightPos(0.0f, 4.0f,-2.0f); // Geometry static DrawGrid grid; static float cubeVertices[] = { // positions // texture Coords -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f }; static float planeVertices[] = { // positions // texture Coords 5.0f, -0.5f, 5.0f, 2.0f, 0.0f, -5.0f, -0.5f, 5.0f, 0.0f, 0.0f, -5.0f, -0.5f, -5.0f, 0.0f, 2.0f, 5.0f, -0.5f, 5.0f, 2.0f, 0.0f, -5.0f, -0.5f, -5.0f, 0.0f, 2.0f, 5.0f, -0.5f, -5.0f, 2.0f, 2.0f }; static float transparentVertices[] = { // positions // texture Coords (swapped y coordinates because texture is flipped upside down) 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, -0.5f, 0.0f, 0.0f, 1.0f, 1.0f, -0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 0.5f, 0.0f, 1.0f, 0.0f }; float quadVertices[] = { // vertex attributes for a quad that fills the entire screen in Normalized Device Coordinates. // positions // texCoords -1.0f, 1.0f, 0.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f }; // cube vao vbo static unsigned int cubeVAO,cubeVBO; static unsigned int planeVAO,planeVBO; static unsigned int quadVAO,quadVBO; static unsigned int FBO; // frame buffer object static unsigned int FBOTextureID; // texture attachment to FBO static unsigned int RBO; // render buffer object static LoadTexture cubeTex; static LoadTexture groundTex; void init(){ camera = new GLFWCamera; camera->pos.y = 1.0f; camera->pos.z = 4.0f; // GL depth zbuffer glEnable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); SurfaceShader.load("shaders/SurfaceShader.vert","shaders/SurfaceShader.frag"); ScreenShader.load("shaders/ScreenShader.vert","shaders/ScreenShader.frag"); glGenVertexArrays(1, &cubeVAO); glGenBuffers(1, &cubeVBO); glBindVertexArray(cubeVAO); glBindBuffer(GL_ARRAY_BUFFER, cubeVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), &cubeVertices, GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); CreateGeometryBuffer(planeVAO, planeVBO); glBufferData(GL_ARRAY_BUFFER,sizeof(planeVertices),&planeVertices, 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))); CreateGeometryBuffer(quadVAO, quadVBO); glBufferData(GL_ARRAY_BUFFER,sizeof(quadVertices),&quadVertices, GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float))); glBindVertexArray(0); cout << "cube VAO:" << cubeVAO <<endl; cubeTex.load("texture/marble.jpg"); groundTex.load("texture/metal.png"); // FBO with texture attchment glGenFramebuffers(1, &FBO); glBindFramebuffer(GL_FRAMEBUFFER, FBO); glGenTextures(1, &FBOTextureID); glBindTexture(GL_TEXTURE_2D, FBOTextureID); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SRC_WIDTH, SRC_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, FBOTextureID, 0); // render buffer object glGenRenderbuffers(1, &RBO); glBindRenderbuffer(GL_RENDERBUFFER, RBO); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, SRC_WIDTH, SRC_WIDTH); // use a single renderbuffer object for both a depth AND stencil buffer. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, RBO); // now actually attach it // now that we actually created the framebuffer and added all attachments we want to check if it is actually complete now if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << endl; glBindFramebuffer(GL_FRAMEBUFFER, 0); grid.initialize(); } // ----------- Render Loop ---------- void display(){ // per-frame time logic // -------------------- float currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; // bind to framebuffer and draw scene as we normally would to color texture glBindFramebuffer(GL_FRAMEBUFFER, FBO); glEnable(GL_DEPTH_TEST); // enable depth testing (is disabled for rendering screen-space quad) glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // object .vert settings glm::mat4 projection = glm::perspective(glm::radians(camera->fov),float(SRC_WIDTH) / float(SRC_HEIGHT),0.1f, 1000.0f); glm::mat4 view = camera->GetViewMatrix(); // object world transformation glm::mat4 model = glm::mat4(1.0f); grid.draw(projection,view); // render cube glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D,cubeTex.textureID); SurfaceShader.use(); SurfaceShader.setInt("diffuse_map", 0); SurfaceShader.setMat4("projection", projection); SurfaceShader.setMat4("view", view); model = glm::translate(model, glm::vec3(-1.0f, 0.0f, -1.0f)); SurfaceShader.setMat4("model", model); glBindVertexArray(cubeVAO); glDrawArrays(GL_TRIANGLES, 0, 36); model = glm::mat4(1.0f); model = glm::translate(model, glm::vec3(2.0f, 0.0f, 0.0f)); SurfaceShader.setMat4("model", model); glDrawArrays(GL_TRIANGLES, 0, 36); // floor glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, groundTex.getTextureID()); SurfaceShader.setInt("diffuse_map", 1); glBindVertexArray(planeVAO); model = glm::mat4(1.0f); SurfaceShader.setMat4("model", model); glDrawArrays(GL_TRIANGLES, 0, 6); // now bind back to default framebuffer and draw a quad plane with the attached framebuffer color texture glBindFramebuffer(GL_FRAMEBUFFER, 0); // disable depth test so screen-space quad isn't discarded due to depth test. glDisable(GL_DEPTH_TEST); glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // set clear color to white (not really necessery actually, since we won't be able to see behind the quad anyways) glClear(GL_COLOR_BUFFER_BIT); ScreenShader.use(); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, FBOTextureID); ScreenShader.setInt("screenTexture",2 ); glBindVertexArray(quadVAO); glDrawArrays(GL_TRIANGLES, 0, 6); } int main() { glfwInit(); FrameWindow FrameWindow(SRC_WIDTH,SRC_HEIGHT); glfwSetFramebufferSizeCallback(FrameWindow.getWindow(), framebuffer_size_callback); glfwSetCursorPosCallback(FrameWindow.getWindow(),mouse_callback); glfwSetScrollCallback(FrameWindow.getWindow(), scroll_callback); init(); // RENDER-------------- //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); while(!glfwWindowShouldClose(FrameWindow.getWindow())){ processInput(FrameWindow.getWindow()); display(); glfwSwapBuffers(FrameWindow.getWindow()); glfwPollEvents(); } delete camera; glDeleteVertexArrays(1, &cubeVAO); glDeleteVertexArrays(1, &planeVAO); glDeleteVertexArrays(1, &quadVAO); glDeleteBuffers(1, &cubeVBO); glDeleteBuffers(1, &planeVBO); glDeleteBuffers(1, &quadVBO); return 0; } 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); } void processInput(GLFWwindow *window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(window, true); if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) camera->processKeyboardMove(deltaTime,GLFWCamera::FORWARD); if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) camera->processKeyboardMove(deltaTime,GLFWCamera::BACKWARD); if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) camera->processKeyboardMove(deltaTime,GLFWCamera::LEFT); if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) camera->processKeyboardMove(deltaTime,GLFWCamera::RIGHT); } // ROTATE VIEW DIR void mouse_callback(GLFWwindow* window, double xpos, double ypos){ int middow_mouse_state = glfwGetMouseButton(window,GLFW_MOUSE_BUTTON_MIDDLE); int mouse_state = glfwGetMouseButton(window,GLFW_MOUSE_BUTTON_LEFT); int key_state = glfwGetKey(window,GLFW_KEY_LEFT_ALT); // set up the camera view if( mouse_state == GLFW_PRESS && key_state== GLFW_PRESS) { 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->processMouseMove(xoffset,yoffset); } if (key_state == GLFW_RELEASE || mouse_state == GLFW_RELEASE){ firstMouse = true; } // Move Camera Position if( middow_mouse_state == GLFW_PRESS) { if (firstMiddowMouse){ lastX = xpos; lastY = ypos; firstMiddowMouse = false; } float xoffset = xpos - lastX; float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top lastX = xpos; lastY = ypos; camera->pos.x += xoffset*0.01f; camera->pos.y += yoffset*0.01f; } if ( middow_mouse_state == GLFW_RELEASE){ firstMiddowMouse = true; } } void scroll_callback(GLFWwindow *window, double xoffset, double yoffset){ camera->processFov(yoffset); }
对于立方体绘制:
// render cube
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,cubeTex.textureID);
SurfaceShader.use();
SurfaceShader.setInt("diffuse_map", 0);
SurfaceShader.setMat4("projection", projection);
SurfaceShader.setMat4("view", view);
model = glm::translate(model, glm::vec3(-1.0f, 0.0f, -1.0f));
SurfaceShader.setMat4("model", model);
// draw geometry
glBindVertexArray(cubeVAO);
glDrawArrays(GL_TRIANGLES, 0, 36);
model = glm::mat4(1.0f);
model = glm::translate(model, glm::vec3(2.0f, 0.0f, 0.0f));
SurfaceShader.setMat4("model", model);
glDrawArrays(GL_TRIANGLES, 0, 36);
对于地面绘制:
// floor glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, groundTex.getTextureID()); SurfaceShader.setInt("diffuse_map", 1); glBindVertexArray(planeVAO); model = glm::mat4(1.0f); SurfaceShader.setMat4("model", model); glDrawArrays(GL_TRIANGLES, 0, 6);
对于屏幕那个方形绘制:
// now bind back to default framebuffer and draw a quad plane with the attached framebuffer color texture glBindFramebuffer(GL_FRAMEBUFFER, 0);
// disable depth test so screen-space quad isn't discarded due to depth test. glDisable(GL_DEPTH_TEST); glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // set clear color to white (not really necessery actually, since we won't be able to see behind the quad anyways) glClear(GL_COLOR_BUFFER_BIT); ScreenShader.use(); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, FBOTextureID); ScreenShader.setInt("screenTexture",2 ); glBindVertexArray(quadVAO); glDrawArrays(GL_TRIANGLES, 0, 6);
教程的目的是自己建立的buffer用来绘制场景,包括深度,模板。
而自己建立的Quad覆盖到窗口上,是只绘制了Quad,加载了个buffer texture
CP22:
直接修改ScreenShader.frag, Kernel网络教程比较多,把官网的抄袭下没啥意思。wiki有更多的,或者更大的kernel
#version 450 core out vec4 FragColor; in vec2 TexCoords; uniform sampler2D screenTexture; const float offset = 1.0 / 300.0; void main() { vec2 offsets[9] = vec2[]( vec2(-offset, offset), // 左上 vec2( 0.0f, offset), // 正上 vec2( offset, offset), // 右上 vec2(-offset, 0.0f), // 左 vec2( 0.0f, 0.0f), // 中 vec2( offset, 0.0f), // 右 vec2(-offset, -offset), // 左下 vec2( 0.0f, -offset), // 正下 vec2( offset, -offset) // 右下 ); float kernel[9] = float[]( -1, -1, -1, -1, 9, -1, -1, -1, -1 ); vec3 sampleTex[9]; for(int i = 0; i < 9; i++) { sampleTex[i] = vec3(texture(screenTexture, TexCoords.st + offsets[i])); } vec3 col = vec3(0.0); for(int i = 0; i < 9; i++) col += sampleTex[i] * kernel[i]; FragColor = vec4(col, 1.0); }
CP23:
首先心里一定要知道6个面的顺序,在for循环中++就可以得到每个面的准确位置。第一个是右,自加一此是左边,再加上.......
关于SKY BOX和 反射的测试
要想让Sky box绘制少,就把他的默认Z值永远作为最大。因为深度测试是在vert shading之后,所以在vert把他的z值永远设置为w/w = 1.0f
#version 450 core // INCOMING DATA layout (location = 0) in vec2 aPos; layout (location = 1) in vec2 aTexCoords; out vec2 TexCoords; void main() { TexCoords = aTexCoords; gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0); }
#version 450 core layout (location = 0) in vec3 aPos; out vec3 TexCoord; uniform mat4 projection; uniform mat4 view; void main() { vec4 pos = projection*view*vec4(aPos, 1.0); gl_Position = pos.xyww; TexCoord = aPos; }
把Draw Sky Box 变成一个类,比较简单的绘制天空盒子
// // Created by Admin on 2020/3/1. // #ifndef TRIANGLE_ALG_DRAWENVBOX_H #define TRIANGLE_ALG_DRAWENVBOX_H #include "ALG_OGLHelper.h" #include <iostream> #include <string> #include <vector> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> #include <map> #include "ALG_LoadShader.h" #include "ALG_OGLHelper.h" #include "ALG_LoadTexture.h" namespace AlgebraMaster { using namespace std; static float skyboxVertices[] = { // positions -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f }; class DrawEnvBox{ public: void initialize(){ if(maps.empty()) { cout << "Error initialize EnvBox, no maps loaded "; return; } shader.load("shaders/SkyBox.vert","shaders/Skybox.frag"); // create Cube Map VAO VBO CreateGeometryBuffer(VAO, VBO); glBufferData(GL_ARRAY_BUFFER,sizeof(skyboxVertices),&skyboxVertices, GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); } void setupMaps(const vector<string> &maps){ texture.loadCubeMap(maps); this->maps = maps; } void draw(glm::mat4 &proj, glm::mat4 &view){ if(maps.empty()) { cout << "Error initialize EnvBox, no maps loaded "; return; } shader.use(); shader.setMat4("projection",proj); shader.setMat4("view",glm::mat4(glm::mat3(view)) ); // we only want get rotation glDepthFunc(GL_LEQUAL); glBindTexture(GL_TEXTURE_CUBE_MAP,texture.getTextureID()); glBindVertexArray(VAO); glDrawArrays(GL_TRIANGLES, 0 ,36); glDepthFunc(GL_LESS); // set depth function back to default } LoadShader shader; LoadTexture texture; vector<string> maps; unsigned int VAO; unsigned int VBO; }; } #endif //TRIANGLE_ALG_DRAWENVBOX_H
并且修改ALG_LoadTexture.h增加一个读取天空盒子的函数
#ifndef LOADTEXTURE_H #define LOADTEXTURE_H #include <GL/glew.h> // IMP the stb image loader #define STB_IMAGE_IMPLEMENTATION #include <stb_image.h> #include <iostream> #include <vector> using namespace std; namespace AlgebraMaster { class LoadTexture { public: LoadTexture(); LoadTexture(const char *fileName); void load(const char *fileName); void loadCubeMap(const vector<string> &maps); virtual ~LoadTexture(); inline GLuint getTextureID()const{return textureID;} inline GLuint getImageFormat()const{return format;} GLuint textureID; GLenum format; bool loadStatus; }; LoadTexture::LoadTexture() { loadStatus = false; } /* GL_TEXTURE_CUBE_MAP_POSITIVE_X RIGTH GL_TEXTURE_CUBE_MAP_NEGATIVE_X LEFT GL_TEXTURE_CUBE_MAP_POSITIVE_Y TOP GL_TEXTURE_CUBE_MAP_NEGATIVE_Y BOTTOM GL_TEXTURE_CUBE_MAP_POSITIVE_Z BACK GL_TEXTURE_CUBE_MAP_NEGATIVE_Z FRONT */ void LoadTexture::loadCubeMap(const vector<string> &maps) { glCreateTextures(GL_TEXTURE_CUBE_MAP, 1, &textureID); glBindTexture(GL_TEXTURE_CUBE_MAP,textureID); int width, height, nrchans; int i=0; for(const auto & map : maps){ unsigned char *data = stbi_load(map.c_str(),&width, &height, &nrchans,0); if(data){ if (nrchans == 1) format = GL_RED; else if (nrchans == 3) format = GL_RGB; else if (nrchans == 4) format = GL_RGBA; // create opengl image glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,0, format, width,height,0, format,GL_UNSIGNED_BYTE, data); i++ ; } else{ std::cout << "Cube map load failed :" << map << endl; stbi_image_free(data); } } // load the cube maps glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_MAG_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); } // Load basis map from stbi_load() void LoadTexture::load(const char *fileName) { glGenTextures(1, &textureID); int width, height, nrComponents; unsigned char *data = stbi_load(fileName, &width, &height, &nrComponents, 0); if (data) { 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); // create opengl image glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data); // gen MipMap 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_MIPMAP_LINEAR); stbi_image_free(data); loadStatus = true; } else { loadStatus = false; std::cout << "Texture failed to load at path: " << fileName << std::endl; stbi_image_free(data); } } LoadTexture::LoadTexture(const char *fileName){ loadStatus = false; load(fileName); } LoadTexture::~LoadTexture(){} } #endif // LOADTEXTURE_H
主程序:
#define GLEW_STATIC // GLEW #include <GL/glew.h> #include <cstdlib> #undef GLFW_DLL // GLFW #include <GLFW/glfw3.h> #include <iostream> #include "ALG_LoadShader.h" #include "ALG_LoadTexture.h" #include "ALG_GLFWCamera.h" #include "ALG_FrameWindow.h" #include "ALG_ModelDelegate.h" #include "ALG_SceneDelegate.h" #include "ALG_DrawGrid.h" #include <cmath> #include "ALG_OGLHelper.h" #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> #include <map> #include "ALG_DrawEnvBox.h" using namespace AlgebraMaster; const unsigned int SRC_WIDTH = 1400; const unsigned int SRC_HEIGHT = 720; static LoadShader SurfaceShader; static LoadShader ScreenShader; static LoadShader SkyBoxShader; void init(); void display(); void processInput(GLFWwindow *window); void framebuffer_size_callback(GLFWwindow* window, int width, int height); // framezize void mouse_callback(GLFWwindow* window, double xpos, double ypos); // Maya Alt+LeftMouse void scroll_callback(GLFWwindow *window, double xoffset, double yoffset); static float lastX = float(SRC_WIDTH) / 2.0f; static float lastY = float(SRC_HEIGHT) / 2.0f; static bool firstMouse = true; static bool firstMiddowMouse = true; // timing static float deltaTime = 0.0f; // time between current frame and last frame static float lastFrame = 0.0f; static float cubeVertices[] = { // positions // texture Coords -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 0.0f, -1.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, -1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f }; static float planeVertices[] = { // positions // texture Coords // NORMAL 5.0f, -0.5f, 5.0f, 2.0f, 0.0f, 0.0f,1.0f,0.0f, -5.0f, -0.5f, 5.0f, 0.0f, 0.0f, 0.0f,1.0f,0.0f, -5.0f, -0.5f, -5.0f, 0.0f, 2.0f, 0.0f,1.0f,0.0f, 5.0f, -0.5f, 5.0f, 2.0f, 0.0f, 0.0f,1.0f,0.0f, -5.0f, -0.5f, -5.0f, 0.0f, 2.0f, 0.0f,1.0f,0.0f, 5.0f, -0.5f, -5.0f, 2.0f, 2.0f, 0.0f,1.0f,0.0f, }; float quadVertices[] = { // vertex attributes for a quad that fills the entire screen in Normalized Device Coordinates. // positions // texCoords -1.0f, 1.0f, 0.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f }; // cube vao vbo static unsigned int cubeVAO,cubeVBO; static unsigned int planeVAO,planeVBO; static unsigned int quadVAO,quadVBO; static unsigned int envCubeVAO,envCubeVBO; static unsigned int FBO; // frame buffer object static unsigned int FBOTextureID; // texture attachment to FBO static unsigned int RBO; // render buffer object // Geometry// // camera static GLFWCamera *camera; // light define static glm::vec3 lightPos(0.0f, 4.0f,-2.0f); static DrawGrid grid; static DrawEnvBox envBox; static LoadTexture cubeTex; static LoadTexture groundTex; void init(){ camera = new GLFWCamera; camera->pos.y = 1.0f; camera->pos.z = 4.0f; // GL depth zbuffer glEnable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); SurfaceShader.load("shaders/SurfaceShader.vert","shaders/SurfaceShader.frag"); ScreenShader.load("shaders/ScreenShader.vert","shaders/ScreenShader.frag"); glGenVertexArrays(1, &cubeVAO); glGenBuffers(1, &cubeVBO); glBindVertexArray(cubeVAO); glBindBuffer(GL_ARRAY_BUFFER, cubeVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), &cubeVertices, GL_STATIC_DRAW); // pos glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0); // st glEnableVertexAttribArray(1); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float))); // N glEnableVertexAttribArray(2); glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(5 * sizeof(float))); CreateGeometryBuffer(planeVAO, planeVBO); glBufferData(GL_ARRAY_BUFFER,sizeof(planeVertices),&planeVertices, GL_STATIC_DRAW); // pos glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0); // st glEnableVertexAttribArray(1); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float))); // N glEnableVertexAttribArray(2); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(5 * sizeof(float))); CreateGeometryBuffer(quadVAO, quadVBO); glBufferData(GL_ARRAY_BUFFER,sizeof(quadVertices),&quadVertices, GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float))); // create Cube Map VAO VBO CreateGeometryBuffer(envCubeVAO, envCubeVBO); glBufferData(GL_ARRAY_BUFFER,sizeof(skyboxVertices),&skyboxVertices, GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); glBindVertexArray(0); cout << "cube VAO:" << cubeVAO <<endl; cubeTex.load("texture/marble.jpg"); groundTex.load("texture/metal.png"); // load cube map vector <string> envMaps{ "texture/skybox/right.jpg", "texture/skybox/left.jpg", "texture/skybox/top.jpg", "texture/skybox/bottom.jpg", "texture/skybox/front.jpg", "texture/skybox/back.jpg" }; envBox.setupMaps(envMaps); envBox.initialize(); // FBO with texture attchment CreateFrameBufferTextured(SRC_WIDTH,SRC_HEIGHT,FBO,FBOTextureID); // Render buffer object CreateRenderBufferObject(SRC_WIDTH,SRC_HEIGHT,RBO); grid.initialize(); } // ----------- Render Loop ---------- void display(){ // per-frame time logic // -------------------- float currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; // object .vert settings glm::mat4 projection = glm::perspective(glm::radians(camera->fov),float(SRC_WIDTH) / float(SRC_HEIGHT),0.1f, 1000.0f); glm::mat4 view = camera->GetViewMatrix(); // object world transformation glm::mat4 model = glm::mat4(1.0f); // bind to framebuffer and draw scene as we normally would to color texture glBindFramebuffer(GL_FRAMEBUFFER, FBO); glEnable(GL_DEPTH_TEST); // enable depth testing (is disabled for rendering screen-space quad) glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // draw grid //grid.draw(projection,view); SurfaceShader.use(); SurfaceShader.setMat4("projection", projection); SurfaceShader.setMat4("view", view); SurfaceShader.setVec3("cameraPos",camera->pos); // ------------------------TEXTURE UNIT ------------------- // box map 0 glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D,cubeTex.textureID); // ground map 1 glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D,groundTex.getTextureID()); // CUBE map 2 glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_CUBE_MAP,envBox.texture.textureID); // set FBO TextureID 3 glActiveTexture(GL_TEXTURE3); glBindTexture(GL_TEXTURE_2D, FBOTextureID); // ------------------------TEXTURE UNIT ------------------- // draw BOX SurfaceShader.setInt("diffuse_map", 0); SurfaceShader.setInt("skybox", 2); model = glm::translate(model, glm::vec3(-1.0f, 0.0f, -1.0f)); SurfaceShader.setMat4("model", model); glBindVertexArray(cubeVAO); glDrawArrays(GL_TRIANGLES, 0, 36); model = glm::mat4(1.0f); model = glm::translate(model, glm::vec3(2.0f, 0.0f, 0.0f)); SurfaceShader.setMat4("model", model); glDrawArrays(GL_TRIANGLES, 0, 36); // Draw Plane SurfaceShader.setInt("diffuse_map", 1); glBindVertexArray(planeVAO); model = glm::mat4(1.0f); SurfaceShader.setMat4("model", model); glDrawArrays(GL_TRIANGLES, 0, 6); // draw Env Cube Map envBox.draw(projection,view); // now bind back to default framebuffer and draw a quad plane with the attached framebuffer color texture glBindFramebuffer(GL_FRAMEBUFFER, 0); // disable depth test so screen-space quad isn't discarded due to depth test. glDisable(GL_DEPTH_TEST); glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // set clear color to white (not really necessery actually, since we won't be able to see behind the quad anyways) glClear(GL_COLOR_BUFFER_BIT); ScreenShader.use(); ScreenShader.setInt("screenTexture",3); glBindVertexArray(quadVAO); glDrawArrays(GL_TRIANGLES, 0, 6); } int main() { glfwInit(); FrameWindow FrameWindow(SRC_WIDTH,SRC_HEIGHT); glfwSetFramebufferSizeCallback(FrameWindow.getWindow(), framebuffer_size_callback); glfwSetCursorPosCallback(FrameWindow.getWindow(),mouse_callback); glfwSetScrollCallback(FrameWindow.getWindow(), scroll_callback); init(); // RENDER-------------- //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); while(!glfwWindowShouldClose(FrameWindow.getWindow())){ processInput(FrameWindow.getWindow()); display(); glfwSwapBuffers(FrameWindow.getWindow()); glfwPollEvents(); } delete camera; glDeleteVertexArrays(1, &cubeVAO); glDeleteVertexArrays(1, &planeVAO); glDeleteVertexArrays(1, &quadVAO); glDeleteBuffers(1, &cubeVBO); glDeleteBuffers(1, &planeVBO); glDeleteBuffers(1, &quadVBO); return 0; } 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); } void processInput(GLFWwindow *window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(window, true); if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) camera->processKeyboardMove(deltaTime,GLFWCamera::FORWARD); if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) camera->processKeyboardMove(deltaTime,GLFWCamera::BACKWARD); if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) camera->processKeyboardMove(deltaTime,GLFWCamera::LEFT); if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) camera->processKeyboardMove(deltaTime,GLFWCamera::RIGHT); } // ROTATE VIEW DIR void mouse_callback(GLFWwindow* window, double xpos, double ypos){ int middow_mouse_state = glfwGetMouseButton(window,GLFW_MOUSE_BUTTON_MIDDLE); int mouse_state = glfwGetMouseButton(window,GLFW_MOUSE_BUTTON_LEFT); int key_state = glfwGetKey(window,GLFW_KEY_LEFT_ALT); // set up the camera view if( mouse_state == GLFW_PRESS && key_state== GLFW_PRESS) { 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->processMouseMove(xoffset,yoffset); } if (key_state == GLFW_RELEASE || mouse_state == GLFW_RELEASE){ firstMouse = true; } // Move Camera Position if( middow_mouse_state == GLFW_PRESS) { if (firstMiddowMouse){ lastX = xpos; lastY = ypos; firstMiddowMouse = false; } float xoffset = xpos - lastX; float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top lastX = xpos; lastY = ypos; camera->pos.x += xoffset*0.01f; camera->pos.y += yoffset*0.01f; } if ( middow_mouse_state == GLFW_RELEASE){ firstMiddowMouse = true; } } void scroll_callback(GLFWwindow *window, double xoffset, double yoffset){ camera->processFov(yoffset); }
主程序里有贴图单元,因为我在测试的时候,平面和立方体用了一个贴图,现在加入一个环境盒子贴图,所以用了贴图单元。
#version 450 core // Final Color To export out vec4 FragColor; // from vert shader in vec3 f_Normal; in vec2 f_TexCoord; in vec3 f_Pos; // fragment position uniform vec3 cameraPos; uniform sampler2D diffuse_map; uniform samplerCube skybox; void main() { vec3 I = normalize(f_Pos - cameraPos); // this is not wi, wi = I - P vec3 R = reflect(I, normalize(f_Normal)); // get reflect dir vec4 reflectEnv = vec4(texture(skybox, R).rgb,1.0f); // sample reflect box vec4 df = texture(diffuse_map, f_TexCoord); FragColor = df*0.8 + reflectEnv*0.4f; }
#version 450 core // INCOMING DATA layout ( location = 0 ) in vec4 v_position; // pos layout ( location = 1 ) in vec2 v_texCoord; // st layout ( location = 2 ) in vec3 v_normal; // st // define out data out vec2 f_TexCoord; // normal at world matrix, we direct from C++ calcalation out vec3 f_Normal; // to world matrix : mat3( transpose(inverse(model)) ) * v_normal; out vec3 f_Pos; // INCOMING THE MATRIX FROM CLIENT to transform the gl point position uniform mat4 model; uniform mat4 view; uniform mat4 projection; void main(){ // Transform the world matrix to view matrix gl_Position = projection * view * model * v_position; f_Normal = mat3(transpose(inverse(model))) * v_normal; // f_Normal at world matrix f_TexCoord = v_texCoord; // out TexCoord f_Pos = vec3(model *v_position); // out fragment position }