当前位置:网站首页>[OpenGL] note 29 anti aliasing (MSAA)
[OpenGL] note 29 anti aliasing (MSAA)
2022-07-04 22:47:00 【ycrsw】
1. technological process
After the previous tutorial , At present, the rendered image has enough expressiveness , But there are still some flaws , For example, when our rendered image resolution cannot keep up with the screen resolution , Some serious jagged effects will appear on the edges of our rendered graphics :
natural , This effect is due to too few pixels sampled in the picture , Thus, there is an obvious “ Broken band ”:
that , Of course , He who breaks the bell must tie the bell , We can increase the number of samples , At present, the widely used anti aliasing method is also multi sampling MSAA, The principle of this method is very simple , It is to divide each sampled pixel into four pixels for sampling calculation , Finally, average the results :
2. Realization
2.1 Increase the frame buffer
stay 【OpenGL】 Note 23 、 Frame buffer in , I reduce the number of samples in the custom frame buffer , Finally, restore to the normal viewport to complete a mosaic wind effect :
So the same , According to the above MSAA principle , I can also increase the number of samples in the custom frame buffer , Finally, restore the viewport size ( Among them, there is the function of automatic averaging ) To complete the anti aliasing effect ( With 4X4 sampling , Take off screen rendering as an example ):
First, increase the viewport before each rendering :
while (!glfwWindowShouldClose(window))
{
glViewport(0, 0, 800 * 4, 600 * 4);// Increase viewport , Bind custom frame buffer
glBindFramebuffer(GL_FRAMEBUFFER, screen->framebuffer);
...
// Render the scene
...
screen->Draw(screenShader);// Render frame buffer
glfwSwapBuffers(window);
glfwPollEvents();
}
Then, when initializing the custom frame buffer, increase the texture and render object attachments proportionally
void setup() {
glGenVertexArrays(1, &quadVAO);
glGenBuffers(1, &quadVBO);
glBindVertexArray(quadVAO);
glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
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)));
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glGenTextures(1, &textureColorbuffer);
glBindTexture(GL_TEXTURE_2D, textureColorbuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 800 * 4, 600 * 4, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);// Increase texture attachment
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);
glGenRenderbuffers(1, &rbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 800 * 4, 600 * 4);// Increase the render buffer object
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << endl;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
Finally, restore the viewport size before rendering our frame buffer :
void Draw(Shader& shader) {
glViewport(0, 0, 800, 600);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDisable(GL_DEPTH_TEST);
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
shader.use();
shader.setInt("screenTexture", 0);
glActiveTexture(GL_TEXTURE0);
glBindVertexArray(quadVAO);
glBindTexture(GL_TEXTURE_2D, textureColorbuffer); // use the color attachment texture as the texture of the quad plane
glDrawArrays(GL_TRIANGLES, 0, 6);
}
Effect comparison before and after :
It can be seen that the actual effect is good , But from my own point of view, the number of rendered frames has decreased a lot , Is there a more efficient way ? Of course
2.2 OpenGL Bring their own MSAA
OpenGL It has its own MSAA function , Its use is also very convenient :
First call before creating the window glfwWindowHint To create a multisampling buffer :
glfwWindowHint(GLFW_SAMPLES, 16);
The second parameter is our number of samples , Sample each pixel 16 One is actually 4X4 Sampling of
Next, we can turn on the multi sampling function before rendering as before :
glEnable(GL_MULTISAMPLE);
You can see , The effect is even better than our last one , Even the number of frames is higher , But this method has a drawback , That is, it cannot be used in off screen rendering , It means that this is invalid when leaving the screen , So how can we better complete the anti aliasing function under the premise of off screen rendering ?
2.3 Off screen MSAA
Actually, off screen MSAA Not many new operations , And before 【OpenGL】 Note 23 、 Frame buffer What is said in is similar , It's just when we bind the texture attachment of the custom buffer and render the buffer object , Changed the function and texture type of partial calls :
glGenTextures(1, &textureColorbuffer);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, textureColorbuffer);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGB, 800, 600, GL_TRUE);// Multisampling texture attachment
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, textureColorbuffer, 0);
unsigned int rbo;
glGenRenderbuffers(1, &rbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, 800, 600);// Multisampling render buffer objects
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
But multisampling buffering is a little special , We can't directly use their buffered images for other operations , For example, sampling them in shaders .
A multisampled image contains more information than an ordinary image , All we have to do is shrink or restore (Resolve) Images . The restoration of multisampling frame buffer is usually through glBlitFramebuffer To complete , It can copy an area in one frame buffer to another frame buffer , And restore the multisampling buffer .
void Draw(Shader& shader) {
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, 800, 600, 0, 0, 800, 600, GL_COLOR_BUFFER_BIT, GL_NEAREST);
// 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 necessary actually, since we won't be able to see behind the quad anyways)
glClear(GL_COLOR_BUFFER_BIT);
shader.use();
shader.setInt("screenTexture", 0);
glActiveTexture(GL_TEXTURE0);
glBindVertexArray(quadVAO);
glBindTexture(GL_TEXTURE_2D, textureColorbuffer); // use the color attachment texture as the texture of the quad plane
glDrawArrays(GL_TRIANGLES, 0, 6);
}
The result is right , But there's a problem , What if we want to use the texture output of multi sampling frame buffer to do things like post-processing ? We cannot use multisampled textures directly in fragment shaders . But what we can do is to transfer the multisampling buffer bit block to a file that does not use the multisampling texture attachment FBO in . Then use this ordinary color attachment for post-processing , So as to achieve our goal . However , This also means that we need to generate a new FBO, As an intermediate frame buffer object , Restore the multisampling buffer to a normal one that can be used in shaders 2D texture .
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
// create a color attachment texture
glGenTextures(1, &screenTexture);
glBindTexture(GL_TEXTURE_2D, screenTexture);
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, screenTexture, 0);
Then we copy the original buffer into the new buffer when rendering , And change the binding texture to this new texture :
void Draw(Shader& shader) {
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
glBlitFramebuffer(0, 0, 800, 600, 0, 0, 800, 600, GL_COLOR_BUFFER_BIT, GL_NEAREST);
// 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 necessary actually, since we won't be able to see behind the quad anyways)
glClear(GL_COLOR_BUFFER_BIT);
shader.use();
shader.setInt("screenTexture", 0);
glActiveTexture(GL_TEXTURE0);
glBindVertexArray(quadVAO);
glBindTexture(GL_TEXTURE_2D, screenTexture); // use the color attachment texture as the texture of the quad plane
glDrawArrays(GL_TRIANGLES, 0, 6);
}
In this way, we can post process the multi sampled texture in the shader , For example, the following gray image processing :
2.4 Custom anti aliasing
It is also feasible to pass a multi sampled texture image directly into the shader without restoring .GLSL Provides such options , Let's sample each sub sample of the texture image , So we can create our own anti aliasing algorithm . This is usually done in large graphics applications .
To get the color value of each sub sample , You need to put the texture uniform The sampler is set to sampler2DMS, Instead of the usual sampler2D:
uniform sampler2DMS screenTextureMS;
Use texelFetch Function can get the color value of each sub sample :
vec4 colorSample = texelFetch(screenTextureMS, TexCoords, 3); // The first 4 Subsample
边栏推荐
- Redis sentinel simply looks at the trade-offs between distributed high availability and consistency
- Detailed explanation of heap sort code
- leetcode 72. Edit Distance 编辑距离(中等)
- [cooking record] - stir fried 1000 pieces of green pepper
- Jvm-Sandbox-Repeater的部署
- NFT Insider #64:电商巨头eBay提交NFT相关商标申请,毕马威将在Web3和元宇宙中投入3000万美元
- Recommendation of mobile app for making barcode
- SPSS安装激活教程(包含网盘链接)
- 2022-07-04: what is the output of the following go language code? A:true; B:false; C: Compilation error. package main import “fmt“ func main() { fmt.Pri
- Unity-VScode-Emmylua配置报错解决
猜你喜欢
Logo special training camp section III initial creative techniques
Naacl-22 | introduce the setting of migration learning on the prompt based text generation task
攻防世界 MISC 进阶区 hit-the-core
Domestic database chaos
Logo special training camp Section V font structure and common design techniques
Serial port data frame
质量体系建设之路的分分合合
Wake up day, how do I step by step towards the road of software testing
Attack and defense world misc advanced area Hong
攻防世界 MISC 进阶 glance-50
随机推荐
LOGO特训营 第三节 首字母创意手法
LOGO special training camp section I identification logo and Logo Design Ideas
LOGO特训营 第一节 鉴别Logo与Logo设计思路
Business is too busy. Is there really no reason to have time for automation?
【OpenGL】笔记二十九、抗锯齿(MSAA)
攻防世界 misc 高手进阶区 a_good_idea
都说软件测试很简单有手就行,但为何仍有这么多劝退的?
蓝队攻防演练中的三段作战
Now MySQL cdc2.1 is parsing the datetime class with a value of 0000-00-00 00:00:00
Taobao commodity review API interface (item_review get Taobao commodity review API interface), tmall commodity review API interface
POM in idea XML dependency cannot be imported
业务太忙,真的是没时间搞自动化理由吗?
繁華落盡、物是人非:個人站長該何去何從
Unity-VScode-Emmylua配置报错解决
串口数据帧
The sandbox has reached a cooperation with digital Hollywood to accelerate the economic development of creators through human resource development
9 - 类
Detailed explanation of flask context
Tla+ introductory tutorial (1): introduction to formal methods
页面关闭前,如何发送一个可靠请求