2012-02-06 294 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