2

我正在尝试在 OpenGL 中编写 UI,但在调整控件大小时遇到​​了问题。

纹理错误

当我缩小面板时,文本纹理似乎会缩小或损坏,最终按钮也会这样做。这些按钮与窗口的大小无关,因此问题不在于计算大小。我打印了文本纹理的大小和按钮大小,它们在测试期间保持一致。

所以每次我调整窗口大小时,都会发生以下情况:

onResize
    Delete TexturedRectangle object
        | Delete 9 sprites (including vertex data) used for the TexturedRectangle
        | Delete the RenderTexture
    New TexturedRectangle Object
        | Create 9 sprites (new vertex data) for the textured rectangle
        | Render the rectangle using the 9 sprites to a new RenderTexture the size of the window

我检查了代码并确保在创建新缓冲区之前从 gpu 中删除旧数据。我的缓冲区是否损坏或我渲染到 RenderTextures 的方式不正确?我检查了 glGetError() 并在运行时没有出错。问题可能出在OpenGL堆栈上吗?我不知道问题出在哪里,因为当我调整窗口大小时按钮根本没有改变。

Sprite::Sprite() 
    : ISprite(), mVbo(0) {
    mDiffuse = ResourceCache::getSingleton().getTexture("Texture_NOTFOUND");
    createVbo();
}

Sprite::Sprite(ITexture *diffuse, FloatRect textureBounds)
    : ISprite(), mVbo(0) {
    mDiffuse = diffuse;

    if(textureBounds.x == 0 && textureBounds.y == 0) {
        mTextureBounds = diffuse->getBounds();
    } else {
        mTextureBounds = textureBounds;
    }

    createVbo();
}

Sprite::~Sprite() {
    glDeleteBuffers(1, &mVbo);
}

void Sprite::draw(IRenderTarget *target, RenderState *state) const {
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    glBindBuffer(GL_ARRAY_BUFFER, mVbo);

    switch(state->getRenderMode()) {
    default:
    case RenderState::DIFFUSE:
        mDiffuse->bindTexture();
        break;
    case RenderState::NORMAL_MAP:
        mNormalMap->bindTexture();
        break;
    case RenderState::HEIGHT_MAP:
        mHeightMap->bindTexture();
        break;
    };

    glPushMatrix();
    glTranslatef(mPosition.x, mPosition.y, mPosition.z);
    glColor4f(mColor.r, mColor.g, mColor.b, mColor.a);

    glVertexPointer(3, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, x));
    glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, tx));

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    glPopMatrix();

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);
}

void Sprite::createVbo() {
    if(mVbo != 0) {
        glDeleteBuffers(1, &mVbo);
    }

    // Generate the VBO
    glGenBuffers(1, &mVbo);
    Vector2f size = getSize();

    float texW = mDiffuse->getWidth();
    float texH = mDiffuse->getHeight();
    float srcW = size.x / texW;
    float srcH = size.y / texH;


    // Calculate the vertices
    Vertex verts[] = {{0.f, 0.f, 0.f, mTextureBounds.x / texW, mTextureBounds.y / texH},
                        {size.x, 0.f, 0.f, (mTextureBounds.x / texW) + srcW, mTextureBounds.y / texH},
                        {0.f, size.y, 0.f, mTextureBounds.x / texW, (mTextureBounds.y / texH ) + srcH},
                        {size.x, size.y, 0.f, (mTextureBounds.x / texW) + srcW, (mTextureBounds.y  / texH) + srcH}};

    int vertSize = sizeof(verts);

    // Bind the VBO
    glBindBuffer(GL_ARRAY_BUFFER, mVbo);

    // Submit the vertex data to the GPU
    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * 4, &verts[0].x, GL_STATIC_DRAW_ARB);

    // Unbind the VBO
    glBindBuffer(GL_ARRAY_BUFFER, 0);
}

重复精灵

RepeatingSprite::RepeatingSprite(Texture *diffuseTexture, FloatRect spriteBounds, int xRepeat, int yRepeat) 
    : ISprite(), mXRepeat(xRepeat), mYRepeat(yRepeat) {
    mVbo = 0;
    mDiffuse = diffuseTexture;
    mTextureBounds = spriteBounds;
    createVbo();
}

RepeatingSprite::~RepeatingSprite() {
    glDeleteBuffers(1, &mVbo);
}



void RepeatingSprite::draw(IRenderTarget *target, RenderState *state) const {
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    glBindBuffer(GL_ARRAY_BUFFER, mVbo);

    switch(state->getRenderMode()) {
    default:
    case RenderState::DIFFUSE:
        mDiffuse->bindTexture();
        break;
    case RenderState::NORMAL_MAP:
        mNormalMap->bindTexture();
        break;
    case RenderState::HEIGHT_MAP:
        mHeightMap->bindTexture();
        break;
    };

    glPushMatrix();
    glTranslatef(mPosition.x, mPosition.y, mPosition.z);
    glColor4f(mColor.r, mColor.g, mColor.b, mColor.a);

    glVertexPointer(3, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, x));
    glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, tx));

    glDrawArrays(GL_QUADS, 0, (mXRepeat * mYRepeat) * 4);

    glPopMatrix();

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);
}

void RepeatingSprite::createVbo() {
    int totalRepeats = mXRepeat * mYRepeat;
    float textureWidth = mDiffuse->getWidth();
    float textureHeight = mDiffuse->getHeight();
    Vertex *vertices = new Vertex[totalRepeats*4];

    int counter = 0;
    // For each sprite count, create a quad
    for(float y = 0; y < mYRepeat; y++) {
        for(float x = 0; x < mXRepeat; x++) {   

            Vertex v1 = {x * mTextureBounds.w, 
                         y * mTextureBounds.h, 0.f, 
                         mTextureBounds.x / textureWidth, 
                         mTextureBounds.y / textureHeight};

            Vertex v2 = {x * mTextureBounds.w + mTextureBounds.w, 
                         y * mTextureBounds.h, 0.f, 
                         (mTextureBounds.x / textureWidth) + (mTextureBounds.w / textureWidth), 
                         mTextureBounds.y / textureHeight};

            Vertex v3 = {x * mTextureBounds.w, 
                         y * mTextureBounds.h + mTextureBounds.h, 0.f, 
                         mTextureBounds.x / textureWidth, 
                         (mTextureBounds.y / textureHeight) + (mTextureBounds.h / textureHeight)};

            Vertex v4 = {x * mTextureBounds.w + mTextureBounds.w, 
                         y * mTextureBounds.h + mTextureBounds.h, 0.f, 
                         (mTextureBounds.x / textureWidth) + (mTextureBounds.w / textureWidth), 
                         (mTextureBounds.y / textureHeight) + (mTextureBounds.h / textureHeight)};


            vertices[counter] = v1;
            counter++;
            vertices[counter] = v2;
            counter++;
            vertices[counter] = v4;
            counter++;
            vertices[counter] = v3;
            counter++;
        }
    }

    glGenBuffers(1, &mVbo);

    glBindBuffer(GL_ARRAY_BUFFER, mVbo);

    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * (totalRepeats*4), &vertices[0].x, GL_STATIC_DRAW_ARB);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    delete[] vertices;
}

渲染纹理

RenderTexture::RenderTexture(float width, float height) {
    mWidth = width;
    mHeight = height;

    // Create the color buffer
    glGenTextures(1, &mId);
    glBindTexture(GL_TEXTURE_2D, mId);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int)mWidth, (int)mHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    glBindTexture(GL_TEXTURE_2D, 0);

    // Create the framebuffer
    glGenFramebuffers(1, &mFbo);
    glBindFramebuffer(GL_FRAMEBUFFER, mFbo);

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mId, 0);

    GLenum err = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    assert(err == GL_FRAMEBUFFER_COMPLETE); // Make sure texture is valid

    glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

RenderTexture::~RenderTexture() {
    glDeleteBuffers(1, &mFbo);
    glDeleteTextures(1, &mId);
    mFbo = 0;
}


void RenderTexture::preDraw() {
    // store the glViewport and glEnable states
    glPushAttrib(GL_VIEWPORT_BIT);

    // Bind the frame buffer
    //glBindTexture(GL_TEXTURE_2D, 0);
    glBindFramebuffer(GL_FRAMEBUFFER, mFbo);

    // Save the current matrix
    glPushMatrix();
    glLoadIdentity();

    // Setup the projection matrix for the render target
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    glViewport(0, 0, (int)mWidth, (int)mHeight);
    glOrtho(0, mWidth, 0.f, mHeight, 0.f, 100.f);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    glDrawBuffer(GL_COLOR_ATTACHMENT0);
}

void RenderTexture::postDraw() {
    // Pop the render target's projection matrix off the stack
    glPopMatrix();
    // Restore previouse projection matrix
    glPopMatrix();
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    // Restore the previous viewport settings
    glPopAttrib();
}
4

1 回答 1

2

在 OpenGL 中,当您对一个对象应用某种变换并看到其他对象受到影响时,开始查找的一个好地方是您的变换和堆栈操作逻辑。

所以在RenderTexture::preDraw()你有:

glPushMatrix();
// ...
glMatrixMode(GL_PROJECTION);
glPushMatrix();

并在RenderTexture::postDraw()

glPopMatrix();
// Restore previouse projection matrix
glPopMatrix();

他们之间没有任何通话glMatrixMode()

它不会像这样正常工作。每个矩阵模式都有自己的堆栈,因此第二个glPopMatrix()是弹出错误的堆栈。

您将需要执行以下操作:

glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
于 2012-05-16T07:08:51.503 回答