我正在尝试在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();
}
答案 0 :(得分:2)
在OpenGL中,当您将某种变换应用于对象并看到其他对象受到影响时,开始查看的好地方是变换和堆栈操作逻辑。
所以在RenderTexture::preDraw()
你有:
glPushMatrix();
// ...
glMatrixMode(GL_PROJECTION);
glPushMatrix();
和RenderTexture::postDraw()
:
glPopMatrix();
// Restore previouse projection matrix
glPopMatrix();
他们之间没有调用glMatrixMode()
。
它不会像这样正常工作。每个矩阵模式都有自己的堆栈,因此第二个glPopMatrix()
会弹出错误的堆栈。
你需要做类似的事情:
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();