1

OpenGLで2Dゲームをプログラミングしていて、20x15フィールドで構成されるレベルを出力する必要があります。

そのため、現在、各フィールドのテクスチャを出力していますが、これは非常に低速です(300テクスチャ/フレーム)。

しかし、レベルが変わらないという理由で、ゲームループが始まる前にテクスチャを大きな単一のテクスチャに結合することは可能かどうか疑問に思いました。

次に、4つのテクスチャ座標(0/0)(0/1)(1/1)(1/0)とウィンドウ内の位置を指定する4つのglVertex2f()を持つ1つのテクスチャのみを出力する必要があります。

これは、300フィールドのそれぞれに対する私の現在のコードです。

glColor3f(1,1,1);
glBindTexture(GL_TEXTURE_2D,textur);
glBegin(GL_QUADS);
    glTexCoord2f(textArea.a.x,textArea.b.y);glVertex2f(display.a.x,display.a.y);
    glTexCoord2f(textArea.a.x,textArea.a.y);glVertex2f(display.a.x,display.b.y);
    glTexCoord2f(textArea.b.x,textArea.a.y);glVertex2f(display.b.x,display.b.y);
    glTexCoord2f(textArea.b.x,textArea.b.y);glVertex2f(display.b.x,display.a.y);
glEnd();

1つの.tgaファイルにすべての可能なフィールドタイプの画像があることに注意してください。だから私はglTexCoord2f()で正しいものを選んでいます。

すべてのタイルを含む画像ファイルがロードされます

GLuint textur;

したがって、すべてのフィールドに同じテクスチャをバインドします。

私の目標はCPU時間を減らすことです。グラフィックカードにロードするデータが非常に多いため、ディスプレイリストは機能しませんでした。その結果、ディスプレイリストはさらに遅くなりました。

また、GLUTのような拡張機能を使用していないため、VBOを使用できませんでした。

だから私のアイデアは、非常に簡単で効果的な単一のテクスチャを生成することでした。

テクスチャを組み合わせる方法と、この方法がパフォーマンスを向上させる最も簡単な方法であるかどうかについて、フィードバックをお寄せいただければ幸いです。

編集:それは私が私のプログラムで使用するOpenGl-Functionsです:

プログラムを起動すると、ウィンドウが初期化されます。

glfwInit();                     
if( !glfwOpenWindow(windowSize.x,windowSize.y, 0, 0, 0, 0, 0, 0, GLFW_WINDOW ) ) 
{   glfwTerminate();           
    return;
}

そして、それがゲームループがOpenGで行うことのすべてです。

int main()
{
    //INIT HERE (see code above)

    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_BLEND);                                
    glAlphaFunc(GL_GREATER,0.1f);
    glEnable(GL_ALPHA_TEST);

    long loopStart;//measure loopcycle-time
    do{
        height = height > 0 ? height : 1;
        glViewport( 0, 0, width, height );              //set Origin
        glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );      //background-color
        glClear(GL_COLOR_BUFFER_BIT);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();                      
        glOrtho(0,windowSize.x,0,windowSize.y,0,128);   //2D-Mode
        glMatrixMode(GL_MODELVIEW);
        loopStart=clock();

        //(...) OUTPUT HERE (code see above)

        glfwSwapBuffers();                              //erzeugte Grafikdaten ausgeben

        printf("%4dms -> ",clock()-loopStart);
    }while(...);

    glDisable(GL_ALPHA_TEST);
    glDisable(GL_TEXTURE_2D);
    glfwTerminate();
}
4

2 に答える 2

2

GLFWを使用しているようです。GLEWとGLMを追加してから、OpenGL3.x以降を使用する必要があります。

これは完全な例です。失われた予算のラップトップで、FPSが200以上の場合に2000テクスチャクワッド(アルファブレンドあり)以上を簡単に描画する方法を示します。テクスチャは1つしかありませんが、4096x4096テクスチャアトラスでも機能します。大きなテクスチャのサブテクスチャサイズが描画するクワッドのサイズと正確に一致する場合は、1つの大きなパフォーマンスが得られます。ビッグテクスチャでも50x50ピクセルを使用する必要があります。次のDeme-Codeも、フレームごとにすべての2000 Quadを更新し、GPUに送信します。フレームごとに更新して、スクロール座標をシェーダーに配置する必要がない場合は、パフォーマンスが再び向上します。ブレンディングが必要ない場合は、Alpha-Testsを使用してください。速度が再び向上します。

#define GLEW_STATIC
#include "glew.h"
#include "glfw.h"
#include "glm.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "glm/gtx/transform.hpp"
#include <sstream>
#include <fstream>
#include <vector>

#define BUFFER_OFFSET(i) ((char *)NULL + (i))

std::ofstream logger("Log\\Ausgabe.txt", (std::ios::out | std::ios::app));

class Vertex
{
public:
    float x;
    float y;
    float z;
    float tx;
    float ty;
};

class Quad
{
public:
    float x;
    float y;
    float width;
    float height;
};

int getHighResTimeInMilliSeconds(bool bFirstRun);
GLuint buildShader();
void addQuadToLocalVerticeArray(Vertex * ptrVertexArrayLocal, Quad *quad, int *iQuadCounter);

int main()
{
    logger << "Start" << std::endl;

    if(!glfwInit())
        exit(EXIT_FAILURE);

    glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR,3);
    glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR,3);
    glfwOpenWindowHint(GLFW_OPENGL_FORWARD_COMPAT, 1);
    glfwOpenWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE);

    if( !glfwOpenWindow(1366, 768,8,8,8,8,32,32,GLFW_FULLSCREEN) )
    {
        glfwTerminate();
        exit( EXIT_FAILURE );
    }

    if (glewInit() != GLEW_OK)
        exit( EXIT_FAILURE );

    //Init
    GLuint VertexArrayID;
    GLuint vertexbuffer;
    GLuint MatrixID;
    GLuint TextureID;
    GLuint Texture;

    GLuint programID = buildShader();

    //Texture in Video-Speicher erstellen
    GLFWimage img;
    int iResult = glfwReadImage("Graphics\\gfx.tga", &img, GLFW_NO_RESCALE_BIT);

    glEnable(GL_TEXTURE_2D);
    glGenTextures(1, &Texture);
    glBindTexture(GL_TEXTURE_2D, Texture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,32,32, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.Data);
    glfwFreeImage(&img);

    Vertex * ptrVertexArrayLocal = new Vertex[12000];

    glGenVertexArrays(1, &VertexArrayID);
    glBindVertexArray(VertexArrayID);
    glGenBuffers(1, &vertexbuffer);
    glBindBuffer(GL_ARRAY_BUFFER, VertexArrayID);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * 12000, NULL, GL_DYNAMIC_DRAW);

    glm::mat4 Projection = glm::ortho(0.0f, (float)1366,0.0f, (float)768, 0.0f, 100.0f);
    glm::mat4 Model      = glm::mat4(1.0f); 
    glm::mat4 MVP        = Projection * Model;

    glViewport( 0, 0, 1366, 768 ); 

    MatrixID = glGetUniformLocation(programID, "MVP");
    glEnable(GL_CULL_FACE);
    glEnable (GL_BLEND); 
    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    TextureID  = glGetUniformLocation(programID, "myTextureSampler");

    glUseProgram(programID);

    glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, Texture);
    glUniform1i(TextureID, 0);

    int iQuadVerticeCounter=0;

    int iNumOfQuads = 2000;
    Quad * ptrQuads = new Quad[iNumOfQuads];

    //LOCAL VERTICES CHANGES EACH LOOP
    for (int i=0; i<iNumOfQuads; i++)
    {
        ptrQuads[i].width  = 32;
        ptrQuads[i].height = 32;
        ptrQuads[i].x      = (float)(rand() % (1334));
        ptrQuads[i].y      = (float)(rand() % (736));
    }

    int iCurrentTime=0;
    int iFPS=0;
    int iFrames=0;
    int iFrameCounterTimeStart=0;
    int running = GL_TRUE;

    bool bFirstRun=true;

    while( running )
    {
        iCurrentTime = getHighResTimeInMilliSeconds(bFirstRun);
        bFirstRun=false;

        //UPDATE ALL QUADS EACH FRAME!
        for (int i=0; i<iNumOfQuads; i++)
        {
            ptrQuads[i].width  = 32;
            ptrQuads[i].height = 32;
            ptrQuads[i].x      = ptrQuads[i].x;
            ptrQuads[i].y      = ptrQuads[i].y;
            addQuadToLocalVerticeArray(ptrVertexArrayLocal, &ptrQuads[i], &iQuadVerticeCounter);
        }

        //DO THE RENDERING
        glClear( GL_COLOR_BUFFER_BIT );

        glBindBuffer(GL_ARRAY_BUFFER, VertexArrayID);
        glBufferSubData(GL_ARRAY_BUFFER, 0,sizeof(Vertex) * iQuadVerticeCounter, ptrVertexArrayLocal);

        glEnableVertexAttribArray(0);
        glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
        glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,sizeof(Vertex),BUFFER_OFFSET(0));

        glEnableVertexAttribArray(1);
        glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
        glVertexAttribPointer(1,2,GL_FLOAT,GL_FALSE,sizeof(Vertex),BUFFER_OFFSET(3*sizeof(GL_FLOAT)));

        glDrawArrays(GL_TRIANGLES, 0, iQuadVerticeCounter);

        glDisableVertexAttribArray(0);
        glDisableVertexAttribArray(1);

        iQuadVerticeCounter=0;

        glfwSwapBuffers();

        //END OF DOING THE RENDERING

        running = !glfwGetKey( GLFW_KEY_ESC ) &&glfwGetWindowParam( GLFW_OPENED );

        iFrames++;

        if (iCurrentTime >= iFrameCounterTimeStart + 1000.0f)
        {
            iFPS = (int)((iCurrentTime - iFrameCounterTimeStart) / 1000.0f * iFrames);
            iFrameCounterTimeStart = iCurrentTime;
            iFrames = 0;
            logger << "FPS: " << iFPS << std::endl;
        }
    }

    glfwTerminate();
    exit( EXIT_SUCCESS );
}

int getHighResTimeInMilliSeconds(bool bFirstRun)
{
    if (bFirstRun)
        glfwSetTime(0);

    return (int)((float)glfwGetTime()*1000.0f);
}

GLuint buildShader()
{
    //Hint: Shader in the TXT-File looks like this
    /*std::stringstream ssVertexShader;
    ssVertexShader << "#version 330 core"<< std::endl 
                   <<   "layout(location = 0) in vec3 vertexPosition_modelspace;"<< std::endl
                   <<   "layout(location = 1) in vec2 vertexUV;"<< std::endl
                   <<   "out vec2 UV;"<< std::endl
                   <<   "uniform mat4 MVP;"<< std::endl
                   <<   "void main(){"<< std::endl
                   <<   "vec4 v = vec4(vertexPosition_modelspace,1);"<< std::endl
                   <<   "gl_Position = MVP * v;"<< std::endl
                   <<   "UV = vertexUV;"<< std::endl
                   <<   "}"<< std::endl;*/


    std::string strVertexShaderCode;
    std::ifstream VertexShaderStream("Shader\\VertexShader.txt", std::ios::in);
    if(VertexShaderStream.is_open())
    {
        std::string Line = "";
        while(getline(VertexShaderStream, Line))
            strVertexShaderCode += "\n" + Line;

        VertexShaderStream.close();
    }

    //Hint: Shader in the TXT-File looks like this
    /*std::stringstream ssFragmentShader;
    ssFragmentShader << "#version 330 core\n"
                      "in vec2 UV;\n"
                      "out vec4 color;\n"
                      "uniform sampler2D myTextureSampler;\n"
                      "void main(){\n"
                      "color = texture( myTextureSampler, UV ).rgba;\n"
                      "}\n";*/


    std::string strFragmentShaderCode;
    std::ifstream FragmentShaderStream("Shader\\FragmentShader.txt", std::ios::in);
    if(FragmentShaderStream.is_open())
    {
        std::string Line = "";
        while(getline(FragmentShaderStream, Line))
            strFragmentShaderCode += "\n" + Line;

        FragmentShaderStream.close();
    }

    GLuint gluiVertexShaderId = glCreateShader(GL_VERTEX_SHADER);
    char const * VertexSourcePointer = strVertexShaderCode.c_str();
    glShaderSource(gluiVertexShaderId, 1, &VertexSourcePointer , NULL);
    glCompileShader(gluiVertexShaderId);

    GLint Result = GL_FALSE;
    int InfoLogLength;
    glGetShaderiv(gluiVertexShaderId, GL_COMPILE_STATUS, &Result);
    glGetShaderiv(gluiVertexShaderId, GL_INFO_LOG_LENGTH, &InfoLogLength);
    std::vector<char> VertexShaderErrorMessage(InfoLogLength);
    glGetShaderInfoLog(gluiVertexShaderId, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
    std::string strInfoLog = std::string(&VertexShaderErrorMessage[0]);

    GLuint gluiFragmentShaderId = glCreateShader(GL_FRAGMENT_SHADER);
    char const * FragmentSourcePointer = strFragmentShaderCode.c_str();
    glShaderSource(gluiFragmentShaderId, 1, &FragmentSourcePointer , NULL);
    glCompileShader(gluiFragmentShaderId);

    Result = GL_FALSE;
    glGetShaderiv(gluiFragmentShaderId, GL_COMPILE_STATUS, &Result);
    glGetShaderiv(gluiFragmentShaderId, GL_INFO_LOG_LENGTH, &InfoLogLength);
    std::vector<char> FragmentShaderErrorMessage(InfoLogLength);
    glGetShaderInfoLog(gluiFragmentShaderId, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
    strInfoLog = std::string(&FragmentShaderErrorMessage[0]);

    GLuint gluiProgramId = glCreateProgram();
    glAttachShader(gluiProgramId, gluiVertexShaderId);
    glAttachShader(gluiProgramId, gluiFragmentShaderId);
    glLinkProgram(gluiProgramId);

    Result = GL_FALSE;
    glGetProgramiv(gluiProgramId, GL_LINK_STATUS, &Result);
    glGetProgramiv(gluiProgramId, GL_INFO_LOG_LENGTH, &InfoLogLength);
    std::vector<char> ProgramErrorMessage( std::max(InfoLogLength, int(1)) );
    glGetProgramInfoLog(gluiProgramId, InfoLogLength, NULL, &ProgramErrorMessage[0]);
    strInfoLog = std::string(&ProgramErrorMessage[0]);

    glDeleteShader(gluiVertexShaderId);
    glDeleteShader(gluiFragmentShaderId);
    return gluiProgramId;
}

void addQuadToLocalVerticeArray(Vertex * ptrVertexArrayLocal, Quad *quad, int *ptrQuadVerticeCounter)
{
    //Links oben
    ptrVertexArrayLocal[*ptrQuadVerticeCounter].x  = quad->x;
    ptrVertexArrayLocal[*ptrQuadVerticeCounter].y  = quad->y;
    ptrVertexArrayLocal[*ptrQuadVerticeCounter].z  = 0.0f;
    ptrVertexArrayLocal[*ptrQuadVerticeCounter].tx = 0.0f;
    ptrVertexArrayLocal[*ptrQuadVerticeCounter].ty = 1.0f;

    ++(*ptrQuadVerticeCounter);

    //Links unten
    ptrVertexArrayLocal[*ptrQuadVerticeCounter].x  = quad->x;
    ptrVertexArrayLocal[*ptrQuadVerticeCounter].y  = quad->y - quad->height;
    ptrVertexArrayLocal[*ptrQuadVerticeCounter].z  = 0.0f;
    ptrVertexArrayLocal[*ptrQuadVerticeCounter].tx = 0.0f;
    ptrVertexArrayLocal[*ptrQuadVerticeCounter].ty = 0.0f;

    ++(*ptrQuadVerticeCounter);

    //Rechts unten
    ptrVertexArrayLocal[*ptrQuadVerticeCounter].x  = quad->x + quad->width;
    ptrVertexArrayLocal[*ptrQuadVerticeCounter].y  = quad->y - quad->height;
    ptrVertexArrayLocal[*ptrQuadVerticeCounter].z  = 0.0f;
    ptrVertexArrayLocal[*ptrQuadVerticeCounter].tx = 1.0f;
    ptrVertexArrayLocal[*ptrQuadVerticeCounter].ty = 0.0f;

    ++(*ptrQuadVerticeCounter);

    //Rechts unten
    ptrVertexArrayLocal[*ptrQuadVerticeCounter].x  = quad->x + quad->width;
    ptrVertexArrayLocal[*ptrQuadVerticeCounter].y  = quad->y - quad->height;
    ptrVertexArrayLocal[*ptrQuadVerticeCounter].z  = 0.0f;
    ptrVertexArrayLocal[*ptrQuadVerticeCounter].tx = 1.0f;
    ptrVertexArrayLocal[*ptrQuadVerticeCounter].ty = 0.0f;

    ++(*ptrQuadVerticeCounter);

    //Rechts oben
    ptrVertexArrayLocal[*ptrQuadVerticeCounter].x  = quad->x + quad->width;
    ptrVertexArrayLocal[*ptrQuadVerticeCounter].y  = quad->y;
    ptrVertexArrayLocal[*ptrQuadVerticeCounter].z  = 0.0f;
    ptrVertexArrayLocal[*ptrQuadVerticeCounter].tx = 1.0f;
    ptrVertexArrayLocal[*ptrQuadVerticeCounter].ty = 1.0f;

    ++(*ptrQuadVerticeCounter);

    //Links oben
    ptrVertexArrayLocal[*ptrQuadVerticeCounter].x  = quad->x;
    ptrVertexArrayLocal[*ptrQuadVerticeCounter].y  = quad->y;
    ptrVertexArrayLocal[*ptrQuadVerticeCounter].z  = 0.0f;
    ptrVertexArrayLocal[*ptrQuadVerticeCounter].tx = 0.0f;
    ptrVertexArrayLocal[*ptrQuadVerticeCounter].ty = 1.0f;

    ++(*ptrQuadVerticeCounter);
}
于 2013-04-22T20:48:38.830 に答える
1

私は今、巨大なタイムキラーを特定しました。私が使用していたテクスチャは大きすぎて、解像度は非常に非効率的でした。

レベルスプライトを含むメインテクスチャの解像度は2200x2200ピクセルでした。そのため、GPUはサイズを4096x4096に増やし、大量のデータを使用して計算しました。

画像には、それぞれ50x50ピクセルの解像度で画面に出力される10x10の異なるレベルタイルが含まれています。
そこで、タイルファイルを低解像度(1020 x1020ピクセル->各タイル=102x102px)で保存しましたが、ループサイクル時間は<=15msになりました。
これは完璧ではありませんが、以前の30〜60ミリ秒と比較すると、大きな進歩でした。

于 2012-11-13T12:51:19.890 に答える