7

タイルベースの OpenGL、C++ アプリケーションに取り組んでいます。より明確になるように、アプリケーションからサンプル画面を追加しています。

sの配列をTile含むクラスがありますObject。各タイルには最大 15 個のオブジェクトを格納できます。その例ではTile、緑と黄色の正方形 (2 つのオブジェクト) があるため、描画には 10x10x15 = 1500Object秒かかります (最悪の場合、「空の」ものを処理していないため) )。通常はそれより少なく、私のテストでは約 600 個使用しています。Object描画できる独自のグラフィックがあります。それぞれObjectが一度に 1 つに属しTileますが、移動することができます (たとえば、図の赤い四角のように)。

Object背景には境界線があり、適切にスケーラブルにする必要があるため、9 パッチ パターンを使用して描画しています (9 つのクワッドで構成されています)。

Tiles (正確にはそれらの s) を描画せずObjectに、私のアプリケーションには約600 fps.

最初は、 /とsTileを使用して、これらの s を描画するために時代遅れの方法を使用していました。その描画により、パフォーマンスが大幅に低下しました-から. これは私がそれらを描いてきた方法です:glBegin(GL_QUADS)glEnd()glDisplayList600320 fps

bool Background::draw(const TPoint& pos, int width, int height)
{
    if(width <= 0 || height <= 0)
        return false;
    //glFrontFace(GL_CW);
    glPushMatrix();
    glTranslatef((GLfloat)pos.x, (GLfloat)pos.y, 0.0f);     // Move background to right direction
    if((width != m_savedWidth) || (height != m_savedHeight))    // If size to draw is different than the one saved in display list,
        // then recalculate everything and save in display list
    {
        // That size will be now saved in display list
        m_savedWidth = width;
        m_savedHeight = height;

        // If this background doesn't have unique display list id specified yet,
        // then let OpenGL generate one
        if(m_displayListId == NO_DISPLAY_LIST_ID)
        {
            GLuint displayList;
            displayList = glGenLists(1);
            m_displayListId = displayList;
        }

        glNewList(m_displayListId, GL_COMPILE);

        GLfloat texelCentersOffsetX = (GLfloat)1/(2*m_width);

        // Instead of coordinates range 0..1 we need to specify new ones
        GLfloat maxTexCoordWidth = m_bTiling    ? (GLfloat)width/m_width    :   1.0;
        GLfloat maxTexCoordHeight = m_bTiling   ? (GLfloat)height/m_height  :   1.0;

        GLfloat maxTexCoordBorderX = (GLfloat)m_borderWidth/m_width;
        GLfloat maxTexCoordBorderY = (GLfloat)m_borderWidth/m_height;

        /* 9-cell-pattern

        -------------------
        | 1 |    2    | 3 |
        -------------------
        |   |         |   |
        | 4 |    9    | 5 |
        |   |         |   |
        -------------------
        | 6 |    7    | 8 |
        -------------------

        */

        glBindTexture(GL_TEXTURE_2D, m_texture);               // Select Our Texture

        // Top left quad [1]
        glBegin(GL_QUADS);
            // Bottom left
            glTexCoord2f(0.0, maxTexCoordBorderY);
            glVertex2i(0, 0 + m_borderWidth);

            // Top left
            glTexCoord2f(0.0, 0.0);
            glVertex2i(0, 0);

            // Top right
            glTexCoord2f(maxTexCoordBorderX, 0.0);
            glVertex2i(0 + m_borderWidth, 0);

            // Bottom right
            glTexCoord2f(maxTexCoordBorderX, maxTexCoordBorderY);
            glVertex2i(0 + m_borderWidth, 0 + m_borderWidth);
        glEnd();

        // Top middle quad [2]
        glBegin(GL_QUADS);
            // Bottom left
            glTexCoord2f(maxTexCoordBorderX + texelCentersOffsetX, maxTexCoordBorderY);
            glVertex2i(0 + m_borderWidth, 0 + m_borderWidth);

            // Top left
            glTexCoord2f(maxTexCoordBorderX + texelCentersOffsetX, 0.0);
            glVertex2i(0 + m_borderWidth, 0);

            // Top right
            glTexCoord2f((GLfloat)1.0 - maxTexCoordBorderX - texelCentersOffsetX, 0.0);
            glVertex2i(0 + width - m_borderWidth, 0);

            // Bottom right
            glTexCoord2f((GLfloat)1.0 - maxTexCoordBorderX - texelCentersOffsetX, maxTexCoordBorderY);
            glVertex2i(0 + width - m_borderWidth, 0 + m_borderWidth);
        glEnd();

        // Top right quad [3]
        glBegin(GL_QUADS);
            // Bottom left
            glTexCoord2f((GLfloat)1.0 - maxTexCoordBorderX, maxTexCoordBorderY);
            glVertex2i(0 + width - m_borderWidth, 0 + m_borderWidth);

            // Top left
            glTexCoord2f((GLfloat)1.0 - maxTexCoordBorderX, 0.0);
            glVertex2i(0 + width - m_borderWidth, 0);

            // Top right
            glTexCoord2f(1.0, 0.0);
            glVertex2i(0 + width, 0);

            // Bottom right
            glTexCoord2f(1.0, maxTexCoordBorderY);
            glVertex2i(0 + width, 0 + m_borderWidth);
        glEnd();

        // Middle left quad [4]
        glBegin(GL_QUADS);
            // Bottom left
            glTexCoord2f(0.0, (GLfloat)1.0 - maxTexCoordBorderY );
            glVertex2i(0, 0 + height - m_borderWidth);

            // Top left
            glTexCoord2f(0.0, maxTexCoordBorderY );
            glVertex2i(0, 0 + m_borderWidth);

            // Top right
            glTexCoord2f(maxTexCoordBorderX, maxTexCoordBorderY );
            glVertex2i(0 + m_borderWidth, 0 + m_borderWidth);

            // Bottom right
            glTexCoord2f(maxTexCoordBorderX, (GLfloat)1.0 - maxTexCoordBorderY );
            glVertex2i(0 + m_borderWidth, 0 + height - m_borderWidth);
        glEnd();

        // Middle right quad [5]
        glBegin(GL_QUADS);
            // Bottom left
            glTexCoord2f((GLfloat)1.0 - maxTexCoordBorderX, (GLfloat)1.0 - maxTexCoordBorderY);
            glVertex2i(0 + width - m_borderWidth, 0 + height - m_borderWidth);

            // Top left
            glTexCoord2f((GLfloat)1.0 - maxTexCoordBorderX, maxTexCoordBorderY);
            glVertex2i(0 + width - m_borderWidth, 0 + m_borderWidth);

            // Top right
            glTexCoord2f(1.0, maxTexCoordBorderY);
            glVertex2i(0 + width, 0 + m_borderWidth);

            // Bottom right
            glTexCoord2f(1.0, (GLfloat)1.0 - maxTexCoordBorderY);
            glVertex2i(0 + width, 0 + height - m_borderWidth);
        glEnd();

        // Bottom left quad [6]
        glBegin(GL_QUADS);
            // Bottom left
            glTexCoord2f(0.0f, 1.0);
            glVertex2i(0, 0 + height);

            // Top left
            glTexCoord2f(0.0f, (GLfloat)1.0 - maxTexCoordBorderY);
            glVertex2i(0, 0 + height - m_borderWidth);

            // Top right
            glTexCoord2f(maxTexCoordBorderX, (GLfloat)1.0 - maxTexCoordBorderY);
            glVertex2i(0 + m_borderWidth, 0 + height - m_borderWidth);

            // Bottom right
            glTexCoord2f(maxTexCoordBorderX, 1.0);
            glVertex2i(0 + m_borderWidth, 0 + height);
        glEnd();

        // Bottom middle quad [7]
        glBegin(GL_QUADS);
            // Bottom left
            glTexCoord2f(maxTexCoordBorderX + texelCentersOffsetX, 1.0);
            glVertex2i(0 + m_borderWidth, 0 + height);

            // Top left
            glTexCoord2f(maxTexCoordBorderX + texelCentersOffsetX, (GLfloat)1.0 - maxTexCoordBorderY);
            glVertex2i(0 + m_borderWidth, 0 + height - m_borderWidth);

            // Top right
            glTexCoord2f((GLfloat)1.0 - maxTexCoordBorderX - texelCentersOffsetX, (GLfloat)1.0 - maxTexCoordBorderY);
            glVertex2i(0 + width - m_borderWidth, 0 + height - m_borderWidth);

            // Bottom right
            glTexCoord2f((GLfloat)1.0 - maxTexCoordBorderX - texelCentersOffsetX, 1.0);
            glVertex2i(0 + width - m_borderWidth, 0 + height);
        glEnd();

        // Bottom right quad [8]
        glBegin(GL_QUADS);
            // Bottom left
            glTexCoord2f((GLfloat)1.0 - maxTexCoordBorderX, 1.0);
            glVertex2i(0 + width - m_borderWidth, 0 + height);

            // Top left
            glTexCoord2f((GLfloat)1.0 - maxTexCoordBorderX, (GLfloat)1.0 - maxTexCoordBorderY);
            glVertex2i(0 + width - m_borderWidth, 0 + height - m_borderWidth);

            // Top right
            glTexCoord2f(1.0, (GLfloat)1.0 - maxTexCoordBorderY);
            glVertex2i(0 + width, 0 + height - m_borderWidth);

            // Bottom right
            glTexCoord2f(1.0, 1.0);
            glVertex2i(0 + width, 0 + height);
        glEnd();

        GLfloat xTexOffset;
        GLfloat yTexOffset;

        if(m_borderWidth > 0)
        {
            glBindTexture(GL_TEXTURE_2D, m_centerTexture);     // If there's a border, we have to use
            // second texture now for middle quad
            xTexOffset = 0.0;                                  // We are using another texture, so middle middle quad
            yTexOffset = 0.0;                                  // has to be texture with a whole texture
        }
        else
        {
            // Don't bind any texture here - we're still using the same one

            xTexOffset = maxTexCoordBorderX;                   // But it implies using offset which equals
            yTexOffset = maxTexCoordBorderY;                   // maximum texture coordinates
        }

        // Middle middle quad [9]
        glBegin(GL_QUADS);
            // Bottom left
            glTexCoord2f(xTexOffset, maxTexCoordHeight - yTexOffset);
            glVertex2i(0 + m_borderWidth, 0 + height - m_borderWidth);

            // Top left
            glTexCoord2f(xTexOffset, yTexOffset);
            glVertex2i(0 + m_borderWidth, 0 + m_borderWidth);

            // Top right
            glTexCoord2f(maxTexCoordWidth - xTexOffset, yTexOffset);
            glVertex2i(0 + width - m_borderWidth, 0 + m_borderWidth);

            // Bottom right
            glTexCoord2f(maxTexCoordWidth - xTexOffset, maxTexCoordHeight - yTexOffset);
            glVertex2i(0 + width - m_borderWidth, 0 + height - m_borderWidth);
        glEnd();

        glEndList();
    }

    glCallList(m_displayListId); // Now we can call earlier or now created display list

    glPopMatrix();

    return true;
}

コードが多すぎるかもしれませんが、すべてを表示したかったのです。このバージョンの主な点は、glVertex2i非推奨のディスプレイ リストの使用です。

このような速度低下の問題は、私が読んだこの時代遅れの方法の使用が非常に遅いと思ったので、に行くことにしましたVBO。私はこのチュートリアルを使用しましたが、それに従って、方法を次のように変更しました。

bool Background::draw(const TPoint& pos, int width, int height)
{
    if(width <= 0 || height <= 0)
        return false;

    glPushMatrix();
    glTranslatef((GLfloat)pos.x, (GLfloat)pos.y, 0.0f);             // Move background to right direction
    if((width != m_savedWidth) || (height != m_savedHeight))        // If size to draw is different than the one saved in display list,
                                                                    // then recalculate everything and save in display list
    {
        // That size will be now saved in display list
        m_savedWidth = width;
        m_savedHeight = height;

        GLfloat texelCentersOffsetX = (GLfloat)1/(2*m_width);

        // Instead of coordinates range 0..1 we need to specify new ones
        GLfloat maxTexCoordWidth = m_bTiling    ? (GLfloat)width/m_width    :   1.0;
        GLfloat maxTexCoordHeight = m_bTiling   ? (GLfloat)height/m_height  :   1.0;

        GLfloat maxTexCoordBorderX = (GLfloat)m_borderWidth/m_width;
        GLfloat maxTexCoordBorderY = (GLfloat)m_borderWidth/m_height;

        /* 9-cell-pattern, each number represents one quad

        -------------------
        | 1 |    2    | 3 |
        -------------------
        |   |         |   |
        | 4 |    9    | 5 |
        |   |         |   |
        -------------------
        | 6 |    7    | 8 |
        -------------------

        */

        /* How vertices are distributed on one quad made of two triangles

        v1 ------ v0
        |       /  |
        |     /    |
        |  /       |
        v2 ------ v3

        */

        GLfloat vertices[] = { 
                                // Top left quad [1]
                                m_borderWidth, 0, 0,                            // v0
                                0, 0, 0,                                        // v1       
                                0, m_borderWidth, 0,                            // v2               

                                0, m_borderWidth, 0,                            // v2
                                m_borderWidth, m_borderWidth, 0,                // v3
                                m_borderWidth, 0, 0,                            // v0

                                // Top middle quad [2]
                                width-m_borderWidth, 0, 0,                      // v0
                                m_borderWidth, 0, 0,                            // v1
                                m_borderWidth, m_borderWidth, 0,                // v2

                                m_borderWidth, m_borderWidth, 0,                // v2
                                width-m_borderWidth, m_borderWidth, 0,          // v3
                                width-m_borderWidth, 0, 0,                      // v0

                                // Top right quad [3]
                                width, 0, 0,                                    // v0  
                                width-m_borderWidth, 0, 0,                      // v1
                                width-m_borderWidth, m_borderWidth, 0,          // v2

                                width-m_borderWidth, m_borderWidth, 0,          // v2
                                width, m_borderWidth, 0,                        // v3
                                width, 0, 0,                                    // v0

                                // Middle left quad [4]
                                m_borderWidth, m_borderWidth, 0,                // v0
                                0, m_borderWidth, 0,                            // v1
                                0, height-m_borderWidth, 0,                     // v2

                                0, height-m_borderWidth, 0,                     // v2
                                m_borderWidth, height-m_borderWidth, 0,         // v3
                                m_borderWidth, m_borderWidth, 0,                // v0

                                // Middle right quad [5]
                                width, m_borderWidth, 0,                        // v0
                                width-m_borderWidth, m_borderWidth, 0,          // v1
                                width-m_borderWidth, height-m_borderWidth, 0,   // v2

                                width-m_borderWidth, height-m_borderWidth, 0,   // v2
                                width, height-m_borderWidth, 0,                 // v3
                                width, m_borderWidth, 0,                        // v0

                                // Bottom left quad [6]
                                m_borderWidth, height-m_borderWidth, 0,         // v0
                                0, height-m_borderWidth, 0,                     // v1
                                0, height, 0,                                   // v2

                                0, height, 0,                                   // v2
                                m_borderWidth, height, 0,                       // v3
                                m_borderWidth, height-m_borderWidth, 0,         // v0

                                // Bottom middle quad [7]
                                width-m_borderWidth, height-m_borderWidth, 0,   // v0
                                m_borderWidth, height-m_borderWidth, 0,         // v1
                                m_borderWidth, height, 0,                       // v2

                                m_borderWidth, height, 0,                       // v2
                                width-m_borderWidth, height, 0,                 // v3
                                width-m_borderWidth, height-m_borderWidth, 0,   // v0

                                // Bottom right quad [8]
                                width, height-m_borderWidth, 0,                 // v0
                                width-m_borderWidth, height-m_borderWidth, 0,   // v1
                                width-m_borderWidth, height, 0,                 // v2

                                width-m_borderWidth, height, 0,                 // v2
                                width, height, 0,                               // v3
                                width, height-m_borderWidth, 0,                 // v0

                                // Middle middle quad [9]
                                width-m_borderWidth, m_borderWidth, 0,          // v0
                                m_borderWidth, m_borderWidth, 0,                // v1
                                m_borderWidth, height-m_borderWidth, 0,         // v2

                                m_borderWidth, height-m_borderWidth, 0,         // v2
                                width-m_borderWidth, height-m_borderWidth, 0,   // v3
                                width-m_borderWidth, m_borderWidth, 0           // v0
                            };

        copy(vertices, vertices + 162, m_vCoords);              // 162, because we have 162 coordinates 


        int dataSize = 162 * sizeof(GLfloat);
        m_vboId = createVBO(m_vCoords, dataSize);

    }

    // bind VBOs for vertex array
    glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_vboId);          // for vertex coordinates

    glEnableClientState(GL_VERTEX_ARRAY);                   // activate vertex coords array
        glVertexPointer(3, GL_FLOAT, 0, 0);                     
        glDrawArrays(GL_TRIANGLES, 0, 162);
    glDisableClientState(GL_VERTEX_ARRAY);                  // deactivate vertex array

    // bind with 0, so, switch back to normal pointer operation
    glBindBufferARB(GL_ARRAY_BUFFER_ARB, NO_VBO_ID);

    glPopMatrix();

    return true;
}

これは以前のバージョンと非常に似ていますが、配列に格納されたデータから作成されるものを代わりglDisplayListglVertex2i()使用しました。VBO

しかし、結果は私を失望させました.ブーストの代わりにパフォーマンスが低下したため、かろうじて得 ~260 fpsられました.このメソッドバージョンではまだテクスチャの使用を実装していないことに注意する必要があります.

このような速度低下の理由を見つけるためにいくつかの記事を読んだところ、大量の小さなVBOs が原因である可能性があり、おそらく背景ごとVBOに個別ではなく、すべての背景データを含むものを用意する必要があることがわかりました。VBOしかし、問題は、Objectが動き回ることができ、テクスチャが異なることです (テクスチャ アトラスは私にとっては良い解決策ではありません)。そのため、状態を変更した の変更を更新するのは難しいでしょうObject。今のところ、Objects が変更されているときは、それを再作成するだけVBOで、残りの s は変更さVBOれません。

だから私の質問は - 私が間違っているのは何ですか? より大きな数 (~600) の小さなVBOs を使用すると、時代遅れの描画方法よりも本当に遅くなりglVertex2iますか? そして、私の場合、最善ではないかもしれませんが、より良い解決策は何でしょうか?

4

2 に答える 2

7

見たところ、すべてのフレームで VBO を再作成しています。データを変更したいだけの場合は、長い VBO の初期化全体をglBufferSubData実行します。glBufferData

データが静的な場合は、VBO を 1 回だけ作成してから再利用します。

于 2013-02-27T16:23:58.367 に答える
3

固定機能のものは古く、非推奨であり、一般的に推奨されていないからといって、常に遅いとは限りません。

また、バッファーやシェーダーなどを備えた派手な「新しい」機能 (しばらく前からあります) は、必ずしもすべてが電光石火の速さになることを意味するわけではありません。

描画を表示リストにラップすると、基本的に一連の操作がドライバーに渡されます。これにより、ドライバーが何が起こっているかを最適化するためのかなりの範囲が実際に与えられます。実行していることのほとんどを、非常に効率的な事前にパッケージ化された GPU 操作の塊にパッケージ化することができます。これは、データをバッファにパッケージ化して送信する場合よりもわずかに効率的かもしれません。

古いスタイルのインターフェイスを使い続けることをお勧めするわけではありませんが、古いスタイルのインターフェイスがうまく機能する場合があることは確かに驚くことではありません。

于 2013-02-27T17:33:15.543 に答える