代码之家  ›  专栏  ›  技术社区  ›  Alec Jacobson

如何将抗锯齿图像渲染到纹理(然后写入PNG)?

  •  0
  • Alec Jacobson  · 技术社区  · 6 年前

    我想使用“渲染到纹理”范例来编写OpenGL 3D渲染的.png屏幕快照。我让它工作 没有 多个采样,但我正在努力得到一个消除混叠的图像。

    首先,这可能吗?

    其次,什么是API调用的正确组合?

    (第三个问题,如何更好地调试它? glCheckFramebufferStatus 显然还不够)。

    以下是我的工作内容:

      // https://stackoverflow.com/questions/7402504/multisampled-render-to-texture-in-ios
      GLuint texture;
      glGenTextures(1, &texture);
      glBindTexture(GL_TEXTURE_2D, texture);
      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    
      GLuint resolved_framebuffer, resolvedColorRenderbuffer;
      glGenFramebuffers(1, &resolved_framebuffer);
      glBindFramebuffer(GL_FRAMEBUFFER, resolved_framebuffer);
      glGenRenderbuffers(1, &resolvedColorRenderbuffer);
      glBindRenderbuffer(GL_RENDERBUFFER, resolvedColorRenderbuffer);
      glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
    
      assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
    
      GLuint framebuffer;
      glGenFramebuffers(1, &framebuffer);
      glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
    
      GLuint colorRenderbuffer, depthRenderbuffer;
      glGenRenderbuffers(1, &colorRenderbuffer);
      glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
      glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_RGBA8, width, height);
      glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderbuffer);
    
      glGenRenderbuffers(1, &depthRenderbuffer);
      glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
      glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT16, width, height);
      glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);
    
    
      assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
    
      glBindFramebuffer( GL_FRAMEBUFFER, framebuffer );
      glClearColor(background_color(0), background_color(1), background_color(2), 0.f);
      glClear(GL_COLOR_BUFFER_BIT);// | GL_DEPTH_BUFFER_BIT);
    
      draw_scene();
    
      glBindFramebuffer( GL_READ_FRAMEBUFFER, framebuffer );
      glBindFramebuffer( GL_DRAW_FRAMEBUFFER, resolved_framebuffer );
      // https://forum.juce.com/t/ios-8-getting-the-demo-building/13570/20
      glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
      // ^--- this is throwing `GL_INVALID_OPERATION`
    
    
      GLubyte* pixels = (GLubyte*)calloc(width*height*4,sizeof(GLubyte));
      glReadPixels(0, 0,width, height,GL_RGBA, GL_UNSIGNED_BYTE, pixels);
    
      writePNG(pixels);
    

    现在我得到一张空白图片 glBlitFramebuffer 正在投掷 GL_INVALID_OPERATION . 显然 this error can correspond to many things ,我也不确定哪一个适用。根据 glCheckFramebufferStatus状态 .

    这个问题以前也曾以类似的形式提出过:

    但没有一个答案能提供一个完整的工作示例。我想找到/创造一个 最小值 这个例子。

    1 回复  |  直到 6 年前
        1
  •  2
  •   BDL Vyxzl    6 年前

    上的教程 https://learnopengl.com/Advanced-OpenGL/Anti-Aliasing 基本上得到了我需要的。工作解决方案是:

      unsigned int framebuffer;
      glGenFramebuffers(1, &framebuffer);
      glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
      // create a multisampled color attachment texture
      unsigned int textureColorBufferMultiSampled;
      glGenTextures(1, &textureColorBufferMultiSampled);
      glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, textureColorBufferMultiSampled);
      glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA, width, height, GL_TRUE);
      glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
      glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, textureColorBufferMultiSampled, 0);
      // create a (also multisampled) renderbuffer object for depth and stencil attachments
      unsigned int rbo;
      glGenRenderbuffers(1, &rbo);
      glBindRenderbuffer(GL_RENDERBUFFER, rbo);
      glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, width, height);
      glBindRenderbuffer(GL_RENDERBUFFER, 0);
      glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
      assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
      glBindFramebuffer(GL_FRAMEBUFFER, 0);
    
      // configure second post-processing framebuffer
      unsigned int intermediateFBO;
      glGenFramebuffers(1, &intermediateFBO);
      glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO);
      // create a color attachment texture
      unsigned int screenTexture;
      glGenTextures(1, &screenTexture);
      glBindTexture(GL_TEXTURE_2D, screenTexture);
      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
      glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, screenTexture, 0);    // we only need a color buffer
      assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
      glBindFramebuffer(GL_FRAMEBUFFER, 0);
    
      glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
    
      draw_scene();
    
      glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
      glBindFramebuffer(GL_DRAW_FRAMEBUFFER, intermediateFBO);
      glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
    
      glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO);
      GLubyte* pixels = (GLubyte*)calloc(width*height*4,sizeof(GLubyte));
      glReadPixels(0, 0,width, height,GL_RGBA, GL_UNSIGNED_BYTE, pixels);
    
      writePNG(pixels);
    

    在最初的问题中,代码中似乎至少有两个错误:

    1. 这个 framebuffer 应该有多个样本 纹理 附加的,不是renderbuffer( glFramebufferTexture2D(... GL_TEXTURE_2D_MULTISAMPLE 而不是 glRenderbufferStorageMultisample )
    2. 必须打电话 glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO); 切割后和切割前 glReadPixels