PDA

View Full Version : Copying back buffer contents into a texture



JaakK
02-14-2012, 09:26 AM
Hi,

To make my maze type game faster I decided to put my drawed ball inside a texture, because i have to draw it otherwise once for every room and I'm drawing it like a concave polygon using the stencil buffer, it takes more time than using a texture. The problem is, that I'm getting it inside a texture correctly from the back buffer when I'm rendering the third frame since the start of the game and my question is, why is it like so?

When I'm using a texture from the thirst frame, I'm having texture with solid white color, so it has nothing inside. When I'm using textures from the second frame, then I have only the black background of the desired texture and when I take the texture from the third frame, then I have desired texture. For frame count I use the static variable "done" inside the "drawTexture" function. I added three pictures as well with file manager. On pictures are results when I took the texture from a different frame.

<div class="ubbcode-block"><div class="ubbcode-header">Click to reveal.. <input type="button" class="form-button" value="Show me!" onclick="toggle_spoiler(this, 'Yikes, my eyes!', 'Show me!')" />]<div style="display: none;">

void DrawBall::drawTexture(float imageD) {
static int done = 0;

if (done < 3) {
drawToTexture(imageD);
done++;
}

glEnable(GL_TEXTURE_2D);
glBindTexture (GL_TEXTURE_2D, texture);

glColor3f(1, 1, 1);
glBegin (GL_QUADS);
glTexCoord2f (0.0, 0.0); glVertex3f (0.0, 0.0, -imageD);
glTexCoord2f (1.0, 0.0); glVertex3f (5.0, 0.0, -imageD);
glTexCoord2f (1.0, 1.0); glVertex3f (5.0, 5.0, -imageD);
glTexCoord2f (0.0, 1.0); glVertex3f (0.0, 5.0, -imageD);
glEnd ();

glDisable(GL_TEXTURE_2D);
}

void DrawBall::drawToTexture(float imageD) {
int viewport[4];
glGetIntegerv(GL_VIEWPORT, (int*) viewport);

int textureWidth = 64;
int textureHeight = 64;

texture = genEmptyTexture(textureWidth, textureHeight);

glViewport(0, 0, textureWidth, textureHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, 1, 1, 100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

/*
This function calculates the vertexes for the ball
inside a vector<vector<float>> variable "test"
*/
_calculateCircleVertexes(0.0f, 0.0f, -2.0f, 0.249f, &amp;test, 20);

_displayBall(&amp;test, 0.0f, 0.0f, 0.5f, -2.0f, &amp;*smallBallColor);

glBindTexture(GL_TEXTURE_2D, texture);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, textureWidth, textureHeight, 0);

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, (GLfloat)viewport[2] / (GLfloat)viewport[3], 1.0f, imageD + 10.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

GLuint DrawBall::genEmptyTexture(unsigned int width, unsigned int height) {
GLuint txtIndex;

glGenTextures(1, &amp;txtIndex);
glBindTexture(GL_TEXTURE_2D, txtIndex);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
GL_RGB, GL_UNSIGNED_BYTE, NULL);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTE R,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTE R,GL_LINEAR);

return txtIndex;
}

void DrawBall::_displayBall(vector<vector<GLfloat>> *vertexes, GLfloat x, GLfloat y
, GLfloat imageW, GLfloat imageD, color *color) {
glTranslatef(x, y, imageD);

glClearStencil(0);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_NEVER, 0, 1);
glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT);

glBegin(GL_POLYGON);
vector<vector<GLfloat>>::iterator it = vertexes->begin();
for (; it != vertexes->end(); it++) {
glVertex3f((*it)[0], (*it)[1], 0.0f);
}
glEnd();

glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glStencilFunc(GL_EQUAL, 1, 1);
glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);

glColor3f(color->r, color->g, color->b);
glBegin(GL_QUADS);
glVertex3f(-(imageW / 2.0f), -(imageW / 2.0f), 0.0f);
glVertex3f( (imageW / 2.0f), -(imageW / 2.0f), 0.0f);
glVertex3f( (imageW / 2.0f), (imageW / 2.0f), 0.0f);
glVertex3f(-(imageW / 2.0f), (imageW / 2.0f), 0.0f);
glEnd();

glDisable(GL_STENCIL_TEST);


glTranslatef(x, y, -imageD);
}
[/QUOTE]</div>

BionicBytes
02-15-2012, 05:39 AM
The problem is, that I'm getting it inside a texture correctly from the back buffer when I'm rendering the third frame since the start of the game and my question is, why is it like so?
No idea what you are saying. Can you please think about what you are try to say and clearly state what the problems are.

JaakK
02-23-2012, 04:25 AM
Well, when I start the game, in order to draw white balls onto the screen, I'm using a texture of that impression multiple times. To draw it inside a texture I switch my viewport to 64 X 64 pixels, draw the ball inside window-system-provided framebuffer (backbuffer) and copy it inside a texture, then switch my viewport back to normal and throughout the game I use that texture for every frame. What I'm trying to say is that I should to it before rendering anything on the screen. But I can't somehow to make it work like that. If I make the texture before rendering anything, my texture looks solid white, so it is empty. If I have rendered first frame on to the screen and making the texture before rendering the second frame, texture looks solid black, so it has the desired background color, but not still the ball. Now when I have rendered the second frame and then make the texture, then I have the desired background color and the ball impression in the centre, thats what I want and I don't have to make the texture anymore before rendering a frame and I can use it throughout the game for every frame. My question is, why I can't make it work before rendering any frames. I draw the filled ball like a concave polygon using the stencil buffer. If I draw a unfilled circle using GL_LINE_LOOP, then I get the proper texture before rendering second frame. I think the problem comes using depth and stencil buffer. But I would like to have an opinion from someone who knows the things better than me.

In another forum I had reply like that: "You should not use the window framebuffer (which includes both back- and frontbuffer) for render to texture operations. It just breaks to easily (you've experienced it). Instead use a so called Framebuffer Object, with the texture as rendering target."

tksuoran
02-23-2012, 04:56 AM
For this purpose, using window framebuffer is fine. Your problem is one or more several OpenGL states which are not set properly at the time you render your ball. In general, you should make sure that all relevant OpenGL state is set as it is necessary to get your desired result. Has glClearColor the right value? Is scissor test either disabled or enabled with the correct size? Is stencil test disabled? Is blending, depth test and face culling disabled? Have you set depth mask to false? Is your projection matrix properly setup? Is the Z you render between near and far ranges? This is a start, but OpenGL*does have a lot of states that affect rendering. Your job is to make sure you always have to right state whenever you render anything. The reason why you get the right result after second frame is that your code has finally setup the necessary states the right way.

Remember that you may have more than one state wrong. So you may need to fix multiple states before you see any improvement.

Edit:*Further issue: You also need the correct state while you render the texture. Specifically check texture filtering modes. You can not use the default filtering mode, because it uses mipmaps, unless you have generated those.

JaakK
02-23-2012, 07:19 AM
Tksuoran,

Thank you a lot, now thinking about it's obvious. Got it working before the second frame - didn't had stencil test enabled. Now got to figure out what's not letting it happen before the first frame.