c++ - 如何将屏幕外渲染到 Linux 上的图像?

标签 c++ qt opengl-es opengl-es-2.0 egl

我正在尝试使用 egl 对图像进行离屏渲染。

我的代码没有产生任何错误。 egl 部分似乎是正确的,fbo 也很完整。但是当我使用 glReadPixels 读取像素时,我总是得到一个黑色图像(我用红色清除了整个场景,所以图像也应该是红色的)。

我不知道哪里出了问题。

此外,我注意到 glRenderbufferStorage 只能支持 16 位色深。 GL_RGBA8 被认为是此函数的无效参数。对于严肃的 opengl 应用程序,16 位是不是有点低?

我的环境是带有 mesa 和 intel 图形的 Ubuntu 14.10。

#include <QCoreApplication>
#include <QDebug>
#include <QImage>
#include <GLES2/gl2.h>
#include <EGL/egl.h>

int main(int argc, char *argv[])
{
    #define CONTEXT_ES20

    #ifdef CONTEXT_ES20
        EGLint ai32ContextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2,
                                                     EGL_NONE };
    #endif

    // Step 1 - Get the default display.
    EGLDisplay eglDisplay = eglGetDisplay((EGLNativeDisplayType)0);

    // Step 2 - Initialize EGL.
    eglInitialize(eglDisplay, 0, 0);

    #ifdef CONTEXT_ES20
    // Step 3 - Make OpenGL ES the current API.
    eglBindAPI(EGL_OPENGL_ES_API);

    // Step 4 - Specify the required configuration attributes.
    EGLint pi32ConfigAttribs[5];
    pi32ConfigAttribs[0] = EGL_SURFACE_TYPE;
    pi32ConfigAttribs[1] = EGL_WINDOW_BIT;
    pi32ConfigAttribs[2] = EGL_RENDERABLE_TYPE;
    pi32ConfigAttribs[3] = EGL_OPENGL_ES2_BIT;
    pi32ConfigAttribs[4] = EGL_NONE;
    #else
    EGLint pi32ConfigAttribs[3];
    pi32ConfigAttribs[0] = EGL_SURFACE_TYPE;
    pi32ConfigAttribs[1] = EGL_WINDOW_BIT;
    pi32ConfigAttribs[2] = EGL_NONE;
    #endif

    // Step 5 - Find a config that matches all requirements.
    int iConfigs;
    EGLConfig eglConfig;
    eglChooseConfig(eglDisplay, pi32ConfigAttribs, &eglConfig, 1,
                                                    &iConfigs);

    if (iConfigs != 1) {
        printf("Error: eglChooseConfig(): config not found.\n");
        exit(-1);
    }

    // Step 6 - Create a surface to draw to.
    EGLSurface eglSurface;
    eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig,
                                  (EGLNativeWindowType)NULL, NULL);

    // Step 7 - Create a context.
    EGLContext eglContext;
    #ifdef CONTEXT_ES20
        eglContext = eglCreateContext(eglDisplay, eglConfig, NULL,
                                               ai32ContextAttribs);
    #else
        eglContext = eglCreateContext(eglDisplay, eglConfig, NULL, NULL);
    #endif

    // Step 8 - Bind the context to the current thread
    eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);

    GLuint fboId = 0;
    GLuint renderBufferWidth = 1280;
    GLuint renderBufferHeight = 720;

    // create a framebuffer object
    glGenFramebuffers(1, &fboId);
    glBindFramebuffer(GL_FRAMEBUFFER, fboId);

    // create a texture object
    /*  GLuint textureId;
     glGenTextures(1, &textureId);
     glBindTexture(GL_TEXTURE_2D, textureId);
     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);                             
     //GL_LINEAR_MIPMAP_LINEAR
     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
     glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_HINT, GL_TRUE); // automatic mipmap
     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, renderBufferWidth, renderBufferHeight, 0,
                  GL_RGB, GL_UNSIGNED_BYTE, 0);
     glBindTexture(GL_TEXTURE_2D, 0);
     // attach the texture to FBO color attachment point
     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                         GL_TEXTURE_2D, textureId, 0);
     */
     qDebug() << glGetError();
     GLuint renderBuffer;
     glGenRenderbuffers(1, &renderBuffer);
     glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
     qDebug() << glGetError();
     glRenderbufferStorage(GL_RENDERBUFFER,
                           GL_RGB565,
                           renderBufferWidth,
                           renderBufferHeight);
     qDebug() << glGetError();
     glFramebufferRenderbuffer(GL_FRAMEBUFFER,
                               GL_COLOR_ATTACHMENT0,
                               GL_RENDERBUFFER,
                               renderBuffer);

      qDebug() << glGetError();
      GLuint depthRenderbuffer;
      glGenRenderbuffers(1, &depthRenderbuffer);
      glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
      glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,     renderBufferWidth, renderBufferHeight);
      glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);

      // check FBO status
      GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
      if(status != GL_FRAMEBUFFER_COMPLETE) {
          printf("Problem with OpenGL framebuffer after specifying color render buffer: \n%x\n", status);
      } else {
          printf("FBO creation succedded\n");
  }

  glClearColor(1.0,0.0,0.0,1.0);
  glClear(GL_COLOR_BUFFER_BIT);

  qDebug() << eglSwapBuffers(   eglDisplay, eglSurface);
  int size = 4 * renderBufferHeight * renderBufferWidth;
  printf("print size");
  printf("size %d", size);
  qDebug() << size;

  unsigned char *data2 = new unsigned char[size];

  glReadPixels(0,0,renderBufferWidth,renderBufferHeight,GL_RGB, GL_RGB565, data2);

  QImage image(data2, renderBufferWidth,  renderBufferHeight,renderBufferWidth*2, QImage::Format_RGB16);

  image.save("result.png");


  qDebug() << "done";


  QCoreApplication a(argc, argv);

  return a.exec();
}

最佳答案

OpenGL ES 2.0 支持glReadPixels() 的格式/类型非常有限。不能保证支持您尝试使用的那些:

glReadPixels(0 ,0, renderBufferWidth, renderBufferHeight,
             GL_RGB, GL_RGB565, data2);

仅支持两种格式/类型:

  • GL_RGBA/GL_UNSIGNED_BYTE
  • 依赖于实现的组合。

可以通过以下方式查询依赖于实现的组合的格式和类型:

GLint format = 0, type = 0;
glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &format);
glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &type);

这可以为您提供以下组合之一:

  • GL_RGB/GL_UNSIGNED_BYTE
  • GL_RGB/GL_UNSIGNED_SHORT_5_6_5
  • GL_RGBA/GL_UNSIGNED_SHORT_4_4_4_4
  • GL_RGBA/GL_UNSIGNED_SHORT_5_5_5_1
  • GL_ALPHA/GL_UNSIGNED_BYTE

因此,如果实现从上面的 glGetIntegerv() 调用中返回相应的值,那么您尝试使用的组合可能 得到实现的支持。但是,即使它受支持,您的 glReadPixels() 调用的参数中也存在一个微妙但重要的错误:GL_RGB565 is a value for a format,而第 6 个参数是一个类型。调用必须是:

glReadPixels(0 ,0, renderBufferWidth, renderBufferHeight,
             GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data2);

关于c++ - 如何将屏幕外渲染到 Linux 上的图像?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28491665/

相关文章:

android - 在AndEngine中修改贴图像素

c++ - 为什么类的大小取决于成员声明的顺序?如何?

c++ - 如何将不同的数据类型推送到 void 缓冲区中?

c++ - 如何在 C++ 中使用带有 freopen 的 cmake?

c++ - Qt 和 openGL 的 gluPerspective 等价物

ios - 在 Interface Builder (Xcode) 中使用来自 Shadertoy 的着色器

c++ - 当进程崩溃时,我如何抑制所有错误对话框(我只希望它静默崩溃)

c++ - 理解 QGraphicsItemboundingRect 和 shape 方法之间的交互

c++ - Qt创建MDI文档窗口

三星 Galaxy SIII 上的 Android OpenGL 透明度