QT QML 中的 OpenGL,无法更新屏幕上的图像

OpenGL in QT QML, can't update my image on screen

本文关键字:屏幕 更新 图像 QML 中的 OpenGL QT      更新时间:2023-10-16

为了将OpenGL与QML一起使用,我如下所述创建了OpenGlVideoQtQuickOpenGlVideoQtQuickRenderer类。唯一的区别是我添加了updateData()功能以更新缓冲区,而在示例中,在屏幕上绘制静态图像。

这是OpenGlVideoQtQuickRenderer的关键部分,即paint函数

void OpenGlVideoQtQuickRenderer::paint()
{
    if (this->firstRun) {
        this->firstRun = false;
        //qDebug() << "initializeGL";
        std::cout << "initializing gl" << std::endl;
        //初始化opengl (QOpenGLFunctions继承)函数
        initializeOpenGLFunctions();
        datas[0] = new unsigned char[width*height];     //Y
        datas[1] = new unsigned char[width*height/4];   //U
        datas[2] = new unsigned char[width*height/4];   //V   
        //this->m_F  = QOpenGLContext::currentContext()->functions();
        //program加载shader(顶点和片元)脚本
        //片元(像素)
        std::cout << program.addShaderFromSourceCode(QOpenGLShader::Fragment, tString2) << std::endl;
        //顶点shader
        std::cout << program.addShaderFromSourceCode(QOpenGLShader::Vertex, vString2) << std::endl;
        //设置顶点坐标的变量
        program.bindAttributeLocation("vertexIn",A_VER);
        //设置材质坐标
        program.bindAttributeLocation("textureIn",T_VER);
        //编译shader
        std::cout << "program.link() = " << program.link() << std::endl;
    }
    program.bind();
    //传递顶点和材质坐标
    //顶点
    static const GLfloat ver[] = {
        -1.0f,-1.0f,
        1.0f,-1.0f,
        -1.0f, 1.0f,
        1.0f,1.0f
    };
    //材质
    static const GLfloat tex[] = {
        0.0f, 1.0f,
        1.0f, 1.0f,
        0.0f, 0.0f,
        1.0f, 0.0f
    };
    //顶点
    glVertexAttribPointer(A_VER, 2, GL_FLOAT, 0, 0, ver);
    glEnableVertexAttribArray(A_VER);
    //材质
    glVertexAttribPointer(T_VER, 2, GL_FLOAT, 0, 0, tex);
    glEnableVertexAttribArray(T_VER);
    //glUseProgram(&program);
    //从shader获取材质
    unis[0] = program.uniformLocation("tex_y");
    unis[1] = program.uniformLocation("tex_u");
    unis[2] = program.uniformLocation("tex_v");
    //创建材质
    glGenTextures(3, texs);
    //Y
    glBindTexture(GL_TEXTURE_2D, texs[0]);
    //放大过滤,线性插值   GL_NEAREST(效率高,但马赛克严重)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    //创建材质显卡空间
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, 0);
    //U
    glBindTexture(GL_TEXTURE_2D, texs[1]);
    //放大过滤,线性插值
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    //创建材质显卡空间
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width/2, height / 2, 0, GL_RED, GL_UNSIGNED_BYTE, 0);
    //V
    glBindTexture(GL_TEXTURE_2D, texs[2]);
    //放大过滤,线性插值
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    //创建材质显卡空间
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width / 2, height / 2, 0, GL_RED, GL_UNSIGNED_BYTE, 0);
    ///分配材质内存空间

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texs[0]); //0层绑定到Y材质
    //修改材质内容(复制内存内容)
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE, datas[0]);
    //与shader uni遍历关联
    glUniform1i(unis[0], 0);

    glActiveTexture(GL_TEXTURE0+1);
    glBindTexture(GL_TEXTURE_2D, texs[1]); //1层绑定到U材质
                                           //修改材质内容(复制内存内容)
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width/2, height / 2, GL_RED, GL_UNSIGNED_BYTE, datas[1]);
    //与shader uni遍历关联
    glUniform1i(unis[1],1);

    glActiveTexture(GL_TEXTURE0+2);
    glBindTexture(GL_TEXTURE_2D, texs[2]); //2层绑定到V材质
                                           //修改材质内容(复制内存内容)
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width / 2, height / 2, GL_RED, GL_UNSIGNED_BYTE, datas[2]);
    //与shader uni遍历关联
    glUniform1i(unis[2], 2);
    glDrawArrays(GL_TRIANGLE_STRIP,0,4);
    //this->update();
    // Not strictly needed for this example, but generally useful for when
    // mixing with raw OpenGL.
    m_window->resetOpenGLState();//COMMENT OR NOT?
}

这是我用来更新要绘制的缓冲区的功能:

void OpenGlVideoQtQuickRenderer::updateData(unsigned char**data)
{
    std::cout << "updating data..." << std::endl;
    memcpy(datas[0], data[0], width*height);
    memcpy(datas[1], data[1], width*height/4);
    memcpy(datas[2], data[2], width*height/4);
    //I should update something here
}

我唯一的问题是,我看到使用新数据调用功能更新,因此缓冲区正在更新。但是,屏幕继续处于初始位置(绿色)。我敢肯定,必须有一个我必须打电话来更新所有内容的函数。

我还需要在updateData中打电话吗?

我尝试了各种更新数据的方式,但是图像仍然不会更新

            this->openGlVideoQtQuickRenderer->paint();
            if (this->openGlVideoQtQuick->window()) {
                std::cout << "window update" << std::endl;
                this->openGlVideoQtQuick->update();
                this->openGlVideoQtQuick->window()->update();
            }

但是,如果我调整了屏幕大小,我可以看到不到一秒钟的图像,并且消失了。

整个代码如果有人想看:https://github.com/lucaszanella/orwell/blob/2aff3b97abd88e6ec2980856718e1c8302d4161616161616161616/

好吧,我试图更新您所看到的窗口,但是唯一有效的是

connect(window(), &QQuickWindow::afterRendering, this, &OpenGlVideoQtQuick::update, Qt::DirectConnection);

(我不得不从上方访问该更新窗口才能工作)