OpenGL gluBuild2DMipmaps给我带来了麻烦。救命!

时间:2010-08-17 00:50:58

标签: opengl

编辑:更新了代码。现在运作得很好。

前言。我是一个OpenGL新手,负责维护一个应用程序,除其他外,它使用wxWidgets和OpenGL显示各种图像格式作为背景,以便在覆盖用户项目时进行参考。

用于显示图像的原始代码将图像分解为512x512个块并从中制作纹理,丢弃图像中不适合整个块的任何部分。我需要改变这种行为。我增加了将保存我的命名纹理的数组的大小,我处理了我的循环的边缘情况,我设置了一个不同大小的子图像来抓取,或者我更改纹理坐标以在部分块上正确映射。

然而,当我的子图像没有足够的数据来填充512x512块时,当我尝试将指针传递给我的子图像时,build2DMipmaps会呕吐。指针被指向该函数所指向的数据量是每列最后一次迭代的唯一不同之处。我的意图是稍后设置正确的纹理坐标映射以计算较少的数据。为什么build2dmipmaps呕吐?我用错了吗?我在其他地方做错了吗?

到目前为止,我的问题出现在第一组嵌套for循环中。当内循环在其最后一次迭代时,比如说,htiles是7而y是6,抓取的子图像是一个有效的子图像(根据wxWidgets)意味着它有数据,但是我们得到了mipmap我得到了一个访问冲突错误。

您将在下面找到代码。提前感谢您的时间。

int width,height,wtiles,htiles;
width=bg.GetWidth();
height=bg.GetHeight();
bgwidth = width;
bgheight = height;
wtiles=(int)floor((float)width/(float)MAX_TEX);
htiles=(int)floor((float)height/(float)MAX_TEX);

glEnable(GL_TEXTURE_2D);

//there are two types of tiles here, whole tiles and partial tiles
//wtiles and htiles are the number of whole tiles
//there is one row and one column of partial tiles

unsigned int h_error,w_error;
w_error=width % MAX_TEX;
h_error=height % MAX_TEX;

//Below, if the image dimensions break neatly into MAX_TEX chunks,
//then there is no error(leftover).  This usage here allows me to take advantage
//of the logic already made.  If there is error, keep it and add a tile count
//if there is not, then make MAX_TEX the default dimension for ALL texture dimensions

(w_error == 0) ? w_error = MAX_TEX : wtiles++;
(h_error == 0) ? h_error = MAX_TEX : htiles++;


ntiles=wtiles*htiles;
bgtiles=new unsigned int[ntiles];
glGenTextures(ntiles, bgtiles);
float dialogFactor = ntiles / 100.0;

//now to split the tiles out
for(int x=0;x<wtiles;x++)
    for(int y=0;y<htiles;y++){
        dialog.Update((int) ((x*htiles + y) / dialogFactor), "Generating Textures");

        wxImage bloc=bg.GetSubImage(wxRect(x*MAX_TEX,y*MAX_TEX,
                                            (x == wtiles-1) ? w_error : MAX_TEX,
                                            (y == htiles-1) ? h_error : MAX_TEX
                                            )
                                    );

        glBindTexture(GL_TEXTURE_2D, bgtiles[x+(htiles-(y+1))*wtiles]);
        unsigned char *dat=(unsigned char *)bloc.GetData();
        //printf("%d\n",dat[25]);

        glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
        glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
        //gluBuild2DMipmaps(GL_TEXTURE_2D,GL_COMPRESSED_RGB_ARB,
                                        //(x == wtiles-1) ? w_error : MAX_TEX,
                                        //(y == htiles-1) ? h_error : MAX_TEX,
            //GL_RGB,GL_UNSIGNED_BYTE,(GLvoid *)dat);

        glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
        glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
        glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_ARB,
                                        (x == wtiles-1) ? w_error : MAX_TEX,
                                        (y == htiles-1) ? h_error : MAX_TEX,
                                        0, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid *)dat);

    }

    //marvelous, now make a simple display list to blit out the whole mess
    background=glGenLists(1);//dlist made!
    glNewList(background, GL_COMPILE);
    glEnable(GL_TEXTURE_2D);
    glColor4f(1,1,1,1);

    float h_offset,w_offset;

    glDisable(GL_DEPTH_TEST);
    glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
    {
        glPushMatrix();
        for(int x=0;x<wtiles;x++)
            for(int y=0;y<htiles;y++){
                dialog.Update((int) ((x*htiles + y) / dialogFactor), "Generating Display List");
                //if(x==wtiles-1 && y==htiles-1)printf("%f %f\n",(x+1)*MAX_TEX - width *.5,(y+1)*MAX_TEX - height *.5);
                glBindTexture(GL_TEXTURE_2D, bgtiles[x+(y)*wtiles]);
                glBegin(GL_QUADS);

                //if we are on our last column or row, adjust the texture size accordingly.
                //unless the image has been divided evenly, in which case there is no need for offset.
                (w_error != 0 && x == wtiles - 1) ? w_offset = MAX_TEX - w_error : w_offset = 0;
                (h_error != 0 && y == 0)          ? h_offset = MAX_TEX - h_error : h_offset = 0;

                //apparently, if NPOTS textures are supported, their tex map coords are normalized
                // aka 0-1.

                //god this is an ugly mess.
                //for some reason, the ordering of vertices is correct,
                //but the texture coords need to be this way.  It looks wrong but the program functions
                //the offset garbage is to handle placement of the sections of textures that aren't a full
                //MAX_TEX x MAX_TEX
                //conveinently, if the image does break up into even full squares, the errors are O...

                glTexCoord2d(0,1); glVertex3f(x*MAX_TEX - width *.5,(y*MAX_TEX - height *.5)+h_offset,0);
                glTexCoord2d(1,1); glVertex3f(((x+1)*MAX_TEX - width *.5)-w_offset,(y*MAX_TEX - height *.5)+h_offset,0);
                glTexCoord2d(1,0); glVertex3f(((x+1)*MAX_TEX - width *.5)-w_offset,(y+1)*MAX_TEX - height *.5,0);
                glTexCoord2d(0,0); glVertex3f(x*MAX_TEX - width *.5,(y+1)*MAX_TEX - height *.5,0);
                glEnd();
            }
            glPopMatrix();
    }

    glDisable(GL_TEXTURE_2D);
    glEnable(GL_DEPTH_TEST);
    glEndList();
    //that's that
    glDisable(GL_TEXTURE_2D);

1 个答案:

答案 0 :(得分:1)

openGL纹理必须是POT:2的幂,即32 * 32,32 * 64,1024 * 512,......

您的边缘图像不是,因此您有以下解决方案:

  • 总是让你的纹理为512x512,用黑色填充边框,小心处理UV坐标
  • 使用ARB扩展来获取OpenGL处理​​NPOT纹理,请参阅http://www.opengl.org/wiki/NPOT_Texture。这就是你不知道的事情。但是构建mipmap的GLU函数不知道如何处理NPOT纹理,所以你必须自己动手。

中间(和恕我直言最佳)解决方案是为每个维度获得最接近的2的幂。例如,如果您的输入边缘纹理是512 * 6(因为你不幸^^)创建一个512 * 8(8 = 2 ^ 3)纹理,用随机颜色填充最后两列,让glu处理mipmap处理你的紫外线。