一个很好的FBO---RenderToTexture教程

来源:互联网 发布:手机广播软件 编辑:程序博客网 时间:2024/06/17 00:18

http://www.swiftless.com/tutorials/opengl/framebuffer.html

Introduction

Frame buffers are one of those mythical things that we have all heard of, but many beginner OpenGL developers avoid because there is not much information about them, and they can be confusing at first. A frame buffer can be thought of as another window that we render to, but we don’t end up seeing.

Now you might be thinking, if we draw something, but we don’t end up seeing it, then what is the point? Have you ever heard of off-screen rendering? I might ask you this instead, have you ever seen a reflection in a game of a live scene? Well, to get this reflection, we typically have to render the scene from the angle of the reflection first, and then we turn that render into a texture and bind it to whatever shape has the reflection attached to it. This initial rendering of the reflection is typically done in a frame buffer for speed, as we can bind a frame buffer straight to a texture.

If you have ever heard of pixel buffers, don’t get them confused with frame buffers, they are different, but can be used together. I won’t go into pixel buffers here, I might write a tutorial on them later on, but they are highly useful for asynchronous texture reads and writes. I once had a project, and part of it required I write to two frame buffers and read back the data, and then perform operations on this data and push it back to the GPU as a texture as quickly as possible. Using a combination of frame buffers and pixel buffers, I went from approximately 5 frames per second doing this, to 30 frames per second, and if the demand arises, I will post a tutorial on how to do this. It was a case where offloading the information to the GPU was not possible.

You should now have an idea of what frame buffers are, in short, they are a rendering context that can be bound to a texture, so let’s start coding them and see what we come up with. I am going to aim for a quad, with a texture of a rotating cube on it. It is a simple example, but highly useful, as you can imagine, the entire scene can be rendered into a frame buffer, and then placed onto a quad for some post processing.

Code

Frame buffer objects are stored like textures. OpenGL will store the information on the graphics card, and it will return an ID associated with that texture for us to place inside an unsigned integer. Also, as seen with textures, the frame buffer ID of 0 (zero) is reserved by OpenGL and is used to unbind the current frame buffer. Also, frame buffers can have several buffers attached. The default buffer is the colour buffer, but you can also bind depth buffers, stencil buffers, etc. So let’s create some variables to hold our frame buffer, frame buffers depth buffer and the texture we are going to store our frame buffer in.

view plaincopy to clipboardprint?
  1. unsigned int fbo; // The frame buffer object  
  2. unsigned int fbo_depth; // The depth buffer for the frame buffer object  
  3. unsigned int fbo_texture; // The texture object to write our frame buffer object to  

After we have all the variables required to create and use our frame buffers (yes, we only need three variables), we are going to add some extra variables. First, we need two integer values for the width and height of our GLUT window, this is because when you create a frame buffer, you need to specify the width and the height of the texture, and when you use the frame buffer, you need to change the viewport size to match the texture size. Because frame buffers are independent of the size of the GLUT window, you can use them to create higher or lower resolution textures than your regular scene. Typically you would use a lower resolution texture for effects such as reflections so that it renders quicker. The last extra variable we are going to use will just hold how much our teapot in our frame buffer scene will rotate.

view plaincopy to clipboardprint?
  1. int window_width = 500; // The width of our window  
  2. int window_height = 500; // The height of our window  
  3.   
  4. float rotation_degree = 0.0f; // The angle of rotation in degrees for our teapot  

The next step we have to do is to create/initialize our frame buffer, the associated depth buffer, and the texture we are going to render to. Typically it is done in the following order:

  1. Create the Depth Buffer that we are going to use with our frame buffer.
  2. Create the Texture that we are going to bind our frame buffer to.
  3. Create the actual Frame Buffer.
  4. Bind the texture to the frame buffer.
  5. Bind the depth buffer to the frame buffer.
  6. Check for errors.

You can check for errors along the way if you wish, but I will just be using one check to make sure our final frame buffer is complete.

Frame Buffer – Depth Buffer

Let’s create the depth buffer we are going to use. To begin with, create a method call initFrameBufferDepthBuffer. This method is going to take no parameters and is not going to return anything. This method is going to contain all code related to the depth buffer we are going to use.

view plaincopy to clipboardprint?
  1. void initFrameBufferDepthBuffer(void) {  
  2.   
  3. }  

Inside of this method to create the depth buffer, the first call we need to make will create a render buffer for OpenGL to use, and is very similar to the code used to create textures.

view plaincopy to clipboardprint?
  1. glGenRenderbuffersEXT(1, &fbo_depth); // Generate one render buffer and store the ID in fbo_depth  

This will create a render buffer, and store the ID in our fbo_depth variable for us to access.  Once the render buffer is created for the depth buffer, we then need to bind the buffer so that we can play with it and once we are finished with it, we need to bind the null render buffer, which takes the value of 0. When we are binding a frame buffer, it is once again very similar to texturing, so let’s place our binding code inside our method to fill between.

view plaincopy to clipboardprint?
  1. void initFrameBufferDepthBuffer(void) {  
  2. glGenRenderbuffersEXT(1, &fbo_depth); // Generate one render buffer and store the ID in fbo_depth  
  3. glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo_depth); // Bind the fbo_depth render buffer  
  4. ...  
  5. glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); // Unbind the render buffer  
  6. }  

Next, we need to fill in the … between the binding of the render buffers. These next two lines are the lines that tell OpenGL that this render buffer will be used for depth. The first line tells OpenGL that we are going to be storing the depth component, and we are going to monitor the entire size of the window. The next line then says that we are going to use fbo_depth to render the depth buffer/attachment.

view plaincopy to clipboardprint?
  1. glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, window_width, window_height); // Set the render buffer storage to be a depth component, with a width and height of the window  
  2.   
  3. glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo_depth); // Set the render buffer of this buffer to the depth buffer  

Frame Buffer – Texture

Recapping on what we have done, we have created a render buffer that will store the depth component of the buffer that it is attached to. Now we need to create the texture that we want to store our frame buffer in. To do this, let’s create another method similar to the one we just created, but I am going to call this one initFrameBufferTexture. Because we are only creating a texture here, I am not really going to explain this code, the code comments should outline what is going on if you don’t know about texturing in OpenGL (in which case, you are diving in fairly deep straight out).

view plaincopy to clipboardprint?
  1. void initFrameBufferTexture(void) {  
  2. glGenTextures(1, &fbo_texture); // Generate one texture  
  3.   
  4. glBindTexture(GL_TEXTURE_2D, fbo_texture); // Bind the texture fbo_texture  
  5.   
  6. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, window_width, window_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); // Create a standard texture with the width and height of our window  
  7.   
  8. // Setup the basic texture parameters  
  9.   
  10. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);  
  11. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);  
  12. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);  
  13. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);  
  14.   
  15. // Unbind the texture  
  16. glBindTexture(GL_TEXTURE_2D, 0);  
  17. }  

Frame Buffer – Initialization

Finally, we need one more method; this one will be called initFrameBuffer and will make calls to the above methods we have created, as well as creating the frame buffer and attaching the texture and the depth buffer.

view plaincopy to clipboardprint?
  1. void initFrameBuffer(void) {  
  2. initFrameBufferDepthBuffer(); // Initialize our frame buffer depth buffer  
  3.   
  4. initFrameBufferTexture(); // Initialize our frame buffer texture  
  5. …  
  6. }  

After making the calls to our above methods, we need to create the frame buffer, and bind it. This is extremely similar to how we created the render buffer for the depth component, and how we create textures, so the following should look vaguely familiar.

view plaincopy to clipboardprint?
  1. glGenFramebuffersEXT(1, &fbo); // Generate one frame buffer and store the ID in fbo  
  2. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); // Bind our frame buffer  
  3. …  
  4. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // Unbind our frame buffer  

This code will generate one frame buffer, and then bind it so we can modify it, and then finally it will unbind it. This is fairly straight forward, and the next two calls will attach the texture and render buffer to our frame buffer. First off, let’s attach the texture to the frame buffer.

view plaincopy to clipboardprint?
  1. glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, fbo_texture, 0); // Attach the texture fbo_texture to the color buffer in our frame buffer  

Now that we have a texture, theoretically we can use this straight out, but you won’t get any depth information. So we need to go ahead and attach the depth render buffer we created called fbo_depth, to our frame buffer.

view plaincopy to clipboardprint?
  1. glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo_depth); // Attach the depth buffer fbo_depth to our frame buffer  

And now we have a frame buffer, which outputs to a texture and also has a depth buffer, which we can use. Well, we think we do, so first let’s check if our frame buffer is complete and there were no problems. To do this, we can make a call to glCheckFramebufferStatusEXT while our frame buffer is bound, and this will give us back a GLenum with the status of our frame buffer. For our frame buffer to be complete, we need to check that the status is equal to GL_FRAMEBUFFER_COMPLETE_EXT. We can do this with a simple if statement. Note that if you want the output to the console, you need to include <iostream> into your file.

view plaincopy to clipboardprint?
  1. GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); // Check that status of our generated frame buffer  
  2.   
  3. if (status != GL_FRAMEBUFFER_COMPLETE_EXT) // If the frame buffer does not report back as complete  
  4. {  
  5. std::cout << "Couldn't create frame buffer" << std::endl; // Make sure you include <iostream>  
  6. exit(0); // Exit the application  
  7. }  

General Initialization

Because in this example, we want to use the frame buffer constantly, I am going to create an init method which will call the initFrameBuffer method, and init will be called straight after we initialize GLEW, which is straight after we call glutCreateWindow. So here is our init method, which in this example, enables texturing, enables depth testing, and then initializes our frame buffer.

view plaincopy to clipboardprint?
  1. void init(void) {  
  2. glEnable(GL_TEXTURE_2D); // Enable texturing so we can bind our frame buffer texture  
  3. glEnable(GL_DEPTH_TEST); // Enable depth testing  
  4.   
  5. initFrameBuffer(); // Create our frame buffer object  
  6. }  

Next up, here is an example of my main method, which calls glewInit and calls our own init method.

view plaincopy to clipboardprint?
  1. int main (int argc, char **argv) {  
  2. …  
  3. glutCreateWindow ("Your first OpenGL Window"); // Set the title for the window  
  4.   
  5. if (GLEW_OK != glewInit()) {  
  6. std::cout << "Couldn't initialize GLEW" << std::endl;  
  7. exit(0);  
  8. }  
  9.   
  10. init();  
  11. …  
  12. }  

Frame Buffer – Usage

To use our frame buffer, I am first going to give you the display method, and whilst you could put all your code in here, I am going to make a call to a method to render our teapot scene. This display method builds upon the tutorial for creating a square.

So it looks something like the following code, which will create a square with texture coordinates, and I have placed it back 2 units so that it fills up most of the screen. Keep in mind, that I am not doing anything with the frame buffer at the moment; this is just a standard display method.

view plaincopy to clipboardprint?
  1. void display (void) {  
  2. keyOperations();  
  3.   
  4. glClearColor(1.0f, 0.0f, 0.0f, 1.0f); // Clear the background of our window to red  
  5. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //Clear the colour buffer (more buffers later on)  
  6. glLoadIdentity(); // Load the Identity Matrix to reset our drawing locations  
  7.   
  8. glTranslatef(0.0f, 0.0f, -2.0f);  
  9.   
  10. glBegin(GL_QUADS);  
  11.   
  12. glTexCoord2f(0.0f, 0.0f);  
  13. glVertex3f(-1.0f, -1.0f, 0.0f); // The bottom left corner  
  14.   
  15. glTexCoord2f(0.0f, 1.0f);  
  16. glVertex3f(-1.0f, 1.0f, 0.0f); // The top left corner  
  17.   
  18. glTexCoord2f(1.0f, 1.0f);  
  19. glVertex3f(1.0f, 1.0f, 0.0f); // The top right corner  
  20.   
  21. glTexCoord2f(1.0f, 0.0f);  
  22. glVertex3f(1.0f, -1.0f, 0.0f); // The bottom right corner  
  23.   
  24. glEnd();  
  25.   
  26. glutSwapBuffers();  
  27. }  

Now we will go ahead and bind our frame buffer texture to the quad. This is done just like binding a regular texture, because it is just a regular texture. The only difference between the texture we use for our frame buffer, and a standard texture we load in from a file, is that this texture is filled in on the GPU by OpenGL.

So right before your quad begins, bind your frame buffer texture, and then after you finish drawing your quad, unbind it.

  1. glBindTexture(GL_TEXTURE_2D, fbo_texture);  
  2.   
  3. glBegin(GL_QUADS);  
  4.   
  5. …  
  6.   
  7. glEnd();  
  8.   
  9. glBindTexture(GL_TEXTURE_2D, 0);  

You should be able to run this now, but unfortunately because we haven’t rendered anything into the frame buffer, nothing will appear on our quad, it will be as if we never bound a texture. So let’s create a method where we are going to render our frame buffer. I am going to call this renderTeapotScene, because I am using it to render a teapot.

view plaincopy to clipboardprint?
  1. void renderTeapotScene(void) {  
  2.   
  3. }  

renderTeapotScene is going to be called from inside our display method, right after our keyOperations and before we do any actual rendering.

view plaincopy to clipboardprint?
  1. void display(void) {  
  2. keyOperations();  
  3.   
  4. renderTeapotScene();  
  5.   
  6. ...  
  7. }  

Inside of our renderTeapotScene method, we need to first bind our frame buffer so that we can render to it, and then unbind it when we are finished rendering. I am also going to add in some extra code at the very end of this method, just to update the amount in which we are going to rotate our teapot.

view plaincopy to clipboardprint?
  1. void renderTeapotScene(void) {  
  2. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); // Bind our frame buffer for rendering  
  3.   
  4. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // Unbind our texture  
  5.   
  6. rotation_degree += 0.5f;  
  7. if (rotation_degree > 360.0f)  
  8. rotation_degree = 0.0f;  
  9. }  

So far, everything should be fine, except when you bind a frame buffer, you need to set the size of the viewport that the frame buffer will render to. This is done with a call to glViewport, but first I am going to do some more management orientated activities, and store the current state of our GL_ENABLE_BIT and our GL_VIEWPORT_BIT. This is so that when we finish, we can put these back to how they were and not having any glEnable or glViewport calls modify our regular rendering. It is also wise to store information such as GL_LIGHTING_BIT if you are using lighting, and any other states you might need.

view plaincopy to clipboardprint?
  1. void renderTeapotScene(void) {  
  2. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); // Bind our frame buffer for rendering  
  3. glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT); // Push our glEnable and glViewport states  
  4.   
  5. glPopAttrib(); // Restore our glEnable and glViewport states  
  6. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // Unbind our texture  
  7.   
  8. rotation_degree += 0.5f;  
  9. if (rotation_degree > 360.0f)  
  10. rotation_degree = 0.0f;  
  11. }  

It is our calls to glPushAttrib and glPopAttrib which will save and restore our states. The next step as I said is to set the viewport size for rendering, and then I am going to clear the colour buffer, depth buffer and reset the model view matrix, just like you would in your regular display method.

view plaincopy to clipboardprint?
  1. void renderTeapotScene(void) {  
  2. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); // Bind our frame buffer for rendering  
  3. glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT); // Push our glEnable and glViewport states  
  4. glViewport(0, 0, window_width, window_height); // Set the size of the frame buffer view port  
  5.   
  6. glClearColor (0.0f, 0.0f, 1.0f, 1.0f); // Set the clear colour  
  7. glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear the depth and colour buffers  
  8.   
  9. glLoadIdentity();  // Reset the modelview matrix  
  10.   
  11. glPopAttrib(); // Restore our glEnable and glViewport states  
  12. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // Unbind our texture  
  13.   
  14. rotation_degree += 0.5f;  
  15. if (rotation_degree > 360.0f)  
  16. rotation_degree = 0.0f;  
  17. }  

This should be starting to look a little familiar inside of our frame buffer and push attributes calls, and you are probably right, everything you do from now on is just like rendering a normal scene, only you don’t need to call glFlush or glutSwapBuffers like you would with a regular render as we are not pushing the output to the screen. So now all we need to do is add the code in for our teapot rendering. I am going to translate it back five units, and then rotate it along the x and the y axis.

view plaincopy to clipboardprint?
  1. void renderTeapotScene(void) {  
  2. …  
  3. glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear the depth and colour buffers  
  4. glLoadIdentity();  // Reset the modelview matrix  
  5.   
  6. glTranslatef(0.0f, 0.0f, -5.0f); // Translate back 5 units  
  7.   
  8. glRotatef(rotation_degree, 1.0f, 1.0f, 0.0f); // Rotate according to our rotation_degree value  
  9.   
  10. glutSolidTeapot(1.0f); // Render a teapot  
  11.   
  12. glPopAttrib(); // Restore our glEnable and glViewport states  
  13. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // Unbind our texture  
  14. …  
  15. }  

If you followed everything as I have said correctly, then you should be able to compile this and run it. You should then see a quad with a red background, with a texture of a spinning teapot with a blue background attached to the quad.

Well done if you managed that, and now have your head around frame buffers!

If you have any questions, you can always contact me at swiftless@gmail.com

Tutorial Code

view plaincopy to clipboardprint?
  1. #include <GL/glew.h> // Include the GLEW header file  
  2. #include <GL/glut.h> // Include the GLUT header file  
  3. #include <iostream> // Allow us to print to the console  
  4.   
  5. bool* keyStates = new bool[256]; // Create an array of boolean values of length 256 (0-255)  
  6.   
  7. unsigned int fbo; // The frame buffer object  
  8. unsigned int fbo_depth; // The depth buffer for the frame buffer object  
  9. unsigned int fbo_texture; // The texture object to write our frame buffer object to  
  10.   
  11. int window_width = 500; // The width of our window  
  12. int window_height = 500; // The height of our window  
  13.   
  14. float rotation_degree = 0.0f; // The angle of rotation in degrees for our teapot  
  15.   
  16. void initFrameBufferDepthBuffer(void) {  
  17.   
  18. glGenRenderbuffersEXT(1, &fbo_depth); // Generate one render buffer and store the ID in fbo_depth  
  19. glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo_depth); // Bind the fbo_depth render buffer  
  20.   
  21. glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, window_width, window_height); // Set the render buffer storage to be a depth component, with a width and height of the window  
  22.   
  23. glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo_depth); // Set the render buffer of this buffer to the depth buffer  
  24.   
  25. glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); // Unbind the render buffer  
  26. }  
  27.   
  28. void initFrameBufferTexture(void) {  
  29. glGenTextures(1, &fbo_texture); // Generate one texture  
  30. glBindTexture(GL_TEXTURE_2D, fbo_texture); // Bind the texture fbo_texture  
  31.   
  32. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, window_width, window_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); // Create a standard texture with the width and height of our window  
  33.   
  34. // Setup the basic texture parameters  
  35. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);  
  36. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);  
  37. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);  
  38. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);  
  39.   
  40. // Unbind the texture  
  41. glBindTexture(GL_TEXTURE_2D, 0);  
  42. }  
  43.   
  44. void initFrameBuffer(void) {  
  45. initFrameBufferDepthBuffer(); // Initialize our frame buffer depth buffer  
  46.   
  47. initFrameBufferTexture(); // Initialize our frame buffer texture  
  48.   
  49. glGenFramebuffersEXT(1, &fbo); // Generate one frame buffer and store the ID in fbo  
  50. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); // Bind our frame buffer  
  51.   
  52. glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, fbo_texture, 0); // Attach the texture fbo_texture to the color buffer in our frame buffer  
  53.   
  54. glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo_depth); // Attach the depth buffer fbo_depth to our frame buffer  
  55.   
  56. GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); // Check that status of our generated frame buffer  
  57.   
  58. if (status != GL_FRAMEBUFFER_COMPLETE_EXT) // If the frame buffer does not report back as complete  
  59. {  
  60. std::cout << "Couldn't create frame buffer" << std::endl; // Output an error to the console  
  61. exit(0); // Exit the application  
  62. }  
  63.   
  64. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // Unbind our frame buffer  
  65. }  
  66.   
  67. void init(void) {  
  68. glEnable(GL_TEXTURE_2D); // Enable texturing so we can bind our frame buffer texture  
  69. glEnable(GL_DEPTH_TEST); // Enable depth testing  
  70.   
  71. initFrameBuffer(); // Create our frame buffer object  
  72. }  
  73.   
  74. void keyOperations (void) {  
  75. if (keyStates['a']) { // If the a key has been pressed 
  76. // Perform 'a' key operations 
  77. } 
  78. } 
  79.  
  80. void renderTeapotScene(void) { 
  81. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); // Bind our frame buffer for rendering 
  82. glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT); // Push our glEnable and glViewport states 
  83. glViewport(0, 0, window_width, window_height); // Set the size of the frame buffer view port 
  84.  
  85. glClearColor (0.0f, 0.0f, 1.0f, 1.0f); // Set the clear colour 
  86. glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear the depth and colour buffers 
  87. glLoadIdentity();  // Reset the modelview matrix 
  88.  
  89. glTranslatef(0.0f, 0.0f, -5.0f); // Translate back 5 units 
  90.  
  91. glRotatef(rotation_degree, 1.0f, 1.0f, 0.0f); // Rotate according to our rotation_degree value 
  92.  
  93. glutSolidTeapot(1.0f); // Render a teapot 
  94.  
  95. glPopAttrib(); // Restore our glEnable and glViewport states 
  96. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // Unbind our texture 
  97.  
  98. rotation_degree += 0.5f; 
  99. if (rotation_degree > 360.0f) 
  100. rotation_degree = 0.0f; 
  101. } 
  102.  
  103. void display (void) { 
  104. keyOperations(); // Perform any key presses 
  105.  
  106. renderTeapotScene(); // Render our teapot scene into our frame buffer 
  107.  
  108. glClearColor(1.0f, 0.0f, 0.0f, 1.0f); // Clear the background of our window to red 
  109. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //Clear the colour buffer (more buffers later on) 
  110. glLoadIdentity(); // Load the Identity Matrix to reset our drawing locations 
  111.  
  112. glTranslatef(0.0f, 0.0f, -2.0f); 
  113.  
  114. glBindTexture(GL_TEXTURE_2D, fbo_texture); // Bind our frame buffer texture 
  115.  
  116. glBegin(GL_QUADS); 
  117.  
  118. glTexCoord2f(0.0f, 0.0f); 
  119. glVertex3f(-1.0f, -1.0f, 0.0f); // The bottom left corner 
  120.  
  121. glTexCoord2f(0.0f, 1.0f); 
  122. glVertex3f(-1.0f, 1.0f, 0.0f); // The top left corner 
  123.  
  124. glTexCoord2f(1.0f, 1.0f); 
  125. glVertex3f(1.0f, 1.0f, 0.0f); // The top right corner 
  126.  
  127. glTexCoord2f(1.0f, 0.0f); 
  128. glVertex3f(1.0f, -1.0f, 0.0f); // The bottom right corner 
  129.  
  130. glEnd(); 
  131.  
  132. glBindTexture(GL_TEXTURE_2D, 0); // Unbind any textures 
  133.  
  134. glutSwapBuffers(); 
  135. } 
  136.  
  137. void reshape (int width, int height) { 
  138. glViewport(0, 0, (GLsizei)width, (GLsizei)height); // Set our viewport to the size of our window 
  139. glMatrixMode(GL_PROJECTION); // Switch to the projection matrix so that we can manipulate how our scene is viewed 
  140. glLoadIdentity(); // Reset the projection matrix to the identity matrix so that we don't get any artifacts (cleaning up)  
  141. gluPerspective(60, (GLfloat)width / (GLfloat)height, 1.0, 100.0); // Set the Field of view angle (in degrees), the aspect ratio of our window, and the new and far planes  
  142. glMatrixMode(GL_MODELVIEW); // Switch back to the model view matrix, so that we can start drawing shapes correctly  
  143. }  
  144.   
  145. void keyPressed (unsigned char key, int x, int y) {  
  146. keyStates[key] = true// Set the state of the current key to pressed  
  147. }  
  148.   
  149. void keyUp (unsigned char key, int x, int y) {  
  150. keyStates[key] = false// Set the state of the current key to not pressed  
  151. }  
  152.   
  153. int main (int argc, char **argv) {  
  154. glutInit(&argc, argv); // Initialize GLUT  
  155. glutInitDisplayMode (GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGBA); // Set up a basic display buffer (only single buffered for now)  
  156. glutInitWindowSize (500, 500); // Set the width and height of the window  
  157. glutInitWindowPosition (100, 100); // Set the position of the window  
  158. glutCreateWindow ("Your first OpenGL Window"); // Set the title for the window  
  159.   
  160. if (GLEW_OK != glewInit()) {  
  161. std::cout << "Couldn't initialize GLEW" << std::endl;  
  162. exit(0);  
  163. }  
  164.   
  165. init();  
  166.   
  167. glutDisplayFunc(display); // Tell GLUT to use the method "display" for rendering  
  168. glutIdleFunc(display); // Tell GLUT to use the method "display" for rendering  
  169.   
  170. glutReshapeFunc(reshape); // Tell GLUT to use the method "reshape" for reshaping  
  171.   
  172. glutKeyboardFunc(keyPressed); // Tell GLUT to use the method "keyPressed" for key presses  
  173. glutKeyboardUpFunc(keyUp); // Tell GLUT to use the method "keyUp" for key up events  
  174.   
  175. glutMainLoop(); // Enter GLUT's main loop  
  176. }  

原创粉丝点击