OpenGL&x2B;SDL&x2B;无法绘制到屏幕外FBO

OpenGL&x2B;SDL&x2B;无法绘制到屏幕外FBO,opengl,textures,sdl-2,fbo,glreadpixels,Opengl,Textures,Sdl 2,Fbo,Glreadpixels,我有2个程序-都是OpenGL 3.x: 一个是Win32程序(修改后的NeHe教程),它通过wglCreateContext()和wlgmakCurrent()创建窗口和GL上下文 一个是SDL2程序 两个程序都调用此功能: int DrawGLScene( GLvoid ) { static int nFirstTime = 1; if( nFirstTime ) { glewInit(); n

我有2个程序-都是OpenGL 3.x:

  • 一个是Win32程序(修改后的NeHe教程),它通过wglCreateContext()和wlgmakCurrent()创建窗口和GL上下文
  • 一个是SDL2程序
两个程序都调用此功能:

int DrawGLScene( GLvoid )                               
{
  static int nFirstTime = 1;

  if( nFirstTime )
  {
    glewInit();

    nFirstTime = 0;
    glGenTextures( 1, &g_OffscreenTexture );
    glGenFramebuffers( 1, &g_OffscreenFBO );
  }

  GLuint nScreenFBO = 0;

  glBindTexture( GL_TEXTURE_2D, 0 );

  SelectColor( COLOR_YELLOW );  
  DrawFilledRectangle( 50, 50, 200, 200 );

  // Now draw to offscreen FBO..
  glGetIntegerv( GL_FRAMEBUFFER_BINDING, (GLint *) &nScreenFBO );

  glBindFramebuffer( GL_FRAMEBUFFER, g_OffscreenFBO );
  glBindTexture( GL_TEXTURE_2D, g_OffscreenTexture );

  //glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, g_ScreenWidth, g_ScreenHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0 );  // WORKS
  glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0 ); // DOESN'T WORK

  glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, g_OffscreenTexture, 0 );

  SelectColor( COLOR_GREEN );  
  DrawFilledRectangle( 0, 0, 200, 200 );

  SelectColor( COLOR_RED );  
  DrawFilledRectangle( 0, 50, 200, 200 );

  // Go test the colours
  TestRGB();

  // Put screen FBO back..
  glBindTexture( GL_TEXTURE_2D, 0 );
  glBindFramebuffer( GL_FRAMEBUFFER, nScreenFBO );

  return TRUE;
}
该函数在可见屏幕上绘制一个黄色矩形,并应在屏幕外FBO中绘制两个绿色和红色矩形

然后,我使用一个函数(TestRGB(),它调用glReadPixels()返回屏幕外FBO中红色和绿色矩形内点的RGB值

glReadPixels()在非SDL程序中工作正常。对于SDL程序,它始终返回0(黑色)的RGB值

当我更改屏幕外FBO的glTexImage2D()尺寸以匹配实际屏幕时,SDL版本就可以工作了

注意:我希望屏幕外的纹理比屏幕小

我做错了什么?我是否错过了纹理初始化步骤

下面是我用来获取RGB值的函数:

void GetRGBAt( GLuint nFBO, int x, int y, GLfloat *pfR, GLfloat *pfG, GLfloat *pfB )
{
  GLuint nScreenFBO = 0;

  // Remember the screen FBO..
  glGetIntegerv( GL_FRAMEBUFFER_BINDING, (GLint *) &nScreenFBO );

  // Now bind to given FBO where we'll pull the colours from..
  glBindFramebuffer( GL_FRAMEBUFFER, nFBO );

  // windowHeight - y - 1
  BYTE abRGBA[ 4 ] = { 0 };
  glReadPixels( x, g_ScreenHeight - y - 1, 1, 1, GL_RGBA,   GL_UNSIGNED_BYTE, abRGBA );

  (*pfR) = (float) abRGBA[ 0 ] / 255.0f;
  (*pfG) = (float) abRGBA[ 1 ] / 255.0f;
  (*pfB) = (float) abRGBA[ 2 ] / 255.0f;

  // Put screen FBO back..
  glBindFramebuffer( GL_FRAMEBUFFER, nScreenFBO );
}
这是我的SDL窗口初始化-不确定双缓冲是否是原因之一

  if( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER ) < 0 )
  {
    LogDebugf( "FATAL - SDL_Init" );
    exit( -1 );
  }

  atexit( SDL_Quit );

  // Use OpenGL 3.1 core 
  SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 3 );
  SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 1 ); 
  SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE );

  SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
  SDL_GL_SetAttribute( SDL_GL_ACCELERATED_VISUAL, 1 );
  SDL_GL_SetAttribute( SDL_GL_RED_SIZE,     8 );
  SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE,   8 );
  SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE,    8 );
  SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE,   8 );
  SDL_GL_SetAttribute( SDL_GL_BUFFER_SIZE, 32 );
  SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE,  24 );

  SDL_DisplayMode currentDisplay;

  SDL_GetCurrentDisplayMode( 0, &currentDisplay );

  g_ScreenWidth  = 960;
  g_ScreenHeight = 640;

  int nWindowPosY = SDL_WINDOWPOS_UNDEFINED;

  SDL_DisplayMode displayMode;
  SDL_GetDesktopDisplayMode( 0, &displayMode );

  g_SDLWindow = SDL_CreateWindow( "OffscreenFBO",
                                 SDL_WINDOWPOS_UNDEFINED,
                                 nWindowPosY,
                                 g_ScreenWidth,
                                 g_ScreenHeight,
                                /* SDL_WINDOW_FULLSCFREEN | */ SDL_WINDOW_OPENGL );
  if( g_SDLWindow == NULL )
  {
    LogDebugf( "SDL_CreateWindow.. FAILED" );
    exit( -1 );
  }

  g_SDLWindowID = SDL_GetWindowID( g_SDLWindow );

  SDL_GL_CreateContext( g_SDLWindow );

  GLenum glewRC = glewInit();

  if( glewRC != GLEW_OK )
    exit( 1 );

  glViewport( 0, 0, g_ScreenWidth, g_ScreenHeight );                    // Reset The Current Viewport
  glClearColor( 0.9f, 0.9f, 0.9f, 1.0f );

  g_Ortho = glm::ortho( 0.0f, (GLfloat) g_ScreenWidth, (GLfloat) g_ScreenHeight, 0.0f, 0.0f, 1000.0f );

  g_SolidProgram            = BuildProgram( vsSolid, fsSolid );

  glClearColor( 0.215f, 0.2f, 0.176f, 1.0f );
  glClear( GL_COLOR_BUFFER_BIT );

  SDL_Event     event;

  while( g_Running )
  {
    DrawGLScene();
    ...
  }
赫罗诺斯声明如下:

width
    Specifies the width of the texture image. All implementations support texture images that are at least 1024 texels wide.
height
    Specifies the height of the texture image, or the number of layers in a texture array, in the case of the GL_TEXTURE_1D_ARRAY and GL_PROXY_TEXTURE_1D_ARRAY targets. All implementations support 2D texture images that are at least 1024 texels high, and texture arrays that are at least 256 layers deep. 

在我看来,SDL2实现似乎不支持小于1024像素宽/高的纹理-至少是为了绘制到FBO中。

这不起作用的主要原因是我忘记在屏幕外FBO上应用正确的正交投影矩阵。我使用的投影与屏幕相同(1024x640),其中纹理矩阵应该使用512x512。此外,GetRGBAt()代码使用的是g_ScreenHeight,而不是纹理的高度。现在,只要设置投影,它就可以处理许多纹理高度

换言之,对屏幕外FBO的绘制不正确

width
    Specifies the width of the texture image. All implementations support texture images that are at least 1024 texels wide.
height
    Specifies the height of the texture image, or the number of layers in a texture array, in the case of the GL_TEXTURE_1D_ARRAY and GL_PROXY_TEXTURE_1D_ARRAY targets. All implementations support 2D texture images that are at least 1024 texels high, and texture arrays that are at least 256 layers deep.