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像素:
我現在想用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,我錯過了什麼?我越來越瘋了..
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