2012-02-06 227 views
2

我在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像素: Without FBO

我现在想用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(); 

因为图像/纹理不仅是上下颠倒,但纹理映射也是错误的代码不能正常工作。只有当窗口全屏时它才能正常工作,否则它的行为真的很奇怪。

见下图: With FBO

正如你所看到的,纹理正确的窗口内缩放,但它被“裁剪”成比例全屏窗口的大小和实际的窗口尺寸之间的差别。

我试过一切都没有成功。

由于这是我第一次使用OpenGL,我错过了什么?我越来越疯了..

回答

2
// 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(); 
+0

Oh..my坏..非常感谢您的回答。 我只在窗口大小调整时设置了视口和投影。我没有意识到我必须为FBO和后台缓冲区指定两个不同的视口和投影。这解决了纹理映射问题,但是(显然)纹理仍然是颠倒/反射的。我知道我可以更改'glTexCoord2f'和'glVertex2f'之间的关联来修复它,但为什么我需要它?如果我直接绘制到后台缓冲区,纹理的方向是否正确。为什么在绘制到FBO时需要更改内容? – Andrea3000 2012-02-06 14:18:26

+1

@ Andrea3000:呃,它是翻转的,因为你把它翻过来。图像的原点是左下角,而不是在右上角,这是你似乎假设的。至于视口和投影的设置:这大概是我告诉OpenGL新手的80% - 将它们设置在绘图函数中,而不是在窗口大小调整器中。窗口调整大小处理程序对此很不利,因为它会在使用FBO或绘制HUD或类似物时导致麻烦。所有OpenGL操作(静态数据上传除外)都属于绘图功能。 – datenwolf 2012-02-06 14:30:59

+0

感谢您对OpenGL的建议,我会牢记它们;-)关于翻转后的图像:FBO和后台缓冲区有不同的坐标系统吗?我问你这个问题,因为我不明白图像在绘制到后台缓冲区时如何正确显示,并且在绘制到FBO然后回到后台缓冲区时翻转。这两种情况下'glTexCoord2f'和'glVertex2f'都是相同的。 – Andrea3000 2012-02-06 14:49:07