- OPENGL8 - 抗锯齿 MSAA & Default Framebuffer & Postframebuffer
CP27抗锯齿:
方法1:最简单得就用GLFW: MSAA
glfwWindowHint(GLFW_SAMPLES, 4); glEnable(GL_MULTISAMPLE);
方法2:离屏MSAA
第一种是直接生成MultiSampled Framebuffer 直接拷贝到 default Framebuffer.
// // Created by admin on 2020/2/27. // #ifndef TRIANGLE_ALG_OGLHELPER_H #define TRIANGLE_ALG_OGLHELPER_H #include <iostream> #define GLEW_STATIC #include <GL/glew.h> namespace AlgebraMaster{ // --------------------- function declaration ---------------------------------------- // * create VAO and VBO, but not contain any data / void CreateGeometryBuffer(GLuint &VAO, GLuint &VBO); // * Create framebuffer that can attach a texture/ void CreateFrameBufferTextured(int width, int height, GLuint &framebufferID, GLuint &attachTextureID); // * create RenderBuffer object that can render depth, stent void CreateRenderBufferObject(int width, int height, GLuint &renderBufferID); // * Create multiSampled frame buffer that attached a texture / void CreateMultiSampledFrameBufferTextured(int width, int height, GLuint &framebufferID, GLuint &attachTextureID, int samples=4); // * Create multiSampled RenderBuffer / void CreateMultiSampledRenderBufferObject(int width, int height, GLuint &renderBufferID,int samples = 4); //* from src buffer to des buffer , if des buffer=0 , that copy to screen void CopyFrameBuffer(const GLuint &srcBufferID, const GLuint &desBufferID, int width, int height, bool copyDepth=false, bool copyStencil= false ); // --------------------- function declaration ---------------------------------------- // --------------------- function definition ---------------------------------------- void CreateGeometryBuffer(GLuint &VAO, GLuint &VBO){ glCreateVertexArrays(1, &VAO); glCreateBuffers(1,&VBO); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); } // create frame buffer that attached a texture void CreateFrameBufferTextured(int width, int height ,GLuint &framebufferID, GLuint &attachTextureID){ glGenFramebuffers(1, &framebufferID); glBindFramebuffer(GL_FRAMEBUFFER, framebufferID); glGenTextures(1, &attachTextureID); glBindTexture(GL_TEXTURE_2D, attachTextureID); 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, attachTextureID, 0); } // create render buffer that can render DEPTH/STENCIL void CreateRenderBufferObject(int width, int height, GLuint &renderBufferID) { glGenRenderbuffers(1, &renderBufferID); glBindRenderbuffer(GL_RENDERBUFFER, renderBufferID); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); // use a single renderbuffer object for both a depth AND stencil buffer. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderBufferID); // 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); } // a multi sampled frame buffer with a multi sampled texture void CreateMultiSampledFrameBufferTextured(int width, int height, GLuint &framebufferID, GLuint &attachTextureID, int samples){ glCreateFramebuffers(1,&framebufferID); glBindFramebuffer(GL_FRAMEBUFFER, framebufferID); glGenTextures(1,&attachTextureID); glBindTexture(GL_TEXTURE_2D_MULTISAMPLE,attachTextureID); glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE,samples,GL_RGB,width,height,GL_TRUE); glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0); glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D_MULTISAMPLE,attachTextureID,0); } // Multi sampled render buffer void CreateMultiSampledRenderBufferObject(int width, int height, GLuint &renderBufferID,int samples ){ glGenRenderbuffers(1, &renderBufferID); glBindRenderbuffer(GL_RENDERBUFFER, renderBufferID); glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL_DEPTH24_STENCIL8, width,height); glBindRenderbuffer(GL_RENDERBUFFER, 0); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderBufferID); // now actually attach it if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) cout << "ERROR::MULTI_FRAMEBUFFER:: Framebuffer is not complete!" << endl; glBindFramebuffer(GL_FRAMEBUFFER, 0); } //* from src buffer to des buffer , if des buffer=0 , that copy to screen void CopyFrameBuffer(const GLuint &srcBufferID, const GLuint &desBufferID, int width, int height, bool copyDepth, bool copyStencil ) { glBindFramebuffer(GL_READ_FRAMEBUFFER, srcBufferID); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, desBufferID); glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST); if (copyDepth) glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_DEPTH_BUFFER_BIT, GL_NEAREST); if (copyStencil) glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_STENCIL_BUFFER_BIT, GL_NEAREST); } // --------------------- function definition ---------------------------------------- } // end of namespace #endif //TRIANGLE_ALG_OGLHELPER_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 "ALG_DrawOriginGnomon.h" #include "ALG_DrawCube.h" #include <cmath> #include "ALG_Random.h" #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> using namespace AlgebraMaster; const unsigned int SRC_WIDTH = 1400; const unsigned int SRC_HEIGHT = 720; static GLuint cubeVAO,VBO; static GLuint lightVAO; //VBO stays the same; the vertices are the same for the light object which is also a 3D cube static LoadShader SurfaceShader; 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); static Scene scene; static DrawGrid grid; static DrawOriginGnomon gnomon; const int amount = 100; // framebuffer static GLuint multiFBO; static GLuint multiFBOTexture; static GLuint multiRBO; // PostProcessing Buffer static GLuint postFrameBufferID; void init(){ camera = new GLFWCamera; camera->pos.y = 0.5f; camera->pos.z = 2.0f; // GL depth zbuffer glEnable(GL_DEPTH_TEST); SurfaceShader.load("shaders/standard_surface/SurfaceShader.vert","shaders/standard_surface/SurfaceShader.frag"); scene.read("scene/scene.json"); scene.parseInitialize(); scene.parseModel(); scene.parseMats(); scene.parseAssignMats(); grid.initialize(); gnomon.initialize(); // Instance Array building: auto *modelMatrices = new glm::mat4[amount]; RandomN1P1 xPosSet(amount, 1); RandomN1P1 zPosSet(amount, 2); RandomN1P1 rotAmount(amount,3); Random01 scaleAmount(amount,4); //cout << scaleAmount <<endl; for(int i=0;i<amount;i++) { // new translate glm::mat4 model(1.0f); model = glm::translate(model,glm::vec3(xPosSet[i]*20, 0.0, zPosSet[i]*20 ) ); // new rot glm::mat4 rot(1.0f); rot = glm::rotate(rot,glm::radians(rotAmount[i]*360) , glm::vec3(0.0,1.0,0.0)); // R S T order glm::mat4 scale(1.0f); scale = glm::scale( scale,glm::vec3(scaleAmount[i]) ); modelMatrices[i] = model * scale * rot ; } //object share one mem buffer of instance unsigned int buffer; glCreateBuffers(1, &buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer); glBufferData(GL_ARRAY_BUFFER, amount * sizeof(glm::mat4), &modelMatrices[0], GL_STATIC_DRAW); for(auto &model: scene.allModels){ for(auto &loc: model->locations) { glBindVertexArray(loc->mesh->VAO); glEnableVertexAttribArray(10); glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)0); glEnableVertexAttribArray(11); glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(sizeof(glm::vec4))); glEnableVertexAttribArray(12); glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(2 * sizeof(glm::vec4))); glEnableVertexAttribArray(13); glVertexAttribPointer(13, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(3 * sizeof(glm::vec4))); glVertexAttribDivisor(10, 1); glVertexAttribDivisor(11, 1); glVertexAttribDivisor(12, 1); glVertexAttribDivisor(13, 1); glBindVertexArray(0); } } delete [] modelMatrices; const int samplers = 32; // Create MultiSampler Framebuffer with attached texture CreateMultiSampledFrameBufferTextured(SRC_WIDTH, SRC_HEIGHT, multiFBO, multiFBOTexture, samplers); // Create MultiSampler render buffer CreateMultiSampledRenderBufferObject(SRC_WIDTH, SRC_HEIGHT, multiRBO, samplers); } // object .vert settings // ----------- Render Loop ---------- void display(){ // per-frame time logic // -------------------- float currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; glm::mat4 view = camera->GetViewMatrix(); glm::mat4 projection = glm::perspective(glm::radians(camera->fov),float(SRC_WIDTH) / float(SRC_HEIGHT),0.1f, 1000.0f); // object world transformation glm::mat4 model = glm::mat4(1.0f); scene.setMatrix(projection,view,model); // 1. draw scene as normal in multisampled buffers glBindFramebuffer(GL_FRAMEBUFFER, multiFBO); glClearColor(0.1f, 0.2f, 0.4f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); for(auto &m: scene.allModels){ for(auto &loc: m->locations){ glBindVertexArray(loc->mesh->VAO); loc->mesh->shader.use(); loc->mesh->shader.setInt("useInstance", 1); loc->mesh->shader.setMatrix(model,view,projection); loc->mesh->allocateTextureChannelFromShader(loc->mesh->shader); //glDrawElements(GL_TRIANGLES, loc->mesh->indices.size(), GL_UNSIGNED_INT, 0); glDrawElementsInstanced(GL_TRIANGLES, loc->mesh->indices.size(), GL_UNSIGNED_INT, 0, amount); glBindVertexArray(0); } } grid.draw(projection,view); gnomon.draw(projection,view); // copy multi buffer to our default screen buffer CopyFrameBuffer(multiFBO,0,SRC_WIDTH,SRC_HEIGHT,true); } 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-------------- while(!glfwWindowShouldClose(FrameWindow.getWindow())){ processInput(FrameWindow.getWindow()); display(); glfwSwapBuffers(FrameWindow.getWindow()); glfwPollEvents(); } delete camera; 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); }
上面OGLHelper.h里有3个函数:
// a multi sampled frame buffer with a multi sampled texture void CreateMultiSampledFrameBufferTextured(int width, int height, GLuint &framebufferID, GLuint &attachTextureID, int samples){ glCreateFramebuffers(1,&framebufferID); glBindFramebuffer(GL_FRAMEBUFFER, framebufferID); glGenTextures(1,&attachTextureID); glBindTexture(GL_TEXTURE_2D_MULTISAMPLE,attachTextureID); glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE,samples,GL_RGB,width,height,GL_TRUE); glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0); glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D_MULTISAMPLE,attachTextureID,0); } // Multi sampled render buffer void CreateMultiSampledRenderBufferObject(int width, int height, GLuint &renderBufferID,int samples ){ glGenRenderbuffers(1, &renderBufferID); glBindRenderbuffer(GL_RENDERBUFFER, renderBufferID); glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL_DEPTH24_STENCIL8, width,height); glBindRenderbuffer(GL_RENDERBUFFER, 0); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderBufferID); // now actually attach it if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) cout << "ERROR::MULTI_FRAMEBUFFER:: Framebuffer is not complete!" << endl; glBindFramebuffer(GL_FRAMEBUFFER, 0); } //* from src buffer to des buffer , if des buffer=0 , that copy to screen void CopyFrameBuffer(const GLuint &srcBufferID, const GLuint &desBufferID, int width, int height, bool copyDepth, bool copyStencil ) { glBindFramebuffer(GL_READ_FRAMEBUFFER, srcBufferID); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, desBufferID); glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST); if (copyDepth) glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_DEPTH_BUFFER_BIT, GL_NEAREST); if (copyStencil) glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_STENCIL_BUFFER_BIT, GL_NEAREST); }
所以main中逻辑就是:
void init() { ... // Create MultiSampler Framebuffer with attached texture CreateMultiSampledFrameBufferTextured(SRC_WIDTH, SRC_HEIGHT, multiFBO, multiFBOTexture, samplers); // Create MultiSampler render buffer CreateMultiSampledRenderBufferObject(SRC_WIDTH, SRC_HEIGHT, multiRBO, samplers); } void display(){ // 1. draw scene as normal in multisampled buffers glBindFramebuffer(GL_FRAMEBUFFER, multiFBO); glClearColor(0.1f, 0.2f, 0.4f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); // RenderYour Objs......... // copy multi buffer to our default screen buffer CopyFrameBuffer(multiFBO,0,SRC_WIDTH,SRC_HEIGHT,true); }
这种情况下的材质是没改变的。
如果要改变成 自定义多采样材质算法,参考https://www.cnblogs.com/chandler00x/p/3888139.html
注意这样对拷有个问题,是因为直接从MultiSampledBuffer->DefaultSampledBuffer.会导致屏幕放大,并没有适配。
但是下面的带有PostProcessingBuffer不会。
第二种带有Post processing的framebuffer
两幅图来展示:
注意第二幅图中间copy的过程,glBlitFrameBuffer()我没有copy depth, copy stencil, 因为这个imtermediateFBO 是一个only color attached texture buffer.
// // Created by admin on 2020/3/9. // #ifndef TRIANGLE_ALG_DRAWPOSTPOCESSINGQUAD_H #define TRIANGLE_ALG_DRAWPOSTPOCESSINGQUAD_H #include "ALG_LoadShader.h" #include "ALG_OGLHelper.h" namespace AlgebraMaster{ static float __postQuadVertices__[] = { // 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 }; class DrawPostProcessingQuad{ public: void initialize(){ glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(__postQuadVertices__), &__postQuadVertices__, GL_STATIC_DRAW); // pos 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))); shader.fromSrc(vertexShaderSource,fragmentShaderSource); CreateFrameBufferTextured(mWidth,mHeight,FBO,FBOTexture); } void setupWidthHeight(int width,int height){ mWidth = width; mHeight = height; } void draw(){ shader.use(); glBindVertexArray(VAO); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D,FBOTexture ); // use the now resolved color attachment as the quad's texture glDrawArrays(GL_TRIANGLES, 0, 6); } const char* fragmentShaderSource = "#version 450 core\n" "out vec4 FragColor;\n" "in vec2 TexCoords;\n" "uniform sampler2D screenTexture;\n" "void main()\n" "{\n" "vec3 col = texture(screenTexture, TexCoords).rgb;\n" "float grayscale = 0.2126 * col.r + 0.7152 * col.g + 0.0722 * col.b;\n" "FragColor = vec4(vec3(grayscale), 1.0);\n" "}\n\0"; const char* vertexShaderSource = "#version 450 core\n" "layout (location = 0) in vec2 aPos;\n" "layout (location = 1) in vec2 aTexCoords;\n" "out vec2 TexCoords;\n" "void main()\n" "{\n" "TexCoords = aTexCoords;\n" "gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0);\n" "}\n\0"; unsigned int VAO,VBO,FBO,FBOTexture; LoadShader shader; int mWidth; int mHeight; }; } #endif //TRIANGLE_ALG_DRAWPOSTPOCESSINGQUAD_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 "ALG_DrawOriginGnomon.h" #include "ALG_DrawCube.h" #include "ALG_DrawPostPocessingQuad.h" #include <cmath> #include "ALG_Random.h" #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> using namespace AlgebraMaster; const unsigned int SRC_WIDTH = 1400; const unsigned int SRC_HEIGHT = 720; static GLuint cubeVAO,VBO; static GLuint lightVAO; //VBO stays the same; the vertices are the same for the light object which is also a 3D cube static LoadShader SurfaceShader; 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); static Scene scene; static DrawGrid grid; static DrawOriginGnomon gnomon; static DrawPostProcessingQuad quad; const int amount = 100; // framebuffer static GLuint multiFBO; static GLuint multiFBOTexture; static GLuint multiRBO; // PostProcessing Buffer void init(){ camera = new GLFWCamera; camera->pos.y = 0.5f; camera->pos.z = 2.0f; // GL depth zbuffer glEnable(GL_DEPTH_TEST); SurfaceShader.load("shaders/standard_surface/SurfaceShader.vert","shaders/standard_surface/SurfaceShader.frag"); scene.read("scene/scene.json"); scene.parseInitialize(); scene.parseModel(); scene.parseMats(); scene.parseAssignMats(); grid.initialize(); gnomon.initialize(); quad.setupWidthHeight(SRC_WIDTH,SRC_HEIGHT); quad.initialize(); // Instance Array building: auto *modelMatrices = new glm::mat4[amount]; RandomN1P1 xPosSet(amount, 1); RandomN1P1 zPosSet(amount, 2); RandomN1P1 rotAmount(amount,3); Random01 scaleAmount(amount,4); //cout << scaleAmount <<endl; for(int i=0;i<amount;i++) { // new translate glm::mat4 model(1.0f); model = glm::translate(model,glm::vec3(xPosSet[i]*20, 0.0, zPosSet[i]*20 ) ); // new rot glm::mat4 rot(1.0f); rot = glm::rotate(rot,glm::radians(rotAmount[i]*360) , glm::vec3(0.0,1.0,0.0)); // R S T order glm::mat4 scale(1.0f); scale = glm::scale( scale,glm::vec3(scaleAmount[i]) ); modelMatrices[i] = model * scale * rot ; } //object share one mem buffer of instance unsigned int buffer; glCreateBuffers(1, &buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer); glBufferData(GL_ARRAY_BUFFER, amount * sizeof(glm::mat4), &modelMatrices[0], GL_STATIC_DRAW); for(auto &model: scene.allModels){ for(auto &loc: model->locations) { glBindVertexArray(loc->mesh->VAO); glEnableVertexAttribArray(10); glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)0); glEnableVertexAttribArray(11); glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(sizeof(glm::vec4))); glEnableVertexAttribArray(12); glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(2 * sizeof(glm::vec4))); glEnableVertexAttribArray(13); glVertexAttribPointer(13, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(3 * sizeof(glm::vec4))); glVertexAttribDivisor(10, 1); glVertexAttribDivisor(11, 1); glVertexAttribDivisor(12, 1); glVertexAttribDivisor(13, 1); glBindVertexArray(0); } } delete [] modelMatrices; const int samplers = 1; // Create MultiSampler Framebuffer with attached texture CreateMultiSampledFrameBufferTextured(SRC_WIDTH, SRC_HEIGHT, multiFBO, multiFBOTexture, samplers); // Create MultiSampler render buffer CreateMultiSampledRenderBufferObject(SRC_WIDTH, SRC_HEIGHT, multiRBO, samplers); // FBO } // object .vert settings // ----------- Render Loop ---------- void display(){ // per-frame time logic // -------------------- float currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; // render // ------ glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 1. draw scene as normal in multisampled buffers glBindFramebuffer(GL_FRAMEBUFFER, multiFBO); glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); glm::mat4 view = camera->GetViewMatrix(); glm::mat4 projection = glm::perspective(glm::radians(camera->fov),float(SRC_WIDTH) / float(SRC_HEIGHT),0.1f, 1000.0f); // object world transformation glm::mat4 model = glm::mat4(1.0f); scene.setMatrix(projection,view,model); for(auto &m: scene.allModels){ for(auto &loc: m->locations){ glBindVertexArray(loc->mesh->VAO); loc->mesh->shader.use(); loc->mesh->shader.setInt("useInstance", 1); loc->mesh->shader.setMatrix(model,view,projection); loc->mesh->allocateTextureChannelFromShader(loc->mesh->shader); //glDrawElements(GL_TRIANGLES, loc->mesh->indices.size(), GL_UNSIGNED_INT, 0); glDrawElementsInstanced(GL_TRIANGLES, loc->mesh->indices.size(), GL_UNSIGNED_INT, 0, amount); glBindVertexArray(0); } } grid.draw(projection,view); gnomon.draw(projection,view); // copy multi buffer to our default screen buffer CopyFrameBuffer(multiFBO,quad.FBO,SRC_WIDTH,SRC_HEIGHT); glBindFramebuffer(GL_FRAMEBUFFER, 0); glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); quad.draw(); } 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-------------- while(!glfwWindowShouldClose(FrameWindow.getWindow())){ processInput(FrameWindow.getWindow()); display(); glfwSwapBuffers(FrameWindow.getWindow()); glfwPollEvents(); } delete camera; 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); }
可以看到main中最后使用了一个Renderbuffer.方法就是从MultiSampledBuffer->PostProcessingBuffer
// copy multi buffer to our default screen buffer ...... CopyFrameBuffer(multiFBO,quad.FBO,SRC_WIDTH,SRC_HEIGHT); glBindFramebuffer(GL_FRAMEBUFFER, 0); glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); quad.draw();