2017-06-09 105 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進行錯誤的繪製。