c++ - 我的 OpenGL QQuickItem 没有我想要的大小

标签 c++ qt opengl qml glsl

我在 Qtquick 上使用 OpenGL 绘图,无论我在 QML 上的 OpenGlVideoQtQuick 上放置什么尺寸,它总是占据窗口的整个空间。我希望能够控制它的大小。

我创建了这个使用 OpenGL 绘制绿屏的最小示例。我应该能够控制 QQuickItem 的大小,从而控制绿屏的大小,例如占据屏幕的 1/4。

您可以看到,我什至尝试(并评论)了 QQuickItem 上的 setWidthsetHeight 方法。这是行不通的。

你可以在这里看到一个最小的工作和可编译的例子:https://github.com/lucaszanella/openglqtquickexample/tree/4de3ec1535eb40c31788512a027c1e86f76d4090

如何控制 QQuickItem 的大小?

主.qml:

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

    }
}

主要.cpp:

#include <iostream>
#include <QApplication>
#include <QMediaPlayer>
#include <QPushButton> 
#include <QGuiApplication>

#include <QtQuick/QQuickView>

#include "OpenGlVideoQtQuick.h"

int main(int argc, char **argv)
{
    QGuiApplication app(argc, argv);
    QCoreApplication::addLibraryPath("./");
    qmlRegisterType<OpenGlVideoQtQuick>("OpenGLComponents", 1, 0, "OpenGlVideoQtQuick");

    QQuickView view;
    view.setResizeMode(QQuickView::SizeRootObjectToView);
    view.setSource(QUrl("qrc:/main.qml"));
    view.show();

    return app.exec();
}

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;
    void main(void)
    {
        gl_Position = 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();
    //setWidth(640);
    //setHeight(480);
    //width=640
    //height=480
}

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

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

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();

    //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();

}

最佳答案

您必须在顶点着色器中缩放顶点坐标。这可以通过 4x4 矩阵 (mat4) 来完成。 声明 uniform variable类型 mat4 并通过矩阵转换(乘以)顶点坐标,然后将其分配给剪辑空间位置 gl_Position:

attribute vec4 vertexIn;
attribute vec2 textureIn;

varying vec2 textureOut;

uniform mat4 u_transform;   

void main(void)
{
    gl_Position = u_transform * vertexIn;
    textureOut = textureIn;
}   

必须在程序中设置制服的值,由 QOpenGLShaderProgram::setUniformValue() .值的类型必须是 QMatrix4x4 .

例如

program->bind();

QMatrix4x4 transform;
transform.setToIdentity();
transform.scale(0.25, 0.25);

program->setUniformValue("u_transform", transform);

当然也可以使用glm::mat4。在这种情况下,制服的值必须由 glUniformMatrix4fv 设置:

GLint transformLoc = program->uniformLocation("u_transform");

program->bind();

glm::mat4 transform(1.0f);
transform = glm::scale(transform, glm::vec3(0.25f, 0.25f, 1.0f));
glUniformMatrix4fv(transformLoc , 1, GL_FALSE, glm::value_ptr(transform ));

关于c++ - 我的 OpenGL QQuickItem 没有我想要的大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54872975/

相关文章:

c++ - OpenGL glTexImage2D 立方图和宽度/高度参数

c++ - 通过纹理四边形的 OpenGL 字体

c++ - 我应该如何在不同的操作系统上测试独立的应用程序

c++ - 我的类(指向另一个类的指针的容器)似乎无法访问公共(public)构造函数

c++ - 仅继承父级构造函数的部分参数

c++ - 如何使用 QT RegExp 从字符串中提取子字符串列表

c++ - 将行编辑的输入存储到字符串 qt

opengl - WebKit 是否使用 OpenGL 来呈现 CSS 过渡?

c++ - 模板参数中的函数调用

c++ - C++ 中 CV 限定的基类