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()で。

このように正しく動作しません。各マトリックスモードには独自のスタックがあるため、2番目glPopMatrix()は間違ったスタックから飛び出します。

あなたは次のようなことをする必要があります:

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