Windows / MFC上的OpenGL:FBO?

时间:2012-05-18 18:30:25

标签: c++ opengl fbo

我正在尝试通过FBO将RTT通过C ++ MFC应用程序中的适当像素格式使用OpenGL添加到我的应用程序中。我已经将RTO工作的另一个基于SDL的应用程序复制了FBO代码。我正在使用glew访问OpenGL驱动程序。

在创建,激活,停用和渲染FBO时,我已经对所有OpenGL调用结果进行了广泛测试,并且没有任何错误。

当将渲染缓冲区从GL_BACK切换到渲染FBO的颜色附件时,似乎没有任何东西可以写入颜色缓冲区 - 甚至glClearColor()似乎也无法使用它。

这是因为Windows像素格式不允许我渲染到FBO吗?由于渲染缓冲区切换都是通过OpenGL进行的,我怀疑是这种情况,但我绝对不知道为什么RTT在我的应用程序中不起作用。

我可能需要寻找什么指针?

标题文件:

#ifndef __FBO_H
#define __FBO_H

#include <windows.h>
#include <stddef.h>

#define MAX_COLOR_BUFFERS 16

typedef struct tFrameBuffer {
   GLuint   hFBO; // OpenGL FBO handle
   GLuint   hColorBuffers [MAX_COLOR_BUFFERS]; // color buffer handles
   GLuint   bufferIds [MAX_COLOR_BUFFERS]; // color buffer attachment ids
   GLuint   hDepthBuffer; // depth buffer handle
   GLuint   hStencilBuffer; // stencil buffer handle
   int      nColorBuffers; // number of available color buffers
   int      nBuffer; // currently selected color buffer(s)
   int      nType; // depth buffer type (depth only / depth + stencil)
   int      nWidth; // render buffer width
   int      nHeight; // render buffer height
   int      bActive; // FBO is draw buffer
   GLenum   nStatus; // result of availability test
} tFrameBuffer;

class CFBO {
   private:
      tFrameBuffer   m_info;

   public:
      CFBO () { Init (); }
      ~CFBO () { Destroy (); }
      static bool Setup (void);
      void Init (void);
      int Create (int nWidth, int nHeight, int nType = 1, int nColorBuffers = 1);
      void Destroy (void);
      int Available (void);
      int Enable (int nColorBuffers = 0);
      int Disable (void);
      inline GLuint Handle (void) { return m_info.hFBO; }
      void SelectColorBuffers (int nBuffer = 0);
      void CFBO::Draw (CRect viewport);

   private:
      int CreateColorBuffers (int nBuffers);
      int CreateDepthBuffer (void);
      void AttachBuffers (void);
   };

#endif //__FBO_H

实现:

//---------------------------------------------------------------------------

int CFBO::Available (void)
{
if (!Handle ()) // no FBO generated
   return 0;
switch (m_info.nStatus = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT)) {                                          
   case GL_FRAMEBUFFER_COMPLETE_EXT:                       
      return 1;
   case GL_FRAMEBUFFER_UNSUPPORTED_EXT:                    
      return -1;
   default:                                                
      return -1;
   }
}

//---------------------------------------------------------------------------

void CFBO::Init (void)
{
memset (&m_info, 0, sizeof (m_info));
m_info.nBuffer = 0x7FFFFFFF;
}

//---------------------------------------------------------------------------
// Create nBuffers color buffers for the FBO
// The texture handle is stored in m_info.hColorBuffers, the color attachment
// id in m_info.bufferIds
// This method can be overriden to create different kinds of render targets

int CFBO::CreateColorBuffers (int nBuffers)
{
if (!nBuffers)
   return 1;

   GLint   nMaxBuffers;

glGetIntegerv (GL_MAX_COLOR_ATTACHMENTS_EXT, &nMaxBuffers);
if (nMaxBuffers > MAX_COLOR_BUFFERS)
   nMaxBuffers = MAX_COLOR_BUFFERS;
else if (nBuffers > nMaxBuffers)
   nBuffers = nMaxBuffers;
m_info.nColorBuffers = 
m_info.nColorBuffers = nBuffers;
m_info.nFirstBuffer = 0;
glGenTextures (nBuffers, m_info.hColorBuffers);
glEnable (GL_TEXTURE_2D);
glActiveTexture (GL_TEXTURE0);
for (int i = 0; i < nBuffers; i++) {
   glBindTexture (GL_TEXTURE_2D, m_info.hColorBuffers [i]);
   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
   glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 
   glTexParameteri (GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE);
   glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, m_info.nWidth, m_info.nHeight, 
                 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
   m_info.bufferIds [i] = GL_COLOR_ATTACHMENT0_EXT + i;
   }
return glGetError () ? 0 : 1;
}

// -----------------------------------------------------------------------
// Create depth texture 
// (depth only: nType == 0, depth + stencil: nType == 1)

#define GL_DEPTH_STENCIL_EXT        0x84F9
#define GL_UNSIGNED_INT_24_8_EXT    0x84FA
#define GL_DEPTH24_STENCIL8_EXT     0x88F0
#define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1

GLuint CreateDepthTexture (int nType, int nWidth, int nHeight)
{
if (!(nWidth && nHeight))
   return 0;

GLuint   hDepthBuffer;

glEnable (GL_TEXTURE_2D);
glActiveTexture (GL_TEXTURE0);
glGenTextures (1, &hDepthBuffer);
if (glGetError ())
   return hDepthBuffer = 0;
glBindTexture (GL_TEXTURE_2D, hDepthBuffer);
glTexParameteri (GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
glTexParameteri (GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);    
if (nType == 1) // depth + stencil
   glTexImage2D (GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8_EXT, nWidth, nHeight, 0,
                 GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, NULL);
else
   glTexImage2D (GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, nWidth, nHeight, 0,
                 GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
if (glGetError ()) {
   glDeleteTextures (1, &hDepthBuffer);
   return hDepthBuffer = 0;
   }
glBindTexture (GL_TEXTURE_2D, 0);
return hDepthBuffer;
}

//------------------------------------------------------------------------

int CFBO::CreateDepthBuffer (void)
{
// depth buffer
if (!(m_info.hDepthBuffer = 
      CreateDepthTexture (m_info.nType, m_info.nWidth, m_info.nHeight)))
   return 0;
glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, 
                           GL_TEXTURE_2D, m_info.hDepthBuffer, 0);
if (m_info.nType) // stencil buffer
   glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
                              GL_TEXTURE_2D, 
                              m_info.hStencilBuffer = m_info.hDepthBuffer, 0);
return glGetError () ? 0 : 1;
}

//------------------------------------------------------------------------
// Attach render buffers

void CFBO::AttachBuffers (void)
{
for (int i = 0; i < m_info.nColorBuffers; i++)
   glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, m_info.bufferIds [i], 
                              GL_TEXTURE_2D, m_info.hColorBuffers [i], 0);
// depth + stencil buffer
glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, 
                           GL_TEXTURE_2D, m_info.hDepthBuffer, 0);
if (m_info.nType)
   glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
                              GL_TEXTURE_2D, 
                              m_info.hStencilBuffer = m_info.hDepthBuffer, 0);
}

//------------------------------------------------------------------------
// Create an FBO with width nWidth, height nHeight, depth (nType == 0) or 
// depth + stencil (nType == 1) buffer
// and one or more color buffers (nColorBuffers)

int CFBO::Create (int nWidth, int nHeight, int nType, int nColorBuffers)
{
Destroy ();
// compute power of two >= nWidth and nHeight
m_info.nWidth = Pow2ize (nWidth); 
m_info.nHeight = Pow2ize (nHeight);

m_info.nType = nType;
m_info.hDepthBuffer = 0;
m_info.hStencilBuffer = 0;

glGenFramebuffersEXT (1, &m_info.hFBO);
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, m_info.hFBO);

if (!(CreateColorBuffers (nColorBuffers) && CreateDepthBuffer ())) {
   Destroy ();
   return 0;
   }
AttachBuffers ();
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
if  (!Available ()) {
   Destroy ();
   return 0;
   }
return 1;
}

//------------------------------------------------------------------------

void CFBO::Destroy (void)
{
if (m_info.hFBO) {
   if (m_info.nColorBuffers) {
      glDeleteTextures (m_info.nColorBuffers, m_info.hColorBuffers);
      memset (m_info.hColorBuffers, 0, sizeof (m_info.hColorBuffers));
      m_info.nColorBuffers = 0;
      }
   if (m_info.hDepthBuffer) {
      glDeleteTextures (1, &m_info.hDepthBuffer);
      glDeleteRenderbuffersEXT (1, &m_info.hDepthBuffer);
      m_info.hDepthBuffer =
      m_info.hStencilBuffer = 0;
      }
   glDeleteFramebuffersEXT (1, &m_info.hFBO);
   m_info.hFBO = 0;
   }
}

//---------------------------------------------------------------------------
// depending on nBuffer, select the first, a single specified or a range
// of color buffer als draw buffers. m_info.bufferIds contains the color 
// attachment number (GL_COLOR_ATTACHMENT0, etc).

void CFBO::SelectColorBuffers (int nBuffer) 
{ 
if ((m_info.nColorBuffers == 1) || (nBuffer >= m_info.nColorBuffers)) 
   glDrawBuffer (m_info.bufferIds [nBuffer = 0]); // single buffer/invalid index
else if (nBuffer < 0)
   glDrawBuffers (m_info.nColorBuffers, m_info.bufferIds); // use all buffers
else
   glDrawBuffer (m_info.bufferIds [nBuffer]); // use the specified color buffer
m_info.nBuffer = nBuffer;
}

//---------------------------------------------------------------------------

int CFBO::Enable (int nColorBuffers)
{
if (m_info.bActive)
   return 1;
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, m_info.hFBO);
SelectColorBuffers (nColorBuffers);
glReadBuffer (GL_COLOR_ATTACHMENT0_EXT);
return m_info.bActive = 1;
}

//---------------------------------------------------------------------------

int CFBO::Disable (void)
{
if (!m_info.bActive)
   return 1;
m_info.nBuffer = 0x7FFFFFFF;
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
glDrawBuffer (GL_BACK);
glReadBuffer (GL_BACK);
m_info.bActive = 0;
return 1;
}

//---------------------------------------------------------------------------

void CFBO::Draw (CRect viewport)
{
   float uMax = float (viewport.Width ()) / float (m_info.nWidth);
   float vMax = float (viewport.Height ()) / float (m_info.nHeight);
   float texCoord [4][2] = {{0.0, 0.0},{0.0, vMax},{uMax, vMax},{uMax, 0.0}};
   float vertices [4][2] = {{0.0f, 0.0f},{0.0f, 1.0f},{1.0f, 1.0f},{1.0f, 0.0f}};

glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glOrtho (0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();

glEnable (GL_TEXTURE_2D);
glActiveTexture (GL_TEXTURE0);
glClientActiveTexture (GL_TEXTURE0);
glEnableClientState (GL_TEXTURE_COORD_ARRAY);
glEnableClientState (GL_VERTEX_ARRAY);
glTexCoordPointer (2, GL_FLOAT, 0, texCoord);
glVertexPointer (2, GL_FLOAT, 0, vertices);
glBindTexture (GL_TEXTURE_2D, m_info.hColorBuffers [0]);
glColor3f (1.0f, 1.0f, 1.0f);
glDisable (GL_BLEND);
glDrawArrays (GL_QUADS, 0, 4);
glDisableClientState (GL_TEXTURE_COORD_ARRAY);
glDisableClientState (GL_VERTEX_ARRAY);
}

//---------------------------------------------------------------------------

应用:

CFBO m_renderBuffers;
m_renderBuffers.Create (GetSystemMetrics (SM_CXSCREEN), 
                        GetSystemMetrics (SM_CYSCREEN), 1, 2);

...

//-----------------------------------------------------------------------

void CRendererGL::BeginRender (bool bOrtho)
{
SetupProjection (bOrtho);
m_renderBuffers.Enable ();
}

//-----------------------------------------------------------------------

void CRendererGL::EndRender (bool bSwapBuffers)
{
for (int i = 0; i < 3; i++) {
   glActiveTexture (GL_TEXTURE0 + i);
   glClientActiveTexture (GL_TEXTURE0 + i);
   glDisableClientState (GL_COLOR_ARRAY);
   glDisableClientState (GL_TEXTURE_COORD_ARRAY);
   glDisableClientState (GL_VERTEX_ARRAY);
   glDisable (GL_TEXTURE_2D);
   }
shaderManager.Deploy (-1);
glDisable (GL_DEPTH_TEST);
if (bSwapBuffers) {
   m_renderBuffers.Disable ();
   m_renderBuffers.Draw (Viewport ());
   SwapBuffers (m_glHDC);
   }
}

//-----------------------------------------------------------------------

1 个答案:

答案 0 :(得分:2)

我知道了。我知道这肯定是愚蠢的事。

将颜色缓冲区渲染为GL_BACK时,而不是

glActiveTexture (GL_TEXTURE0);
glClientActiveTexture (GL_TEXTURE0);
glEnable (GL_TEXTURE_2D);

我写过

glEnable (GL_TEXTURE_2D);
glActiveTexture (GL_TEXTURE0);
glClientActiveTexture (GL_TEXTURE0);

首先必须在启用或禁用纹理之前指定TMU。

我不明白的原因是为什么我的问题已经被三次贬低了。