如何在OpenGL中绘制到屏幕外颜色缓冲区,然后将结果绘制到精灵表面?

时间:2018-02-19 05:01:36

标签: opengl

以下是对问题的描述:

  1. 我想将一些VBO形状(矩形,圆形等)渲染到屏幕外的帧缓冲对象。这可以是任意形状。
  2. 然后我想在简单的精灵表面上绘制结果作为纹理,但不是在整个屏幕上绘制。
  3. 我似乎无法使其正常工作。

    当我运行代码时,我看到整个屏幕上绘制的形状,但不是中间的精灵。它仍然是空白的。尽管看起来我设置了具有1种颜色纹理的FBO,但即使我将FBO对象选择到上下文中,它仍然只会呈现屏幕。

    我想要实现的是将这些形状绘制到屏幕外纹理(显然使用FBO),然后将其渲染到屏幕上某处绘制的精灵(或立方体或我们)的表面上。然而,无论我绘制什么,似乎都是在屏幕上绘制的。

    tex(tex_object_ID);函数只是OpenGL标准纹理绑定的简写包装器。它将纹理选择到当前渲染上下文中。

    无论我尝试什么,我都会得到这样的结果:精灵是空白的,但所有这些形状都应该出现在那里,而不是在主屏幕上。 (我没有将渲染绑定到FBO吗?为什么它仍然在屏幕上渲染?)

    enter image description here

    我认为这只是我缺少正确顺序设置FBO的后勤工作。任何人都可以告诉我的代码有什么问题吗?

    我不知道为什么背景是红色的,因为我在选择FBO后将其清除。这是精灵应该得到红色背景&在它上面绘制的形状。

    /*-- Initialization -- */
    
    GLuint texture = 0;
    GLuint Framebuffer = 0;
    
    GLuint GenerateFrameBuffer(int dimension)
    {
        glEnable(GL_TEXTURE_2D);
        glGenTextures(1, &texture);
        glBindTexture(GL_TEXTURE_2D, texture);
    
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, dimension, dimension, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
    
        glGenFramebuffers(1, &Framebuffer);
        glBindFramebuffer(GL_FRAMEBUFFER, Framebuffer);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
    
        glDrawBuffer(GL_COLOR);
        glReadBuffer(GL_COLOR);
    
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    
        if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
            console_log("GL_FRAMEBUFFER != GL_FRAMEBUFFER_COMPLETE\n");
    
        return texture;
    }
    
    // Store framebuffer texture (should I store texture here or Framebuffer object?)
    GLuint FramebufferHandle = GenerateFrameBuffer( 256 );
    

    遵循标准OpenGL初始化代码,分配内存,创建和绑定VBO等。这正常工作,初始化时没有错误。我可以在标准双缓冲区上成功渲染VBO,多边形,纹理多边形,线条等。

    接下来,在我的渲染循环中,我执行以下操作:

    // Possible problem?
    // Should FramebufferHandle be passed here?
    // I tried "texture" and "Framebuffer " as well, to no effect:
    
    glBindFramebuffer(GL_FRAMEBUFFER, FramebufferHandle); 
    
    // Correct projection, just calculates the view based on current zoom
    Projection = setOrthoFrustum(-config.zoomed_width/2, config.zoomed_width/2, -config.zoomed_height/2, config.zoomed_height/2, 0, 100);
    View.identity();
    Model.identity();
    
    // Mini shader, 100%  *guaranteed* to work, there are no errors in it (works normally on the screen)
    shaderProgramMini.use();
    
    //Clear frame buffer with blue color
    glClearColor(0.0f, 0.0f, 1.0f,  1.0f);
    glClear(GL_COLOR_BUFFER_BIT);// | GL_DEPTH_BUFFER_BIT);
    
    // Set yellow to draw different shapes on the framebuffer
    color = {1.0f,1.0f,0.0f};
    
    // Draw several shapes (already correctly stored in VBO objects)
    Memory.select(VBO_RECTANGLES); // updates uniforms
    glDrawArrays(GL_QUADS, 0, Memory.renderable[VBO_RECTANGLES].indexIndex);
    Memory.select(VBO_CIRCLES); // updates uniforms
    glDrawArrays(GL_LINES, 0, Memory.renderable[VBO_CIRCLES].indexIndex);
    Memory.select(VBO_2D_LIGHT); // updates uniforms
    glDrawArrays(GL_LINES, 0, Memory.renderable[VBO_2D_LIGHT].indexIndex);
    
    // Done writing to framebuffer
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    
    // Correct projection, just calculates the view based on current zoom
    Projection = setOrthoFrustum(-config.zoomed_width/2, config.zoomed_width/2, -config.zoomed_height/2, config.zoomed_height/2, 0, 100);
    View.identity();
    Model.identity();
    Model.scale(10.0);
    
    // Select texture shader to draw what was drawn on offscreen Framebuffer / texture
    // Standard texture shader, 100% *guaranteed* to work, there are no errors in it (works normally on the screen)
    shaderProgramTexture.use();
    
    // This is a wrapper for bind texture to ID, just shorthand function name
    tex(texture); // FramebufferHandle; // ? // maybe the mistake in binding to the wrong target object?
    
    color = {0.5f,0.2f,0.0f};
    Memory.select(VBO_SPRITE); Select a square VBO for rendering sprites (works if any other texture is assigned to it)
    
    // finally draw the sprite with Framebuffer's texture:
    glDrawArrays(GL_TRIANGLES, 0, Memory.renderable[VBO_SPRITE].indexIndex);
    

    我可能已经完全错了。或FramebufferHandle / Framebuffer /纹理对象未正确传递给某些东西。但是我整天都在度过,希望比我更有经验的人能看出错误。

1 个答案:

答案 0 :(得分:4)

GL_COLOR不是glDrawBuffer

的可接受值

请参阅OpenGL 4.6 API Compatibility Profile Specification, 17.4.1 Selecting Buffers for Writing, Table 17.4 and Table 17.5, page 628

  

NONEFRONT_LEFTFRONT_RIGHTBACK_LEFTBACK_RIGHTFRONTBACKLEFTRIGHTFRONT_AND_BACKAUXi

     

当上下文绑定到默认帧缓冲区时,DrawBuffer的参数,以及它们指示的缓冲区。相同的参数对ReadBuffer有效,但只选择了一个缓冲区,如章节中所述。

  

COLOR_ATTACHMENTi

     

当上下文绑定到帧缓冲区对象时,DrawBuffer和ReadBuffer的参数,以及它们指示的缓冲区。 COLOR_ATTACHMENTi i 的范围可以从零到MAX_COLOR_ATTACHMENTS的值减一。

Thsi表示glDrawBuffer(GL_COLOR);glReadBuffer(GL_COLOR);会产生GL_INVALID_ENUM错误。 请尝试使用COLOR_ATTACHMENT0


此外,glCheckFramebufferStatus(GL_FRAMEBUFFER)检查绑定到目标的帧缓冲对象的完整性。

这意味着

glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE

必须在

之前完成
glBindFramebuffer(GL_FRAMEBUFFER, 0);

或者您必须使用:

glNamedFramebufferReadBuffer(Framebuffer, GL_FRAMEBUFFER);