FBO:在绘制渲染纹理时渲染纹理,错误的纹理映射
问题描述:
我在Mac OS X应用程序上使用OpengGL在NSOpenGLView
上绘制纹理。FBO:在绘制渲染纹理时渲染纹理,错误的纹理映射
该应用程序是一个电影播放器。它将电影帧解码为CVOpenGLTextureRef
(这是OpenGL纹理),并使用GL_QUAD
直接将它们绘制到视图中。一切工作正常。
以下是代码的相关部分。
// "image" is the CVOpenGLTextureRef containing the movie frame as texture
GLenum textureTarget = CVOpenGLTextureGetTarget(image);
GLuint textureName = CVOpenGLTextureGetName(image);
glEnable(textureTarget);
glBindTexture(textureTarget, textureName);
glBegin(GL_QUADS);
// Draw the quads
//Note: textureTagret is NOT GL_TEXTURE_2D, therefore texture coordinates
//are NOT scaled to [0, 1]
glTexCoord2f(0.0f, imageRect.size.height);
glVertex2f (0.0f, 0.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex2f (0.0f, windowRect.size.height);
glTexCoord2f(imageRect.size.width, 0.0f);
glVertex2f (windowRect.size.width, windowRect.size.height);
glTexCoord2f(imageRect.size.width, imageRect.size.height);
glVertex2f (windowRect.size.width,0.0f);
glEnd();
glDisable(textureTarget);
glFlush();
它工作得很好,我可以调整窗口大小,并将纹理正确地映射到较小的窗口。
在这里看到从全屏窗口的大小到500x280像素:
我现在想用FBO渲染到纹理,我开始做一个非常简单的实现它包括在渲染动画帧到离屏FBO(纹理),并绑定该纹理在屏幕上绘制。
下面是代码:
// "image" is the CVOpenGLTextureRef containing the movie frame as texture
GLenum textureTarget = CVOpenGLTextureGetTarget(image);
GLuint textureName = CVOpenGLTextureGetName(image);
////////////////////////////////////////////////////////////////////
// the creation on the FBO is done only once on program start:
GLuint fboId;
GLuint textureId;
float targetWidth = 2048;
float targetHeight = 2048;
// create a texture object
glGenTextures(1, &textureId);
glBindTexture(textureTarget, textureId);
glTexParameterf(textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameterf(textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(textureTarget, GL_GENERATE_MIPMAP, GL_TRUE); // automatic mipmap
glTexImage2D(textureTarget, 0, GL_RGBA8, targetWidth, targetHeight, 0,
GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(textureTarget, 0);
// create a framebuffer object
glGenFramebuffersEXT(1, &fboId);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboId);
// attach the texture to FBO color attachment point
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
textureTarget, textureId, 0);
// check FBO status
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if(status != GL_FRAMEBUFFER_COMPLETE_EXT)
return FALSE;
// switch back to window-system-provided framebuffer
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
///////////////////////////////////////////////////////////////////////////////
// Render to texture
glEnable(textureTarget);
glBindTexture(textureTarget, textureName);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboId);
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_QUADS);
// Draw the quads
glTexCoord2f(0.0f, imageRect.size.height);
glVertex2f (0.0f, 0.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex2f (0.0f,imageRect.size.height);
glTexCoord2f(imageRect.size.width, 0.0f);
glVertex2f (imageRect.size.width, imageRect.size.height);
glTexCoord2f(imageRect.size.width, imageRect.size.height);
glVertex2f (imageRect.size.width,0.0f);
glEnd();
glFlush();
// Bind newly rendered texture
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glClear(GL_COLOR_BUFFER_BIT);
glBindTexture(textureTarget, textureId);
glGenerateMipmapEXT(textureTarget);
// draw on-screen
glBegin(GL_QUADS);
// Draw the quads
//Note: textureTagret is NOT GL_TEXTURE_2D, therefore texture coordinates
//are NOT scaled to [0, 1]
glTexCoord2f(0.0f, imageRect.size.height);
glVertex2f (0.0f, 0.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex2f (0.0f, windowRect.size.height);
glTexCoord2f(imageRect.size.width, 0.0f);
glVertex2f (windowRect.size.width, windowRect.size.height);
glTexCoord2f(imageRect.size.width, imageRect.size.height);
glVertex2f (windowRect.size.width,0.0f);
glEnd();
glDisable(textureTarget);
glFlush();
因为图像/纹理不仅是上下颠倒,但纹理映射也是错误的代码不能正常工作。只有当窗口全屏时它才能正常工作,否则它的行为真的很奇怪。
见下图:
正如你所看到的,纹理正确的窗口内缩放,但它被“裁剪”成比例全屏窗口的大小和实际的窗口尺寸之间的差别。
我试过一切都没有成功。
由于这是我第一次使用OpenGL,我错过了什么?我越来越疯了..
答
// Render to texture glEnable(textureTarget); glBindTexture(textureTarget, textureName); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboId); glClear(GL_COLOR_BUFFER_BIT);
我在想念设置视口和这里的帧缓冲区对象的投影。
glBegin(GL_QUADS); // Draw the quads glTexCoord2f(0.0f, imageRect.size.height); g lVertex2f (0.0f, 0.0f); glTexCoord2f(0.0f, 0.0f); glVertex2f (0.0f,imageRect.size.height); glTexCoord2f(imageRect.size.width, 0.0f); glVertex2f (imageRect.size.width, imageRect.size.height); glTexCoord2f(imageRect.size.width, imageRect.size.height); glVertex2f (imageRect.size.width,0.0f); glEnd(); glFlush();
Oh..my坏..非常感谢您的回答。 我只在窗口大小调整时设置了视口和投影。我没有意识到我必须为FBO和后台缓冲区指定两个不同的视口和投影。这解决了纹理映射问题,但是(显然)纹理仍然是颠倒/反射的。我知道我可以更改'glTexCoord2f'和'glVertex2f'之间的关联来修复它,但为什么我需要它?如果我直接绘制到后台缓冲区,纹理的方向是否正确。为什么在绘制到FBO时需要更改内容? – Andrea3000 2012-02-06 14:18:26
@ Andrea3000:呃,它是翻转的,因为你把它翻过来。图像的原点是左下角,而不是在右上角,这是你似乎假设的。至于视口和投影的设置:这大概是我告诉OpenGL新手的80% - 将它们设置在绘图函数中,而不是在窗口大小调整器中。窗口调整大小处理程序对此很不利,因为它会在使用FBO或绘制HUD或类似物时导致麻烦。所有OpenGL操作(静态数据上传除外)都属于绘图功能。 – datenwolf 2012-02-06 14:30:59
感谢您对OpenGL的建议,我会牢记它们;-)关于翻转后的图像:FBO和后台缓冲区有不同的坐标系统吗?我问你这个问题,因为我不明白图像在绘制到后台缓冲区时如何正确显示,并且在绘制到FBO然后回到后台缓冲区时翻转。这两种情况下'glTexCoord2f'和'glVertex2f'都是相同的。 – Andrea3000 2012-02-06 14:49:07