GPU deep mining (II): OpenGL framebuffer object 101 Author: by Rob 'phantom '; Jones Translator: 文 updated: 2007/6/1 Introduction Frame Buffer object (FBO) extension, which is recommended for rendering data to a texture object. Compared with other similar technologies, such as data copy or swap buffer, using FBO technology is more efficient and easier to implement. In this article, I will quickly explain how to use this extension, and introduce some things we should pay attention to during use. After learning this technology, you can add some render to texture functions to your program for faster running. CreateLike other objects in OpenGL, such as texture objects, Pixel Buffer objects, and vertex buffer objects, before using an FBO object, you must first generate the object and obtain a valid Object ID. GLuint fbo; glGenFramebuffersEXT(1, &fbo);
To perform any operations on an FBO, you must first bind it. This step is similar to the VBO or texture process. After binding the object, we can perform various operations on FBO. The following Code demonstrates how to bind the object. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
The first parameter is "target", which indicates the frame buffer to which you want to bind the FBO to. Currently, my parameters only have some predefined options (gl_framebuffer_ext). However, in the future, the expansion may come with other options, allowing you to bind FBO to other targets. Integer variableFBO,Is used to save the FBO Object ID, which we have generated before. To implement any FBO-related operations, we must bind an FBO. Otherwise, an error will occur during the call. |
Add a depth buffer) A fbo is actually useless. To make it more usable, We need to bind it with some buffer zones that can be rendered, this buffer can be a texture, or we will introduce it below.Rendering Buffer(Renderbuffers). OneRendering BufferIt is actually a buffer zone that supports off-screen rendering. It is usually a part of the frame buffer, and generally does not have a texture format. Common Template buffering and deep buffering are such a type of object. Here, we need to specifyRendering Buffer.In this way, when we render thisRendering BufferIt is used as a deep cache of FBO. Like FBO generationRendering BufferSpecify a valid ID. GLuint depthbuffer; glGenRenderbuffersEXT(1, &depthbuffer);
After completing the preceding step, we need to bind the buffer to make it the current Rendering Buffer. The following is the implementation code. glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthbuffer);
Like the FBO binding function, the first parameter is "target", which indicates which target you want to bind to. Currently, it can only be a predefined target. VariableDephtbufferUsed to save the Object ID. There is a key point here, that is, the Rendering Buffer object we generated, which itself does not automatically allocate memory space. Therefore, we need to call the OpenGL function to allocate a specified size of memory space to it. Here, we allocate a fixed size of depth easing space. glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height);
After the above function is successfully run, OpenGL will assign us a depth buffer with the size of width x height. Note that gl_depth_component is used here, which means that our space is used to save the depth value, but apart from this,Rendering BufferIt can also be used to save Normal RGB/rgba format data or template buffer information. After the video memory space is quasi-cached in depth, the next task is to bind it with the FBO image we have prepared earlier. Glframebufferrenderbufferext (gl_framebuffer_ext, gl_depth_attachment_ext, gl_renderbuffer_ext, depthbuffer );
This function looks a little complicated, but it is actually quite understandable. All it has to do is to bind the deep cache object we generated earlier to the current FBO object. Of course, note that a FBO has multiple binding points, this is to be bound to the FBO depth buffer binding point. |
Add texture for rendering So far, we have no way to write color information to FBO. This is what we will discuss next. We have two ways to implement it:
- Bind a Color Rendering Buffer to FBO.
- Bind a texture to FBO.
The former will be used in some places, and we will discuss it in detail in later chapters. Now let's talk about the second method. Before you bind a texture to a FBO, you must first generate the texture. The texture generation process is similar to the texture generation we usually see. Gluint IMG; Glgentextures (1, & IMG ); Glbindtexture (gl_texture_2d, IMG ); Glteximage2d (gl_texture_2d, 0, gl_rgba8, width, height, 0, gl_rgba, gl_unsigned_byte, null );
In this example, we generate a normal rgba image with the size of width x height, which is the same as the size of the previously generated Rendering Buffer, which is very important, that is, all bound objects in FBO must have the same width and height. Note that we have not uploaded any data here, but we will use OpenGL to reserve the allocated space. After the texture is generated, the next step is to bind the texture with FBO so that we can render the data into the texture space. Glframebuffertexture2dext (gl_framebuffer_ext, gl_color_attachment0_ext, gl_texture_2d, IMG, 0 );
Again, we can see this terrible function. Of course, it is not as hard to understand as we think. The gl_color_attachment0_ext parameter tells OpenGL to bind the texture object to the 0 binding point of FBO (a fbo can bind multiple color buffers at the same time, each binding point corresponding to the FBO). The gl_texture_2d parameter specifies the texture format. The IMG saves the texture identifier and points to a previously prepared texture object. Texture can be a multi- ing image. The last parameter specifies that the level is 0, indicating that the original image is used. The last step is to check whether all FBO preparation is complete and whether it can be used properly. This test is completed by the following function. It returns the status information of the currently bound FBO. Glenum status = glcheckframebufferstatusext (gl_framebuffer_ext );
If all work is done, the returned status value isGl_framebuffer_complete_extThat is to say, your FBO is ready and can be used as a rendering object. Otherwise, an error code will be returned. You can find the relevant error information through the definition document, so that the error is generated in which step. |
Rendering to texture All the difficult work is to build the FBO environment. The rest of the work is quite simple. The related thing is to call the following function: glbindframebufferext (). When we want to render the data and output it to FBO, we only need to use this function to bind an FBO object. To stop output to FBO, set the parameter to 0 and call the function again. Of course, it is also important to stop outputting data to FBO. After FBO is finished, we must stop FBO so that the image can be correctly output on the screen. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); glPushAttrib(GL_VIEWPORT_BIT); glViewport(0,0,width, height);
// Render as normal here // output goes to the FBO and it's attached buffers
glPopAttrib(); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
The above three lines of code glpushattrib/glpopattrib and glviewport are used to ensure that the original normal rendering path can be returned when you exit FBO rendering. The call of glviewport is necessary here. We should not try to render the data to an area larger than or smaller than the FBO size. The glpushatrrib and glpopattrib functions are used to quickly save the view information. This step is also necessary because FBO shares all the information of the main context. Any change will affect both the FBO and the main context, and of course it will directly affect your normal screen rendering. Here is an important piece of information. You may also notice that we only bind or unbind FBO during painting, but we did not re-bind the texture or rendering buffer, this is because this binding relationship is always saved in FBO, unless you want to separate them or the FBO object is destroyed. |
Use rendered textures Here, we have rendered the screen data to an image texture. Now let's take a look at how to use this rendered image texture. This operation is actually very simple. We only need to bind the image texture to the current texture as a normal texture. glBindTexture(GL_TEXTURE_2D, img);
After this function is called, the image texture becomes a common texture used for reading during plotting. Depending on the different texture filtering methods you specified during initialization, you may want to generate multi-image (mipmap) information for the texture. If you want to create multiple images, most people upload texture data by calling the glubuild2dmipmaps () function, of course, some may know how to use the extension that automatically generates multiple images, but in the FBO extension, we added the third method for generating images, that is, using the generatemipmapext () function. This function enables OpenGL to help you automatically create multiple image information. The intermediate implementation process varies with different video cards. We only care that their final results are the same. It is worth noting that only this method is correct when multiple images are required for this texture rendered by FBO, here, you cannot use the auto-generated function to generate multiple images. There are many reasons for this. For more information, see the technical documentation. To use this function, you need to bind the texture object to the current texture and call this function once. glGenerateMipmapEXT(GL_TEXTURE_2D); OpenGL will automatically generate all required information for us, and now our texture can be used normally. Note: If you plan to use multiple images (such as gl_linear_mipmap_linear), The glgeneratemipmapext () function must be called before rendering to the texture. When creating a texture, we can follow the code below. glGenTextures(1, &img);glBindTexture(GL_TEXTURE_2D, img);glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);glGenerateMipmapEXT(GL_TEXTURE_2D); Up to now, this texture is no different from a normal texture, so we can use it by processing the normal texture. |
Clear Finally, after you complete all the FBO operations, do not forget to clear or delete the unwanted FBO images, which are similar to the texture object cleanup, this step can be completed with the following function: glDeleteFramebuffersEXT(1, &fbo);
Similarly, if you allocate a rendering buffer to the image, do not forget to clear it. In this example, we allocate a deep cache rendering object. We use the following function to clear it: glDeleteRenderbuffersEXT(1, &depthbuffer); By now, all FBO objects and rendering buffers are released, and our cleaning is complete. Last thoughtThis article is only a preliminary introduction to FBO extensions. For more information, see FBO Spec or 《More OpenGL game programmingThis chapter describes the Extended parts. You can log on to the gpgpu/Cuda Forum of the physical development network to discuss the problem and related technologies. Before the end of this document, I would like to talk about some points worth our attention when using FBO to write programs:
- For the moment, you cannot get the binding point of the template buffer. Although the texture format of such a deep template is defined technically, it is designed to render the template, but this technology still lacks hardware support so far.
- Do not create and destroy FBO images frequently. A good practice should be to generate an FBO object while creating the program, and then use it where we need it.
- If a texture is defined as used for rendering a texture, we should try to avoid using functions such as glteximage to modify the texture data, in most cases, this will cause problems in your program.
Notes in the sample program in this articleAccording to the content discussed in this article, we have written a corresponding program. Its function is to add a deep buffer object and a texture object to FBO. We found that there is a bug in the ATI Video Card, that is, when we add a deep buffer and a texture to the FBO at the same time, there will be a serious conflict. It also tells us that when we write a FBO-related program, we must perform extensive tests on different hardware and drivers, until there are no rendering problems. I 'd also like to put out a big thanks to Rick Appleton for helping me test out and debug the code on each da hardware, couldn't have done it without you mate This program requires the support of the glut function library to run correctly. I am using freeglut. Program download This translation can be freely reproduced and requires that the original author information be retained, and the article is from the physical development network: www.physdev.com ReferenceDeep GPU Exploration More OpenGL game programming Framebuffer object spec GDC 2005 framebuffer object PDF |