2017-06-09 74 views
2

我有2种方案 - 无论是OpenGL的3.x的:的OpenGL + SDL +不能画到画外FBO

  • 一个是Win32程序(修改讷河教程),它通过创建一个wglCreateContext窗口和GL上下文( )和wlgMakeCurrent()
  • 一个是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程序,它总是返回RGB值0(黑色)。

当我改变glTexImage2D()的屏幕外FBO的尺寸,以符合实际的屏幕,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(); 
    ... 
    } 

UPDATE: 我发现纹理的大小似乎与我的问题。

//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, 1024, 1024, 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 

Khronos的声明如下:

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。

回答

1

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

换句话说,正在对屏幕外的FBO进行错误的绘制。