1

我有一个奇怪的问题:
我必须输出一个 15x15 元素的游戏地板。
到目前为止,我在游戏循环中调用了我的函数“printFloor()”。

此函数遍历所有 225 个元素,并根据它们的值显示纹理文件的不同部分。因此 CPU 必须在每个循环周期中渲染相同的 225 个纹理。游戏循环每个周期需要大约 16-32ms,所以我现在把这个输出放在一个显示列表中:

if(!gamefloorPrepared)  //no Display list created -> this is the first time the floor nees to
                        //be printed
{   gamefloor = glGenLists(1);

    glNewList(gamefloor,GL_COMPILE);
        for(int y=0;y<size.y;y++)
        {   for(int x=0;x<size.x;x++)
            {   printFloorElement(spielfeld[y][x],{x,y});     //see below
            }
        }
    glEndList();
    gamefloorPrepared=1;
}else
{   glCallList(gamefloor);
}

函数 printFloorElement 计算位置,将图形模式更改为“switchGraphicMode(TEXTURES);”,绑定纹理并绘制纹理:

glBegin(GL_QUADS);
    glTexCoord2f(spriteSize.x* spritePos.x   +halfTexelSize.x,spriteSize.y*(spritePos.y+1)-halfTexelSize.y);   glVertex2f(display.a.x,display.a.y);
    glTexCoord2f(spriteSize.x* spritePos.x   +halfTexelSize.x,spriteSize.y* spritePos.y   +halfTexelSize.y);   glVertex2f(display.a.x,display.b.y);
    glTexCoord2f(spriteSize.x*(spritePos.x+1)-halfTexelSize.x,spriteSize.y* spritePos.y   +halfTexelSize.y);   glVertex2f(display.b.x,display.b.y);
    glTexCoord2f(spriteSize.x*(spritePos.x+1)-halfTexelSize.x,spriteSize.y*(spritePos.y+1)-halfTexelSize.y);   glVertex2f(display.b.x,display.a.y);
glEnd();

问题:一个游戏循环周期现在需要 60-80 毫秒,所以它相当慢。显示列表只生成一次,我已经检查过了。

“switchGraphicMode()”-函数:

void switchGraphicMode(GRAPHICMODES target)//can be "TEXTURES" or "DRAWING"
{   if(target != graphicMode)//"gaphicMode" = global Variable which shows if GL_TEXTURE_2D is currently enabled
    {   if(target==DRAWING)
        {   glDisable(GL_TEXTURE_2D);
            graphicMode=DRAWING;
        }else
        {   glEnable(GL_TEXTURE_2D);
            graphicMode=TEXTURES;
        }
    }
}

有人知道原因吗?

4

2 回答 2

2

glBegin()/glEnd() 和显示列表是已弃用的“立即模式”管道的一部分。

现在首选的方法是使用顶点缓冲区对象。

这两种方法的区别在于,在立即模式下,每次通过渲染循环,您都将顶点数据从主机内存传输到 GPU,即使您使用的是显示列表(显示列表维护在主机上而不是显示器上)卡片)。

顶点缓冲区对象是在显示卡内存中维护的内存缓冲区。您设置一次,然后在开始渲染之前一次性传输所有顶点数据。然后每次通过渲染循环,您调用专门的绘图函数,告诉显卡使用该缓冲区中的数据进行绘图,从而避免执行昂贵的主机到显卡数据传输的需要。

使用顶点缓冲区对象需要比立即模式渲染更多的设置,但加速是非常值得的。谷歌 opengl 顶点缓冲对象。应该有大量的教程和示例代码来帮助您入门。

于 2012-11-13T06:47:41.163 回答
0

很难用这些代码片段来判断,但对于第一步,我建议您在填充 DisplayList 时利用批处理,您似乎错过了:

glEnable(GL_TEXTURE_2D);

if(!gamefloorPrepared)
{   gamefloor = glGenLists(1);

    glNewList(gamefloor,GL_COMPILE);
    glBegin(GL_QUADS);
        for(int y=0;y<size.y;y++)
        {   for(int x=0;x<size.x;x++)
            {   
                glTexCoord2f(spriteSize.x* spritePos.x   +halfTexelSize.x,spriteSize.y*(spritePos.y+1)-halfTexelSize.y);   glVertex2f(display.a.x,display.a.y);
                glTexCoord2f(spriteSize.x* spritePos.x   +halfTexelSize.x,spriteSize.y* spritePos.y   +halfTexelSize.y);   glVertex2f(display.a.x,display.b.y);
                glTexCoord2f(spriteSize.x*(spritePos.x+1)-halfTexelSize.x,spriteSize.y* spritePos.y   +halfTexelSize.y);   glVertex2f(display.b.x,display.b.y);
                glTexCoord2f(spriteSize.x*(spritePos.x+1)-halfTexelSize.x,spriteSize.y*(spritePos.y+1)-halfTexelSize.y);   glVertex2f(display.b.x,display.a.y);
            }
        }
    glEnd();
    glEndList();
    gamefloorPrepared=1;
}else
{  
 glCallList(gamefloor);    
}
glDisable(GL_TEXTURE_2D);

这样,显示列表中的所有顶点都在一个GL_QUADS子句中,并且没有不必要的 texture_2d 状态更改。

PS有人应该添加关于已弃用功能的评论;)

于 2012-11-12T09:18:49.070 回答