PDA

View Full Version : Mipmap creation from the framebuffer



Anselmo
04-04-2002, 07:35 AM
I am having some problems in trying to
build a mipmap from the framebuffer using
glCopyTexImage2D. If I use glCopyTexImage2D
to set a simple texture everything is Ok, but
when I try to set all the required levels for the mipmapping the thing goes wrong. The image is stored wrongly in the texture as if the bytes were mixedup.

Has someone tried to do something alike?
My motivation is to use a fast method to build a mipmap once my texture is dynamic.

I'm following the ideas in http://www.opengl.org/developers/code/sig99/advanced99/notes/node65.html
but I can't get this running.

I have already checked the pixel storage modes but nothing helps.

Thank you all very much for the attention

Elixer
04-04-2002, 09:17 AM
How about some code snippets?

Anselmo
04-04-2002, 10:46 AM
Originally posted by Elixer:
How about some code snippets?



Here are the snippets you asked.

Please, don't worry about some functions
I use. They are just supposed to deal with the API I use to open a OPENGL windows context.

My application is a little bit intricate so
I have separated the fragment necessary.
My build mipmap function was also simplified
in order to deal only with a simple drawing I made in the canvas, but it already shows the failure.

The state variables are set int the function
InitOpenGLParameters.

static void InitOpenGLParameters(Ihandle * canvas)
{
IupGLMakeCurrent(canvas);
glEnable(GL_DEPTH_TEST);
//glEnable(GL_CULL_FACE);
glDepthFunc(GL_LESS);
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
glPixelStorei(GL_PACK_ALIGNMENT,1);
InitCubesDisplayLists();
InitQuadrics();
}

void BuildMipmap()
{
int i,width,height;
GLuint handle;

glGenTextures(1,&(handle));
glBindTexture(GL_TEXTURE_2D,handle);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL _CLAMP);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL _CLAMP);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTE R,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTE R,GL_LINEAR_MIPMAP_LINEAR);
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_REPLACE);

IupGLMakeCurrent(recCanvas);

GetCanvasSize(&width,&height);

glPixelStorei(GL_PACK_ROW_LENGTH,width);
glPixelStorei(GL_UNPACK_ROW_LENGTH,height);
glRasterPos2i(0,0);
glReadBuffer(GL_BACK);
glDisable(GL_DEPTH_TEST);

PushView();
SetOrtho2DView(width,height);


glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glBegin(GL_POLYGON);
glTexCoord2d(0.0,0.0);
glVertex2f(0,0);
glTexCoord2d(1.0,0.0);
glVertex2f(width,0);
glTexCoord2d(1.0,1.0);
glVertex2f(width,height);
glTexCoord2d(0.0,1.0);
glVertex2f(0,0);
glEnd();

glCopyTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,0,0,256,2 56,0);
glCopyTexImage2D(GL_TEXTURE_2D,1,GL_RGBA,0,0,128,1 28,0);
glCopyTexImage2D(GL_TEXTURE_2D,2,GL_RGBA,0,0,64,64 ,0);
glCopyTexImage2D(GL_TEXTURE_2D,3,GL_RGBA,0,0,32,32 ,0);
glCopyTexImage2D(GL_TEXTURE_2D,4,GL_RGBA,0,0,16,16 ,0);
glCopyTexImage2D(GL_TEXTURE_2D,5,GL_RGBA,0,0,8,8,0 );
glCopyTexImage2D(GL_TEXTURE_2D,6,GL_RGBA,0,0,4,4,0 );
glCopyTexImage2D(GL_TEXTURE_2D,7,GL_RGBA,0,0,2,2,0 );
glCopyTexImage2D(GL_TEXTURE_2D,8,GL_RGBA,0,0,1,1,0 );

for (i=0;i<=8;i++)
{

// glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_BASE_LEVE L, i);
// glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAX_LEVEL , i);

DrawTexture((float)(width/(1<<i)),(float)(height/(1<<i)));
IupGLSwapBuffers(recCanvas);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
printf("level:%d\n",i);
getch();
}

glEnable(GL_DEPTH_TEST);
RestoreView();
}


void DrawTexture(float width,float height)
{
glEnable(GL_TEXTURE_2D);
glBegin(GL_POLYGON);
glTexCoord2d(0.0,0.0);
glVertex2f(0,0);
glTexCoord2d(1.0,0.0);
glVertex2f(width,0);
glTexCoord2d(1.0,1.0);
glVertex2f(width,height);
glTexCoord2d(0.0,1.0);
glVertex2f(0,height);
glEnd();
glDisable(GL_TEXTURE_2D);

}


Thank you again!

V-man
04-04-2002, 12:19 PM
Hi, I just looked at it quick and saw some problems. I commented out the problems and put up the correct statements:

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL _CLAMP);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL _CLAMP);
//glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTE R,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTE R,GL_LINEAR_MIPMAP_LINEAR);
//glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTE R,GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTE R,GL_LINEAR);
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_REPLACE);

IupGLMakeCurrent(recCanvas);

GetCanvasSize(&width,&height);

//glPixelStorei(GL_PACK_ROW_LENGTH,width);
//glPixelStorei(GL_UNPACK_ROW_LENGTH,height);

I'm not sure what width and height are here, but this is a potential source of problem. I would leave these as zero.

V-man

davepermen
04-05-2002, 12:07 AM
i thought you have to grab the fullres image first and copy it to your basetex. then you draw a quad bilinear filtered with halfed sizes, and grab this on the second mipmap layer. and so on..

Anselmo
04-05-2002, 09:15 AM
Originally posted by davepermen:
i thought you have to grab the fullres image first and copy it to your basetex. then you draw a quad bilinear filtered with halfed sizes, and grab this on the second mipmap layer. and so on..

Thanks for the corrections!!! When I changed
the code I made those mistakes. Unfortunatly the problem still remains.

Davepermen, that's exactly what I'm supposed
to do. The problem is that I can't even make the simple code above working, let alone the correct process that's the one you mentioned.

I just watered down the code in order to show
that a simple copy of images to set
the mipmap levels is not functioning.

To make what you said I need to use the
parameters

GL_TEXTURE_BASE_LEVEL
GL_TEXTURE_MAX_LEVEL

to set the levels used in the mipmap otherwise there would be problems in
loding and drawing part of the complete mipmap levels.

This parameters are available in opengl 1.2.

I suppose there's some bug int the api to
create the opengl canvas I use.

If someone has a simple code of mipmap creation from framebuffer in glut I would
be very glad.

I'm really stuck in this problem and
if someone could at least tell me:
"there's nothing wrong, it works with me", then I would know there's something wrong with the opengl canvas my API creates.

Thank you all for the patience.


--Anselmo

davepermen
04-05-2002, 11:07 AM
any pics how the mipmap-levels look like?

Anselmo
04-08-2002, 09:47 AM
Originally posted by davepermen:
any pics how the mipmap-levels look like?

Davepermen, I have some problems to post the image in a webpage, but
I'm sending now a complete glut code where the problem is presented.
It's small and simple.

#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include"GL/gl.h"
#include"glut.h"

void InitOpenGL()
{
//glEnable(GL_DEPTH_TEST);
//glEnable(GL_CULL_FACE);
//glDepthFunc(GL_LESS);
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
glPixelStorei(GL_PACK_ALIGNMENT,1);

}


void DrawTexture(float width,float height)
{
glEnable(GL_TEXTURE_2D);
glBegin(GL_POLYGON);
glTexCoord2d(0.0,0.0);
glVertex2f(0,0);
glTexCoord2d(1.0,0.0);
glVertex2f(width,0);
glTexCoord2d(1.0,1.0);
glVertex2f(width,height);
glTexCoord2d(0.0,1.0);
glVertex2f(0,height);
glEnd();
glDisable(GL_TEXTURE_2D);

}


void BuildMipmap()
{
int i;
GLuint handle;

glGenTextures(1,&(handle));
glBindTexture(GL_TEXTURE_2D,handle);


// glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL _CLAMP);
// glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL _CLAMP);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTE R,GL_NEAREST_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTE R,GL_NEAREST);
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_REPLACE);

glReadBuffer(GL_BACK);
//glDisable(GL_DEPTH_TEST);


glCopyTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8,0,0,256, 256,0);
glCopyTexImage2D(GL_TEXTURE_2D,1,GL_RGBA8,0,0,128, 128,0);
glCopyTexImage2D(GL_TEXTURE_2D,2,GL_RGBA8,0,0,64,6 4,0);
glCopyTexImage2D(GL_TEXTURE_2D,3,GL_RGBA8,0,0,32,3 2,0);
glCopyTexImage2D(GL_TEXTURE_2D,4,GL_RGBA8,0,0,16,1 6,0);
glCopyTexImage2D(GL_TEXTURE_2D,5,GL_RGBA8,0,0,8,8, 0);
glCopyTexImage2D(GL_TEXTURE_2D,6,GL_RGBA8,0,0,4,4, 0);
glCopyTexImage2D(GL_TEXTURE_2D,7,GL_RGBA8,0,0,2,2, 0);
glCopyTexImage2D(GL_TEXTURE_2D,8,GL_RGBA8,0,0,1,1, 0);

for (i=0;i<=6;i++)
{

//glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_BASE_LEVE L, i);
//glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAX_LEVEL , i);


glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
DrawTexture((float)(256/(1<<i)),(float)(256/(1<<i)));
glutSwapBuffers();


printf("level:%d\n",i);
getch();
}

//glEnable(GL_DEPTH_TEST);

}


void DrawScene()
{

glClearColor(0.0,0.0,0.0,1.0);
glColor3ub(255,255,255);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glBegin(GL_POLYGON);
glVertex2f(0,0);
glVertex2f(256,0);
glVertex2f(256,256);
glVertex2f(0,0);
glEnd();

}

void Display(void)
{
DrawScene();
BuildMipmap();
glFlush();
glutSwapBuffers();
}


void MyReshape(int w, int h)
{

glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, (GLdouble) w, 0.0, (GLdouble) h);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

void main(int argc, char ** argv)
{

glutInit(&argc,argv);

glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowSize(256,256);
glutCreateWindow("Teste");
glutReshapeFunc(MyReshape);
glutDisplayFunc(Display);
InitOpenGL();
glutMainLoop();

}

I've shown this to several people that work with opengl and nobody could
find the error source. We think there's some problem with the acceleration
mechanism in the geforce boards(we experimented with geforce 2 and 3), but
I hope it's not. I don't know why its mixing up the data stored in level 0 of the
mipmap. If I change to GL_RGBA4 the problem changes to other levels.

I know that there's now more efficiente ways to do a fast mipmap construction by
rendering to texture, pbuffers and SGIS extension but I'm very curious about what's happening.

Could you please take a look at this?

Thank you very much.

davepermen
04-08-2002, 10:20 AM
ok, once again i try to explain what you do:

you render at 256x256 an image, wich will be your texture

you grab the 0,0,256,256-part of the image and put this onto layer0,
you grab the 0,0,128,128-part of the image and put this onto layer1,
you grab the 0,0,64,64-part of the image and put this onto layer2 etc..

you need to grab the WHOLE PICTURE everytime..

to get it smaller do it like this..

grab full image onto texturelayer0.
draw a quad at 0,0,128,128 with this texture, and bilinearfiltering.. resulting image on screen: a 0,0,128,128 downsampled version of the pic before. grab this on layer1
draw quad with 0,0,64,64 and grab this on layer2
draw quad with 0,0,32,32 and grab this to layer3

etc..

on layer1 you don't get the full image downscaled but only the part of the image at full scale you copy.
why should it downsample for you at copytime? its a COPYFUNCTION, not a scalefunction..

Anselmo
04-08-2002, 01:03 PM
Originally posted by davepermen:
ok, once again i try to explain what you do:

you render at 256x256 an image, wich will be your texture

you grab the 0,0,256,256-part of the image and put this onto layer0,
you grab the 0,0,128,128-part of the image and put this onto layer1,
you grab the 0,0,64,64-part of the image and put this onto layer2 etc..

you need to grab the WHOLE PICTURE everytime..

to get it smaller do it like this..

grab full image onto texturelayer0.
draw a quad at 0,0,128,128 with this texture, and bilinearfiltering.. resulting image on screen: a 0,0,128,128 downsampled version of the pic before. grab this on layer1
draw quad with 0,0,64,64 and grab this on layer2
draw quad with 0,0,32,32 and grab this to layer3

etc..

on layer1 you don't get the full image downscaled but only the part of the image at full scale you copy.
why should it downsample for you at copytime? its a COPYFUNCTION, not a scalefunction..

I know my code does not do what you said it's just a test code to see if glCopyTexImage2D gets whatever is in the framebuffer to the layers.
The problem is that the COPYFUNCTION doesn't work for more than one layer.
It only works fine when I use only the level 0.

It seems glCopyTexImage2D doesn't seem to capture the parts I asked it to get correctly.

The problem is not in construction the mipmap. It is just in getting the layers correctly, just capturing the framebuffer image, whatever it is.

It seems that the opengl glCopyTexImage2D is not grabbing what is in the framebuffer into the layer no matter what it is.

Once I get this funcioning I will implement what you've described. The problem
is that I can't even start because I can't make glCopyTexImage2D get the
framebuffer information into the layers without error.

If you run my code you'll see that the first layer is completly a mess while the
others are correct with the image I expected, that is, part of the whole image.