使用OpenGL ES的iPhone上的平铺背景

时间:2009-08-12 21:13:10

标签: iphone opengl-es

我想在iPhone上制作2D平铺背景系统。获取tilemap和tileset图像并将其转换为屏幕上的完整地图的东西。

只是做一些搞乱,我的第一个方法是为每个瓷砖创建一个多边形。这工作正常,直到我开始测试400多边形左右,然后它开始运行非常缓慢。我只是想知道 - 几种多边形的这种方法是不是要走的路?或者我做错了什么?如果需要,我会稍后发布代码,但我的主要问题是“400个小多边形在iPhone上运行缓慢还是我做错了什么?”

我还考虑了另一种方法,即在初始化期间,通过tilemap / tilesets之外的代码创建地图纹理,然后将其粘贴在一个大的多边形上。所以,是啊...关于我应该怎样做这样的事情的任何反馈?

我知道有人会提到这一点 - 我考虑过尝试cocos2d,但我有理由不去那条路。

6 个答案:

答案 0 :(得分:1)

你的问题几乎可以肯定你是400次绑定纹理,而不是其他任何东西。你应该将所有的瓷砖放在一个大的纹理图集/精灵表中,而不是重新绑定你的纹理,你应该只绑定你的图集一次,然后绘制它的一小部分。如果你这样做,你应该能够绘制数千个没有真正减速的图块。

你可以像这样画出你的精灵:

//Push the matrix so we can keep it as it was previously.
glPushMatrix();

//Store the coordinates/dimensions from a rectangle.
float x = CGRectGetMinX(rect);
float y = CGRectGetMinY(rect);
float w = CGRectGetWidth(rect);
float h = CGRectGetHeight(rect);

float xOffset = x;
float yOffset = y;

if (rotation != 0.0f)
{
    //Translate the OpenGL context to the center of the sprite for rotation.
    glTranslatef(x+w/2, y+h/2, 0.0f);

    //Apply the rotation over the Z axis.
    glRotatef(rotation, 0.0f, 0.0f, 1.0f);

    //Have an offset for the top left corner.
    xOffset = -w/2;
    yOffset = -h/2;
}

// Set up an array of values to use as the sprite vertices.
GLfloat vertices[] =
{
    xOffset, yOffset,
    xOffset, yOffset+h,
    xOffset+w, yOffset+h,
    xOffset+w, yOffset,
};

// Set up an array of values for the texture coordinates.
GLfloat texcoords[] =
{
    CGRectGetMinX(clippingRect),    CGRectGetMinY(clippingRect),
    CGRectGetMinX(clippingRect),    CGRectGetHeight(clippingRect),
    CGRectGetWidth(clippingRect),   CGRectGetHeight(clippingRect),
    CGRectGetWidth(clippingRect),   CGRectGetMinY(clippingRect),
};

//If the image is flipped, flip the texture coordinates.
if (flipped)
{
    texcoords[0] = CGRectGetWidth(clippingRect);
    texcoords[2] = CGRectGetWidth(clippingRect);
    texcoords[4] = CGRectGetMinX(clippingRect);
    texcoords[6] = CGRectGetMinX(clippingRect);
}

//Render the vertices by pointing to the arrays.
glVertexPointer(2, GL_FLOAT, 0, vertices);
glTexCoordPointer(2, GL_FLOAT, 0, texcoords);

// Set the texture parameters to use a linear filter when minifying.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

//Allow transparency and blending.
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

//Enable 2D textures.
glEnable(GL_TEXTURE_2D);

//Bind this texture.
if ([Globals getLastTextureBound] != texture)
{
    glBindTexture(GL_TEXTURE_2D, texture);
}

//Finally draw the arrays.
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

//Restore the model view matrix to prevent contamination.
glPopMatrix();

我使用的两个CGRect只是为了放心。您可以指定绘制图像的X,Y,宽度和高度,还可以使用clippingRect指定要在图像中绘制的位置。使用裁剪矩形,(0,0,1,1)是整个图像,而(0,0,0.25,0.25)只绘制左上角。通过更改剪切矩形,您可以将各种不同的图块放在同一纹理中,然后您只需要绑定一次。方式更便宜。

答案 1 :(得分:0)

也可能使用glDrawTex扩展名。

答案 2 :(得分:0)

斯坦福大学iTune大学有一个关于优化iPhone的OpenGL的播客。

但基本的想法是这些:

  1. 批量几何,将各种顶点数组合成一个大的顶点数组。这应该将x个gl 指针调用的数量减少为单个gl 指针调用。

  2. 纹理地图集,对所有不同的图块使用单个纹理,差异是每个图块使用的区域。只需将纹理绑定到所有图块的纹理即可。

  3. Interleaved Arrays,将点的各个部分(例如顶点,纹理坐标,颜色)组合成一个数组。这应该将gl *指针调用减少到一次调用。

  4. 索引三角形,允许您重复使用几何信息

  5. 如果可能的话,使用Short而不是Float来获取几何信息,因为它更小。

  6. 这只是一般的opengl优化指南。至于瓷砖引擎,嗯..

    1. 在将数据发送到opengl之前进行自己的剔除。你没有画什么,你保存。
    2. 我认为这是我到目前为止所能想到的。

答案 3 :(得分:0)

Scott,TexParameter设置只需要每个纹理完成一次。但是,这不是您放缓的原因。

建立一个索引列表,并为整个tile集调用glDrawArrays一次会好得多。顶点数组的目标是允许您在一个步骤中尽可能多地绘制。

应该避免使用glDrawTex,因为它会迫使你进入非常低效的一次性思维模式。

答案 4 :(得分:0)

我做了什么来加快我的应用程序。在我加载我的水平之后。我在地图上用瓷砖创建了一个图册。然后我检查每一帧,看相机是否移动。如果它确实那么我只是传递glTranslatef并立即移动整个地图。如果只有动态对象在地图上移动,那么我只是在顶点数组图集中更新该对象。这个系统非常有效,因为我可以绘制大量没有帧率下降的瓷砖。

答案 5 :(得分:0)

只应在初始化时启用客户端状态,并且在创建纹理对象时也应调用glTexParameteri函数。 所有glEnable函数都不会被缓存,这意味着它将设置状态,即使它已经设置为该值。 所有这些小事都会加起来,让你慢下来。

BR