首页 > 解决方案 > 如何使用 QOpenGLBuffer:: PixelUnpackBuffer

问题描述

我无法弄清楚如何正确地从QOpenGLBuffer:: PixelUnpackBuffer.

  1. 写入 PBO 之前的正确设置是什么?
  2. QOpenGLBuffer::write无法使用简单的QImage.bits(),或glReadPixels()将 FBO 渲染传递到 PBO。它必须是特定类型的数据吗?
  3. 您如何使用书面 PBO 和Texture::setData()? 一个简单的Texture.setData(*format*, *pixel_type*, pubo, nullptr)就够了吗?

这里有一些代码来举例说明我在做什么:

QImage ScribbleArea::proImg(const QImage& image,
                         const QImage& tip,
                         const QString& vertexPosVar,
                         const QString& textureCoordVar){

    QOpenGLContext context;

    QOffscreenSurface offSurface;
    offSurface.setFormat(context.format());
    offSurface.create();

    // I'm sharing the context to show the offscreen Render into a
    // QOpenGLTextureBlitter under PaintGL()
    context.setShareContext(ScribbleArea::context()); 
    context.create();
    context.makeCurrent(&offSurface);

    m_fbo = new QOpenGLFramebufferObject(image.size());
    m_fbo->bind();

    context.functions()->glViewport(0, 0, image.width(), image.height());

    QOpenGLShaderProgram program(&context);
    program.addShaderFromSourceFile(QOpenGLShader::Vertex, "path to vertex shader");
    program.addShaderFromSourceFile(QOpenGLShader::Fragment, "path to fragment shader");
    program.link();
    program.bind();

    // The next block is basically what I understood how to setup a PBO using
    // Qt's OpenGL wrapper.
    QOpenGLBuffer *pubo = new QOpenGLBuffer(QOpenGLBuffer::PixelUnpackBuffer);
    pubo->setUsagePattern(QOpenGLBuffer::DynamicCopy);
    pubo->create();
    pubo->bind();
    pubo->map(QOpenGLBuffer::ReadWrite);
    pubo->allocate(image.bits(),image.sizeInBytes());
    pubo->write(0,image.bits(),image.sizeInBytes());
    pubo->unmap();
    pubo->release();

    // Testing how to use texture::setData() using straight bytes instead of the
    // baked method of setData(QImage).
    // I believe this is how to use the PBO's content to set the texture using QOpenGL.
    QOpenGLTexture textu(QOpenGLTexture::Target2D);
    textu.setSize(image.width(),image.height());
    textu.setFormat(QOpenGLTexture::RGBA8_UNorm);
    textu.allocateStorage();
    textu.setData(QOpenGLTexture::BGRA,QOpenGLTexture::UInt8,image.bits(),nullptr);

    // The texture bellow is a test to see if I was able to set up two textures and
    // change which one the shader should use.
    QOpenGLTexture brush(QOpenGLTexture::Target2D);
    brush.setData(tip);


    // Using native OpenGL snippets never work. The texture remain black.
//    GLuint tex;
//    glGenTextures(1, &tex);
//    glBindTexture(GL_TEXTURE_2D, tex);

//        glTexImage2D(GL_TEXTURE_2D, 0, 3, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, image.bits());
//        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

//    glBindTexture( GL_TEXTURE_2D, 0);

    GLint brTip = 1;
    brush.bind(brTip);
    GLint oriTxt = 0;
    textu.bind(oriTxt);

//Rest of the code. Following Amin Ahmadi tutorial.

标签: c++qtopenglqt5pbo

解决方案


您有一些误解,其中大多数与 Qt 的抽象类无关,而是与这些对象在 GL 本身中的工作方式有关:

// The next block is basically what I understood how to setup a PBO using
// Qt's OpenGL wrapper.
QOpenGLBuffer *pubo = new QOpenGLBuffer(QOpenGLBuffer::PixelUnpackBuffer);
pubo->setUsagePattern(QOpenGLBuffer::DynamicCopy);
pubo->create();
pubo->bind();

到现在为止还挺好...

pubo->map(QOpenGLBuffer::ReadWrite);

现在您尝试将缓冲区映射到内存。这是行不通的,因为缓冲区对象没有分配任何存储空间,所以这个调用应该失败并出现 GL 错误。此外,map会将内存地址返回到内存将被映射的位置,您在这里从不关心,因此即使映射有效,您也无法使用它。更糟糕的是,当一个缓冲区被映射时,你不能对它做任何 GL 操作(除非你创建一个持久映射)。

pubo->allocate(image.bits(),image.sizeInBytes());

好的,现在你创建一些存储。但这只是因为映射操作较早失败。

pubo->write(0,image.bits(),image.sizeInBytes());

这也应该有效。也只是因为您在这里没有活动的内存映射。

pubo->unmap();

这将失败,因为缓冲区未映射。但没关系。无论如何,您从来不需要也不打算使用缓冲区映射。

  1. 写入 PBO 之前的正确设置是什么?

创建缓冲区对象,并为其分配(足够的)存储空间。

  1. QOpenGLBuffer::write无法使用简单的QImage.bits(),或glReadPixels()将 FBO 渲染传递到 PBO。它必须是特定类型的数据吗?

不知道你在说什么。将数据从一个QImage写入它会起作用。你glReadPixels在这里的意思是不清楚的。如果要将像素读入缓冲区对象,则需要将其绑定为GL_PIXEL_PACK_BUFFER,而不是_UNPACK_BUFFER

为什么说“它不起作用”?

  1. 您如何使用书面 PBO 和Texture::setData()? 一个简单的Texture.setData(*format*, *pixel_type*, pubo, nullptr)

这不是QOpenGLTexture::setData()我所知道的(即可以在文档中找到),它会采用任何QtOpenGLBuffer参数。

在 OpenGL 中,当 aGL_PIXEL_UNPACK_BUFFER被绑data定时,函数的指针glTexImage...()将被视为该缓冲区对象的字节偏移量。因此,您只需要绑定您的pobo, 并setData使用正确的值调用,但显然您永远不会将pobo其作为参数传递给。setData

顺便说一句,那些 Qt OpenGL 抽象产生的问题比它们解决的问题还要多(例如,QtOpenGLBuffer抽象使 GL 缓冲区对象看起来像是类型化的,这是完全错误的——同一个缓冲区对象可以同时绑定到多个绑定目标)。然而,无论你对这些抽象的看法是什么,它们都不会让你免于学习实际的底层 GL 对象是如何工作的——实际上,使用它们你必须同时学习 GLQt 的抽象抽象语义。那些。


推荐阅读