OpenGL结合纹理

问题描述 投票:1回答:2

我正在OpenGL中编写2D游戏,我必须输出一个包含20x15字段的关卡。

因此,我目前正在为每个字段输出非常慢的纹理(每帧300个纹理)。

但是由于级别永远不会改变的原因,我想知道是否有可能在游戏循环开始之前将纹理组合成一个大的单一纹理。

然后,我只需要输出一个具有4个纹理坐标(0/0)(0/1)(1/1)(1/0)和4个glVertex2f()的纹理,即可指定窗口中的位置。

这是我当前针对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();

请注意,我在一个.tga文件中具有所有可能的字段类型的图像。因此,我正在使用glTexCoord2f()选择正确的选项。

具有所有图块的图像文件已加载到

GLuint textur;

所以我为每个字段绑定了相同的纹理。

我的目标是减少CPU时间。显示列表不起作用,因为图形卡中要加载的数据太多,最终显示列表甚至更慢。

我也无法使用VBO,因为我没有使用GLUT这样的扩展。

所以我的想法是生成一个简单而有效的纹理。

我希望您能给我反馈如何组合纹理以及该方法是否是最容易提高性能的方法

编辑:这是我在程序中使用的OpenGl功能:

启动程序时,初始化窗口:

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();
}
performance opengl glfw
2个回答
2
投票

我看到您正在使用GLFW。您可以添加GLEW和GLM,然后应使用OpenGL 3.x或更高版本。

这里是一个完整的示例,如何在丢失预算的笔记本电脑上轻松绘制2000个FPS为200或更高的带纹理的四边形(带有Alphablending)或更多。它只有一个小的Texture,但是它也可以与4096x4096 Texture Atlas一起使用。如果大纹理中的“子纹理”尺寸与您绘制的“四边形”尺寸完全匹配,您将获得一个“巨大的性能命中率”!您也应该在大纹理中使用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);
}

1
投票

我现在确定了一个巨大的时间杀手。我使用的纹理太大,分辨率非常低。包含级别精灵的主纹理的分辨率为2200x2200像素。因此,GPU将大小增加到4096x4096,并使用大量数据进行了计算。图像包含10x10个不同的Level-Tiles,它们在屏幕上输出,每个分辨率为50x50像素。因此,我以较低的分辨率(1020 x 1020像素->每个tile = 102x102px)保存了Tiles-File,现在我的循环循环时间为<= 15ms。这并不完美,但是与我之前的30-60ms相比,这是一个巨大的进步。

© www.soinside.com 2019 - 2024. All rights reserved.