使用Opengl缓冲区时屏幕损坏

时间:2013-09-07 13:06:39

标签: c++ opengl sfml

我正在编写一个Opengl游戏但是我在使用Opengl缓冲区时遇到了一些问题。

我的旧代码有效(但有很多CPU消耗和低fps)看起来像这样:

void Terrain::drawObject(sf::RenderWindow* window)
{
    float scale = 5.0f / max(width_ - 1, length_ - 1);
    glScalef(scale, scale, scale);
    glTranslatef(-(float) (width_ - 1) / 2, 0.0f, -(float) (length_ - 1) / 2);

    bool texture = true;

    for (int z = 0; z < width_ - 1; z++) {
        //Makes OpenGL draw a triangle at every three consecutive vertices

        if (getHeight(0, z) > 15)
        {
            glBindTexture(GL_TEXTURE_2D, textures_.find(Layer::High)->second);
        }
        else
        {
            glBindTexture(GL_TEXTURE_2D, textures_.find(Layer::Mid)->second);
        }

        glBegin(GL_TRIANGLE_STRIP);
        for (int x = 0; x < width_; x++) {

            sf::Vector3f normal = getNormal(x, z);
            glNormal3f(normal.x, normal.y, normal.z);
            if (texture)
            {
                glTexCoord2f(0, 0);
            }
            else
            {
                glTexCoord2f(1, 0);
            }
            glVertex3f((GLfloat) x, (GLfloat) getHeight(x, z), (GLfloat) z);
            normal = getNormal(x, z + 1);
            glNormal3f(normal.x, normal.y, normal.z);
            if (texture)
            {
                glTexCoord2f(0, 1);
                texture = !texture;
            }
            else
            {
                glTexCoord2f(1, 1);
                texture = !texture;
            }
            glVertex3f((GLfloat) x, (GLfloat) getHeight(x, z + 1), (GLfloat) z + 1);
        }
        glEnd();
    }
}

现在我已经更改了我的代码以获得更高的fps。我使用Opengl缓冲区来获得它。但是当我使用它们时,屏幕上的所有内容都已损坏。我现在使用以下源代码:

void Terrain::drawObject(sf::RenderWindow* window)
{

    if (!buffersCreated_)
    {
        createBuffers();
        buffersCreated_ = true;
    }

    float scale = 5.0f / max(width_ - 1, length_ - 1);
    glScalef(scale, scale, scale);
    glTranslatef(-(float) (width_ - 1) / 2, 0.0f, -(float) (length_ - 1) / 2);


    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);
    glEnableClientState(GL_VERTEX_ARRAY);

    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, textures_.find(Layer::Mid)->second);

    glBindBuffer(GL_ARRAY_BUFFER, textCoordBuffer_);
    glTexCoordPointer(2, GL_FLOAT, 0, (char *) NULL);

    glEnableClientState(GL_NORMAL_ARRAY);
    glBindBuffer(GL_ARRAY_BUFFER, normalBuffer_);
    glNormalPointer(GL_FLOAT, 0, (char *) NULL);

    glEnableClientState(GL_VERTEX_ARRAY);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer_);
    glVertexPointer(3, GL_FLOAT, 0, (char *) NULL);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, vhVertexCount);

    glDisableClientState(GL_VERTEX_ARRAY);

    glDisable(GL_TEXTURE_2D);

    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisableClientState(GL_NORMAL_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);
}


void Terrain::createBuffers()
{
    vhVertexCount = (int) (width_ * length_ * 6) / (1 * 1);
    sf::Vector3f* vhVertices = new sf::Vector3f[vhVertexCount];
    sf::Vector3f* vhNormal = new sf::Vector3f[vhVertexCount];
    sf::Vector2i* vhTexCoords = new sf::Vector2i[vhVertexCount];

    bool texture = true;
    int nIndex = 0;

    for (int z = 0; z < length_ - 1; z++) {
        for (int x = 0; x < width_; x++) {

            sf::Vector3f normal = getNormal(x, z);
            if (texture)
            {
                vhTexCoords[nIndex] = sf::Vector2i(0, 0);
            }
            else
            {
                vhTexCoords[nIndex] =  sf::Vector2i(1, 0);
            }

            vhVertices[nIndex] = sf::Vector3f((float) x, getHeight(x, z), (float) z);
            vhNormal[nIndex] = sf::Vector3f(normal.x, normal.y, normal.z);
            nIndex++;

            normal = getNormal(x, z + 1);

            if (texture)
            {
                vhTexCoords[nIndex] = sf::Vector2i(0, 1);
            }
            else
            {
                vhTexCoords[nIndex] = sf::Vector2i(1, 1);
            }

            vhVertices[nIndex] = sf::Vector3f((float) x, getHeight(x, z + 1), (float) z + 1);
            vhNormal[nIndex] = sf::Vector3f(normal.x, normal.y, normal.z);
            nIndex++;
        }
    }

    glGenBuffers(1, &vertexBuffer_);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer_);
    glBufferData(GL_ARRAY_BUFFER, vhVertexCount * sizeof(sf::Vector3f), vhVertices, GL_STATIC_DRAW);

    glGenBuffers(1, &normalBuffer_);
    glBindBuffer(GL_ARRAY_BUFFER, normalBuffer_);
    glBufferData(GL_ARRAY_BUFFER, vhVertexCount * sizeof(sf::Vector3f), vhNormal, GL_STATIC_DRAW);

    glGenBuffers(1, &textCoordBuffer_);
    glBindBuffer(GL_ARRAY_BUFFER, textCoordBuffer_);
    glBufferData(GL_ARRAY_BUFFER, vhVertexCount * sizeof(sf::Vector2i), vhTexCoords, GL_STATIC_DRAW);

    delete [] vhVertices;
    vhVertices = nullptr;

    delete [] vhNormal;
    vhNormal = nullptr;

    delete [] vhTexCoords;
    vhTexCoords = nullptr;
}

我使用SFML创建窗口并渲染2D内容,如左下角的菜单。 用Opengl渲染SFML内容的代码如下:

void GameEngine::gameDraw()
{
    // Clear the depth buffer
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glLoadIdentity();

    if (camera_ != nullptr)
    {
        camera_->drawCamera();
    }

    openglObjectsMutex_.lock();


    for (OpenglObject* openglObject : openglObjects_)
    {
        openglObject->drawObject(window_);
    }

    openglObjectsMutex_.unlock();

    window_->pushGLStates();

    sfmlObjectsMutex_.lock();

    for (SfmlObject * gameObject : sfmlObjects_)
    {
        gameObject->drawObject(window_);
    }

    sfmlObjectsMutex_.unlock();

    window_->popGLStates();
}

有人发现缓冲区代码有问题吗? Corrupted image

上面的图像是正确的,但fps很低。 将源更改为使用缓冲区后,我得到了下面的图像。

Correct but with low fps

1 个答案:

答案 0 :(得分:1)

SFML但它只能保存/恢复OpenGL 2.x状态。我们必须禁用我们在+ 3.x状态下启用的功能。它的工作原理是:

固定添加在自己绘图的末尾,如:

glBindBuffer( GL_ARRAY_BUFFER, 0 );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
glBindTexture( GL_TEXTURE_2D, 0 );
glDisableVertexAttribArray( 0 );
glUseProgram( 0 );