使用OpenGL ES在iPhone上平铺背景

使用OpenGL ES在iPhone上平铺背景,iphone,opengl-es,Iphone,Opengl Es,我想在iPhone上制作一个2D平铺背景系统。获取一个tilemap和tileset图像并将其转换为屏幕上的完整地图的东西 我的第一个方法是为每个瓷砖创建一个多边形,只是做了一些混乱。这很好,直到我开始测试400个多边形左右,然后它开始运行非常缓慢。我只是想知道——这种由几个多边形组成的方法难道不是可行的吗?还是我做错了什么?如果需要,我会稍后发布代码,但我的主要问题是“400个小多边形在iPhone上运行缓慢,还是我只是做错了什么?” 我还考虑了另一种方法,即在初始化期间,通过代码从tilem

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

我的第一个方法是为每个瓷砖创建一个多边形,只是做了一些混乱。这很好,直到我开始测试400个多边形左右,然后它开始运行非常缓慢。我只是想知道——这种由几个多边形组成的方法难道不是可行的吗?还是我做错了什么?如果需要,我会稍后发布代码,但我的主要问题是“400个小多边形在iPhone上运行缓慢,还是我只是做错了什么?”

我还考虑了另一种方法,即在初始化期间,通过代码从tilemap/tilesets中创建贴图纹理,然后将其粘贴到一个大多边形上。所以,是的……有没有关于我应该如何处理这类事情的反馈


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

使用
glDrawTex
扩展也可能是一种可能性。

使用
glDrawTex
扩展也可能是一种可能性。

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

但基本理念是:

  • 批处理几何体,将各种顶点阵列组合成单个大垂直阵列。这会将glPointer调用的x个数减少为单个glPointer调用

  • 纹理地图集,对所有不同的瓷砖使用单个纹理,差异是每个瓷砖要使用的区域。只需为所有平铺绘制绑定一次纹理

  • 交错阵列,将点的各个部分(例如顶点、纹理坐标、颜色)组合成单个阵列。这将把gl*指针调用减少为单个调用

  • 索引三角形,允许您重用几何图形信息

  • 如果可能的话,使用Short代替Float作为几何信息,因为它较小

  • 这只是一个通用的opengl优化指南。至于瓦片引擎,那么

  • 在将数据发送到opengl之前,请自己进行筛选。你不画的,你保存

  • 我想这就是我目前所能想到的。

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

    但基本理念是:

  • 批处理几何体,将各种顶点阵列组合成单个大垂直阵列。这会将glPointer调用的x个数减少为单个glPointer调用

  • 纹理地图集,对所有不同的瓷砖使用单个纹理,差异是每个瓷砖要使用的区域。只需为所有平铺绘制绑定一次纹理

  • 交错阵列,将点的各个部分(例如顶点、纹理坐标、颜色)组合成单个阵列。这将把gl*指针调用减少为单个调用

  • 索引三角形,允许您重用几何图形信息

  • 如果可能的话,使用Short代替Float作为几何信息,因为它较小

  • 这只是一个通用的opengl优化指南。至于瓦片引擎,那么

  • 在将数据发送到opengl之前,请自己进行筛选。你不画的,你保存

  • 我想这就是我目前所能想到的。

    你的问题几乎可以肯定是你绑定了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、宽度和高度,也可以指定要使用剪报在图像中绘制的位置。使用剪切矩形,(0,0,1,1)是整个图像,而(0,0,0.25,0.25)只绘制左上角。通过更改剪裁矩形,可以将各种不同的瓷砖放置在同一纹理中,然后只需绑定一次。便宜多了。

    你的问题几乎肯定是你要绑定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、宽度和高度,也可以指定要使用剪报在图像中绘制的位置。使用剪切矩形,(0,0,1,1)是整个图像,而(0,0,0.25,0.25)只绘制左上角。通过更改剪裁矩形,可以将各种不同的瓷砖放置在同一纹理中,然后只需绑定一次。便宜多了。

    Scott,每个纹理只需设置一次TexParameter。然而,这并不是你减速的原因

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


    应避免使用glDrawTex,因为它会迫使您陷入一次一个的低效思维模式。

    Scott,每个纹理只需进行一次TexParameter设置。然而,这并不是你减速的原因

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

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

    什么