c++ - 如何使我的 OpenGL 视频具有与 QQuickItem 相同的大小和位置?

标签 c++ qt opengl qml

按照我的最新问题:My OpenGL QQuickItem won't have the size I want ,我现在正在尝试,而不是为我的 OpenGL 视频设置任意大小,以将其放入我的 QQuickItem 中。

我听说 QQuickItem::transform() 会给我一个转换矩阵列表。我假设此列表包含所有需要的转换,以达到我的 QQuickItem 的大小和位置的正方形。 <<<< 这是真的吗?如果是这样,转换来自什么坐标和视口(viewport)尺寸?

鉴于此为真,我制作了以下最小的可验证和可编译示例,它试图使绿屏适合我的 QQuickItem 的大小。但目前,它只占用整个屏幕。

我使用函数 getModelMatrix()(您可以在下面找到)获取所有转换并从中创建一个矩阵。然后我将这些转换应用于我的顶点着色器,方法是

gl_Position = u_transform * vertexIn;

正如我所说,结果是绿屏。但是,它与我的窗口具有相同的尺寸,而不是 main.qml

中指定的尺寸 640x480 和 x,y=0

你可以在这里找到一个最小的可编译和可验证的例子:https://github.com/lucaszanella/openglqtquickexample/tree/88fe0092d663dd92c551c72acccd0bf058fe7e5b

OpenGlVideoQtQuick.cpp:

#include "OpenGlVideoQtQuick.h"

#define GET_STR(x) #x
#define A_VER 3
#define T_VER 4

//Simple shader. Outpus the same location as input, I guess
const char *vString2 = GET_STR(
    attribute vec4 vertexIn;
    attribute vec2 textureIn;
    varying vec2 textureOut;
    uniform mat4 u_transform;   
    void main(void)
    {
        gl_Position = u_transform * vertexIn;
        textureOut = textureIn;
    }
);

const char *tString2 = GET_STR(
    varying vec2 textureOut;
    uniform sampler2D tex_y;
    uniform sampler2D tex_u;
    uniform sampler2D tex_v;
    void main(void)
    {
        vec3 yuv;
        vec3 rgb;
        yuv.x = texture2D(tex_y, textureOut).r;
        yuv.y = texture2D(tex_u, textureOut).r - 0.5;
        yuv.z = texture2D(tex_v, textureOut).r - 0.5;
        rgb = mat3(1.0, 1.0, 1.0,
            0.0, -0.39465, 2.03211,
            1.13983, -0.58060, 0.0) * yuv;
        gl_FragColor = vec4(rgb, 1.0);
    }

);

OpenGlVideoQtQuick::OpenGlVideoQtQuick():
    openGlVideoQtQuickRenderer(nullptr)
{
    connect(this, &QQuickItem::windowChanged, this, &OpenGlVideoQtQuick::handleWindowChanged);

    update();
}

void OpenGlVideoQtQuick::handleWindowChanged(QQuickWindow *win)
{
    if (win) {
        connect(win, &QQuickWindow::beforeSynchronizing, this, &OpenGlVideoQtQuick::sync, Qt::DirectConnection);
        win->setClearBeforeRendering(false);
    }
}

QMatrix4x4 OpenGlVideoQtQuick::getModelMatrix() {
    QMatrix4x4 result;

    // Compose model matrix from our transform properties in the QML
    QQmlListProperty<QQuickTransform> transformations = transform();
    const int count = transformations.count(&transformations);
    for (int i=0; i<count; i++) {
        QQuickTransform *transform = transformations.at(&transformations, i);
        transform->applyTo(&result);
    }

    return result;
}


void OpenGlVideoQtQuick::update()
{
    if (window())
        window()->update();
}


OpenGlVideoQtQuickRenderer::~OpenGlVideoQtQuickRenderer()
{
    delete program;
}



void OpenGlVideoQtQuick::sync()
{
    if (!openGlVideoQtQuickRenderer) {
        openGlVideoQtQuickRenderer = new OpenGlVideoQtQuickRenderer();
        connect(window(), &QQuickWindow::beforeRendering, openGlVideoQtQuickRenderer, &OpenGlVideoQtQuickRenderer::render, Qt::DirectConnection);
        connect(window(), &QQuickWindow::afterRendering, this, &OpenGlVideoQtQuick::update, Qt::DirectConnection);
    } 
    this->openGlVideoQtQuickRenderer->qQuickVideoMatrix = getModelMatrix();
}

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
};


void OpenGlVideoQtQuickRenderer::render()
{
    if (this->firstRun) {
        std::cout << "Creating QOpenGLShaderProgram " << std::endl;
        this->firstRun = false;
        program = new QOpenGLShaderProgram();
        initializeOpenGLFunctions();

        std::cout << "Fragment Shader compilation: " << program->addShaderFromSourceCode(QOpenGLShader::Fragment, tString2) << std::endl;
        std::cout << "Vertex Shader compilation: " << program->addShaderFromSourceCode(QOpenGLShader::Vertex, vString2) << std::endl;

        program->bindAttributeLocation("vertexIn",A_VER);
        program->bindAttributeLocation("textureIn",T_VER);
        std::cout << "program->link() = " << program->link() << std::endl;

        glGenTextures(3, texs);//TODO: ERASE THIS WITH glDeleteTextures
    }
    program->bind();
    program->setUniformValue("u_transform", this->qQuickVideoMatrix);


    //glViewport(50, 50, 50, 50);

    glVertexAttribPointer(A_VER, 2, GL_FLOAT, 0, 0, ver);
    glEnableVertexAttribArray(A_VER);

    glVertexAttribPointer(T_VER, 2, GL_FLOAT, 0, 0, tex);
    glEnableVertexAttribArray(T_VER);

    unis[0] = program->uniformLocation("tex_y");
    unis[1] = program->uniformLocation("tex_u");
    unis[2] = program->uniformLocation("tex_v");

    //Y
    glBindTexture(GL_TEXTURE_2D, texs[0]);
    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);



    glDrawArrays(GL_TRIANGLE_STRIP,0,4);

    program->disableAttributeArray(A_VER);
    program->disableAttributeArray(T_VER);
    program->release();

}

OpenGlVideoQtQuick.h:

#ifndef OpenGlVideoQtQuick_H
#define OpenGlVideoQtQuick_H

#include <QtQuick/QQuickItem>
#include <QtGui/QOpenGLShaderProgram>
#include <QtGui/QOpenGLFunctions>
#include <QtQuick/qquickwindow.h>
#include <QtGui/QOpenGLShaderProgram>
#include <QtGui/QOpenGLContext>
#include <QString>
#include <iostream>
#include <QTimer>



class OpenGlVideoQtQuickRenderer : public QObject, protected QOpenGLFunctions
{
    Q_OBJECT

public:
    OpenGlVideoQtQuickRenderer() {        
    }
    ~OpenGlVideoQtQuickRenderer();
    QMatrix4x4 qQuickVideoMatrix;



public slots:
    void render();

private:
    QOpenGLShaderProgram* program;
    GLuint unis[3] = {0};
    GLuint texs[3] = {0};
    unsigned char *datas[3] = { 0 };
    bool firstRun = true;
    //TODO: make this variable according to video data
    int width = 1920;
    int height = 1080;
};

class OpenGlVideoQtQuick : public QQuickItem
{
    Q_OBJECT

public:
    OpenGlVideoQtQuick();
    QMatrix4x4 getModelMatrix();


private slots:
    void handleWindowChanged(QQuickWindow *win);
public slots:
    void sync();
    void update();//Updates the window

private:
    OpenGlVideoQtQuickRenderer *openGlVideoQtQuickRenderer;

};

#endif // OpenGlVideoQtQuick_H

ma​​in.qml:

import QtQuick 2.0
import OpenGLComponents 1.0
Item {
    width: 1280
    height: 720
    OpenGlVideoQtQuick {
        width: 640
        height: 480

    }
}

最佳答案

从你的问题和你的代码中,你“期望”看到的内容有点不清楚,但我确实看到了一些可能对你有帮助的问题:

  1. 我认为您的渲染循环实际上并未被调用。您必须在构造函数中执行此操作:setFlag(ItemHasContents);

  2. 确保将一些纹理/视频数据传递到您的 glTexImage2D() 调用中,否则您会得到一些垃圾(随机绿色垃圾?)

  3. 您可能想看看 QQuickItem::widthChangedQQuickItem::heightChanged 信号

  4. 确保在调试时调用 glViewport() 以及 glClear() 以避免混淆 - 您可以稍后在不需要时删除它们不再需要它们了

关于c++ - 如何使我的 OpenGL 视频具有与 QQuickItem 相同的大小和位置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54902244/

相关文章:

java - 我可以为 OpenGL 中的静态对象推送一次矩阵吗?

c++ - 制作替换系统库中的函数调用的 DLL 的问题

windows - 使用 Qt 显示半透明/不规则形状的窗口

Qt 5 : read property inside Loader

c++ - Qt QSqlDatabase 和 QSqlTableModel 与 PostgreSQL View 的兼容性?

c++ - 为什么我们选择 "bounding box"方法来填充一个三角形呢?

C++,find_if 不工作

c++ - 如何使用 (*mpORBextractorLeft)(in,cv::Mat(),monKeys,Descriptors);

c++ - 如何创建类似 std::function 的包装器?

c++ - 文字类类型成员函数约束