we can’t use our framebuffer yet because it is not complete. For a framebuffer to be complete the following requirements have to be satisfied:
• We have to attach at least one buffer (color, depth or stencil buffer).
• There should be at least one color attachment.
• All attachments should be complete as well (reserved memory).
• Each buffer should have the same number of samples.
Framebuffer Configuration:
// framebuffer configuration
// -------------------------
unsigned int framebuffer;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
// create a color attachment texture
unsigned int textureColorbuffer;
glGenTextures(1, &textureColorbuffer);
glBindTexture(GL_TEXTURE_2D, textureColorbuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SCR_WIDTH, SCR_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, textureColorbuffer, 0);
// create a renderbuffer object for depth and stencil attachment (we won't be sampling these)
unsigned int rbo;
glGenRenderbuffers(1, &rbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, SCR_WIDTH, SCR_HEIGHT); // 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);
1. 生成和绑定 1个 framebuffer
unsigned int framebuffer; glGenFramebuffers(1, &framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
2. 创建1个Texture,并绑定到 framebuffer的 color attachment上
// create a color attachment texture unsigned int textureColorbuffer; glGenTextures(1, &textureColorbuffer); glBindTexture(GL_TEXTURE_2D, textureColorbuffer); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SCR_WIDTH, SCR_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, textureColorbuffer, 0);
3. 创建1个renderbuffer object,并绑定到framebuffer的depth,stencil,attachment 上
unsigned int rbo; glGenRenderbuffers(1, &rbo); glBindRenderbuffer(GL_RENDERBUFFER, rbo); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, SCR_WIDTH, SCR_HEIGHT); // 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
注意:
Renderbuffer objects could provide some optimizations in your framebuffer projects, but it is important to realize when to use renderbuffer objects and when to use textures. The general rule is that if you never need to sample data from a specific buffer, it is wise to use a renderbuffer object for that specific buffer. If you need to someday sample data from a specific buffer like colors or depth values, you should use a texture attachment instead. Performance-wise it doesn’t have an enormous impact though.
4. 检查和解绑 framebuffer
// 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);
Render:
// render
// ------
// bind to framebuffer and draw scene as we normally would to color texture
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glEnable(GL_DEPTH_TEST); // enable depth testing (is disabled for rendering screen-space quad)
// make sure we clear the framebuffer's content
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
shader.use();
glm::mat4 model = glm::mat4(1.0f);
glm::mat4 view = camera.GetViewMatrix();
glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
shader.setMat4("view", view);
shader.setMat4("projection", projection);
// cubes
glBindVertexArray(cubeVAO);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, cubeTexture);
model = glm::translate(model, glm::vec3(-1.0f, 0.0f, -1.0f));
shader.setMat4("model", model);
glDrawArrays(GL_TRIANGLES, 0, 36);
model = glm::mat4(1.0f);
model = glm::translate(model, glm::vec3(2.0f, 0.0f, 0.0f));
shader.setMat4("model", model);
glDrawArrays(GL_TRIANGLES, 0, 36);
// floor
glBindVertexArray(planeVAO);
glBindTexture(GL_TEXTURE_2D, floorTexture);
shader.setMat4("model", glm::mat4(1.0f));
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
// now bind back to default framebuffer and draw a quad plane with the attached framebuffer color texture
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDisable(GL_DEPTH_TEST); // disable depth test so screen-space quad isn't discarded due to depth test.
// clear all relevant buffers
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();
glBindVertexArray(quadVAO);
glBindTexture(GL_TEXTURE_2D, textureColorbuffer); // use the color attachment texture as the texture of the quad plane
glDrawArrays(GL_TRIANGLES, 0, 6);
1. 绑定自定义的framebuffer,之后的渲染的东西都会出现在这个framebuffer上
// bind to framebuffer and draw scene as we normally would to color texture glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
2. 绑定完自定义的Framebuffer之后就开始渲染物体
glEnable(GL_DEPTH_TEST); // enable depth testing (is disabled for rendering screen-space quad) // make sure we clear the framebuffer's content glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); shader.use(); glm::mat4 model = glm::mat4(1.0f); glm::mat4 view = camera.GetViewMatrix(); glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f); shader.setMat4("view", view); shader.setMat4("projection", projection); // cubes glBindVertexArray(cubeVAO); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, cubeTexture); model = glm::translate(model, glm::vec3(-1.0f, 0.0f, -1.0f)); shader.setMat4("model", model); glDrawArrays(GL_TRIANGLES, 0, 36); model = glm::mat4(1.0f); model = glm::translate(model, glm::vec3(2.0f, 0.0f, 0.0f)); shader.setMat4("model", model); glDrawArrays(GL_TRIANGLES, 0, 36); // floor glBindVertexArray(planeVAO); glBindTexture(GL_TEXTURE_2D, floorTexture); shader.setMat4("model", glm::mat4(1.0f)); glDrawArrays(GL_TRIANGLES, 0, 6); glBindVertexArray(0);
3. 重新绑定默认的framebuffer,也就是自定义的framebuffer 解绑了,并且这个时候,渲染一个全屏的quad,把自定义的framebuffer 的 textureColorbuffer 纹理,直接传入到 这个全屏的quad shader中,直接渲染。
// now bind back to default framebuffer and draw a quad plane with the attached framebuffer color texture glBindFramebuffer(GL_FRAMEBUFFER, 0); glDisable(GL_DEPTH_TEST); // disable depth test so screen-space quad isn't discarded due to depth test. // clear all relevant buffers 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(); glBindVertexArray(quadVAO); glBindTexture(GL_TEXTURE_2D, textureColorbuffer); // use the color attachment texture as the texture of the quad plane glDrawArrays(GL_TRIANGLES, 0, 6);