精华内容
下载资源
问答
  • 上一篇文章讲到了利用C++这个桥梁,我们实现了QML和Java的交互。Qt 5大力推崇的QML/JS...接下来的这篇文章讲的是我们使用QML,借助Qt库和OpenGL,实现了使用着色器定义OpenGL的渲染方式,为大家呈现混合渲染的效果。
  • 此资源是演示程序,包含了Windows、Linux、MacOS X以及Android的演示程序,大家可以免...接下来的这篇文章讲的是我们使用QML,借助Qt库和OpenGL,实现了使用着色器定义OpenGL的渲染方式,为大家呈现混合渲染的效果。
  • 前面采用了离屏渲染,多线程的方式实现了nv12视频的播放,这次采用在QSG中渲染方式实现,也就是在渲染线程中。 原理同样是将图像纹理到一个FBO中,然后通过qt的接口带到QSG中进行显示。 采用opengl渲染并用qml显示...

    前面采用了离屏渲染,多线程的方式实现了nv12视频的播放,这次采用在QSG中渲染的方式实现,也就是在渲染线程中。

    原理同样是将图像纹理到一个FBO中,然后通过qt的接口带到QSG中进行显示。

    采用opengl渲染并用qml显示的接口类为QQuickFramebufferObject,渲染线程会在刷新画面的时候调用其createRenderer()方法用于创建渲染,这里我留了一个设置视频地址的接口,因为是显示视频嘛。
    

    #ifndef VideoRende_H
    #define VideoRende_H
    #include

    QT_FORWARD_DECLARE_CLASS(QTimer)
    QT_FORWARD_DECLARE_CLASS(DecodeThread)
    class VideoRender : public QQuickFramebufferObject
    {
    Q_OBJECT
    Q_PROPERTY(QString videoSource READ videoSource WRITE setVideoSource NOTIFY videoSourceChanged) //增加一个设置视频地址的属性
    public:
    explicit VideoRender(QQuickItem* parent = nullptr);
    ~VideoRender();
    Renderer* createRenderer() const override; //重写
    void getFrame(uchar **nv12Ptr,int *w, int *h); //用于在创建的Renderer中访问当前帧的图像数据

    signals:
    void videoSourceChanged();

    private:
    QTimer *m_timer{nullptr};
    QString m_videoSource;

    QString videoSource();
    void setVideoSource(QString);
    DecodeThread *m_decodeThr{nullptr};
    

    };

    #endif // VideoRende_H
    基实现如下

    #include “VideoRender.h”
    #include “nv12render.h”
    #include “NvDecode/decodethread.h”
    #include “logorenderer.h”
    #include
    #include
    #include

    class VideoFboRender : public QQuickFramebufferObject::Renderer //自定义一个FBO的渲染
    {
    public:
    VideoFboRender(){
    }

    ~VideoFboRender(){
    }
    
    //该函数主要从VideoRender中获取数据,用于在render()函数中的渲染;会先调用此函数再调用render
    void synchronize(QQuickFramebufferObject*item){
        dynamic_cast<VideoRender*>(item)->getFrame(&nv12Ptr,&videoW,&videoH);
                           //此处的item是创建Nv12FboRender的QQuickFramebufferObject对象,在这里可以从QQuickFramebufferObject中获取数据保留下来,用于render中的渲染
    

    // item->update(); //GUI线程中刷新,GUI阻塞,会影响画面,应该在QQuickFramebufferObject中用闹钟的方式刷新,避免阻塞,
    //阻塞GUI线程和渲染线程都不好
    }

    void render()override{
        m_nv12Render.render(nv12Ptr,videoW,videoH); //渲染当前帧
    

    // update(); //不是在GUI线程中刷新,GUI线程中的阻塞,不会影响画面;
    }

    QOpenGLFramebufferObject *createFramebufferObject(const QSize &size){
        QOpenGLFramebufferObjectFormat format;   //当大小发生变化时,会调用此函数生成对应大小的FBO
        format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
        format.setSamples(4);
        return new QOpenGLFramebufferObject(size,format);
    }
    

    private:
    Nv12Render m_nv12Render;
    uchar *nv12Ptr{nullptr};
    int videoW,videoH;
    };

    VideoRender::VideoRender(QQuickItem *parent):
    QQuickFramebufferObject(parent)
    {
    m_timer = new QTimer(this);
    m_timer->setInterval(30); //每过30ms刷新一次
    connect(m_timer,SIGNAL(timeout()),this,SLOT(update()));

    m_decodeThr = new DecodeThread;
    

    }

    VideoRender::~VideoRender()
    {
    m_decodeThr->requestInterruption();
    m_decodeThr->quit();
    m_decodeThr->wait();
    m_decodeThr->deleteLater();
    }

    QQuickFramebufferObject::Renderer *VideoRender::createRenderer() const
    {
    return new VideoFboRender; //返回我们自定义的Renderer。
    }

    void VideoRender::getFrame(uchar **nv12Ptr, int *w, int *h) //返回当前帧数据
    {
    *nv12Ptr = m_decodeThr->imgPtr;
    *w = m_decodeThr->videoW;
    *h = m_decodeThr->videoH;
    }

    QString VideoRender::videoSource()
    {
    return m_videoSource;
    }

    void VideoRender::setVideoSource(QString url)
    {
    if(m_videoSource != url){
    m_decodeThr->setUrl(url);
    m_decodeThr->setTimeInterval(m_timer->interval());
    m_decodeThr->start();
    m_timer->start();
    emit videoSourceChanged();
    }

    m_videoSource = url;
    

    }
    主要的结构就是这样了,接下来要说的是nv12的渲染了,这里和前面的nv12渲染有些不同,有几个坑。代码如下

    #ifndef NV12RENDER_H
    #define NV12RENDER_H
    #include
    #include

    #include <QtGui/qvector3d.h>
    #include <QtGui/qmatrix4x4.h>
    #include <QtGui/qopenglshaderprogram.h>
    #include <QtGui/qopenglfunctions.h>
    #include

    #include
    #include

    class Nv12Render : public QOpenGLFunctions
    {
    public:
    Nv12Render();
    void render(uchar*nv12Ptr, int w, int h); //渲染当前帧

    private:
    QOpenGLShaderProgram program;
    GLuint idY,idUV; //Y分量和UV分量的纹理id
    QOpenGLBuffer vbo; //用于在opengl服务端创建数据
    qreal m_fAngle;
    qreal m_fScale;
    };

    #endif // NV12RENDER_H
    以下是其实现

    #include “nv12render.h”
    #include
    #include
    #include
    #include <math.h>

    Nv12Render::Nv12Render()
    {
    initializeOpenGLFunctions();
    const char *vsrc =
    “attribute vec4 vertexIn;
    attribute vec4 textureIn;
    varying vec4 textureOut;
    uniform mediump mat4 matrix;
    void main(void)
    {
    gl_Position = vertexIn * matrix;
    textureOut = textureIn;
    }”;

    const char *fsrc =
            "varying mediump vec4 textureOut;\n"
            "uniform sampler2D textureY;\n"
            "uniform sampler2D textureUV;\n"
            "void main(void)\n"
            "{\n"
            "vec3 yuv; \n"
            "vec3 rgb; \n"
            "yuv.x = texture2D(textureY, textureOut.st).r - 0.0625; \n"
            "yuv.y = texture2D(textureUV, textureOut.st).r - 0.5; \n"
            "yuv.z = texture2D(textureUV, textureOut.st).g - 0.5; \n"
            "rgb = mat3( 1,       1,         1, \n"
                        "0,       -0.39465,  2.03211, \n"
                        "1.13983, -0.58060,  0) * yuv; \n"
            "gl_FragColor = vec4(rgb, 1); \n"
            "}\n";
    
    program.addCacheableShaderFromSourceCode(QOpenGLShader::Vertex,vsrc);
    program.addCacheableShaderFromSourceCode(QOpenGLShader::Fragment,fsrc);
    program.link();
    
    GLfloat points[]{
        -0.8f, 0.8f,
         0.8f, 0.8f,
         0.8f, -0.8f,
        -0.8f, -0.8f,
    
        0.0f,1.0f,
        1.0f,1.0f,
        1.0f,0.0f,
        0.0f,0.0f,
    };
    
    vbo.create();
    vbo.bind();
    vbo.allocate(points,sizeof(points));
    //不能在这里直接将program绑定,以及vbo等等,感觉这里的program整个渲染的一部分,还有其它的program,必须在render()函数中进行数据的绑定和纹理的生成
    GLuint ids[2];
    glGenTextures(2,ids);
    idY = ids[0];
    idUV = ids[1];
    m_fAngle = 0.0;
    m_fScale = 1.0;
    

    }

    void Nv12Render::render(uchar *nv12Ptr, int w, int h)
    {
    glClearColor(0.5f, 0.5f, 0.7f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glDisable(GL_DEPTH_TEST);

    program.bind(); //使用opengl切换为当前的program以使用shader
    QMatrix4x4 modelview;
    modelview.rotate(m_fAngle, 0.0f, 1.0f, 0.0f);
    modelview.rotate(m_fAngle, 1.0f, 0.0f, 0.0f);
    modelview.rotate(m_fAngle, 0.0f, 0.0f, 1.0f);
    modelview.scale(m_fScale);
    modelview.translate(0.0f, -0.2f, 0.0f);
    program.setUniformValue("matrix", modelview);
    
    vbo.bind(); //切换并使用创建好的顶点和纹理坐标数据
    program.enableAttributeArray("vertexIn");
    program.enableAttributeArray("textureIn");
    program.setAttributeBuffer("vertexIn",GL_FLOAT, 0, 2, 2*sizeof(GLfloat));
    program.setAttributeBuffer("textureIn",GL_FLOAT,2 * 4 * sizeof(GLfloat),2,2*sizeof(GLfloat));
    
    glActiveTexture(GL_TEXTURE0 + 1); //这里我试了有个奇葩的现象,必须先选择1号纹理用来渲染Y分量数据,然后必须使用0号纹理来渲染UV分量的数据,原因我暂时也还没搞清楚
    glBindTexture(GL_TEXTURE_2D,idY); //这真是一个大坑,我整了很久
    glTexImage2D(GL_TEXTURE_2D,0,GL_RED,w,h,0,GL_RED,GL_UNSIGNED_BYTE,nv12Ptr);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    
    glActiveTexture(GL_TEXTURE0 + 0); //使用0号纹理填充UV分量的数据
    glBindTexture(GL_TEXTURE_2D,idUV);
    glTexImage2D(GL_TEXTURE_2D,0,GL_RG,w >> 1,h >> 1,0,GL_RG,GL_UNSIGNED_BYTE,nv12Ptr + w*h);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    
    program.setUniformValue("textureUV",0);
    program.setUniformValue("textureY",1);
    glDrawArrays(GL_QUADS,0,4);
    program.disableAttributeArray("vertexIn");
    program.disableAttributeArray("textureIn");
    program.release(); //去掉program的绑定
    
    m_fAngle += 1.0f;
    

    }
    以下为qml中的调用

    import QtQuick 2.7
    import QtQuick.Controls 2.0
    import QtQuick.Layouts 1.3
    import QtMultimedia 5.9
    import SceneGraphRendering 1.0

    ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr(“Hello World”)

    Item{
        id: root
        anchors.fill: parent
        RenderItem{
            anchors.fill: parent
            videoSource: "D:/迅雷下载/香肠派对720p.mp4"
            Text {
                id: name2
                anchors.centerIn: parent
                font.pixelSize: 18
                color: "green"
                text: qsTr("texfffffffffffffffsft")
            }
        }
    
        MouseArea{
            anchors.fill: parent
            onClicked: {
                parent.grabToImage(function(result){
                    console.log(result.image)
    

    // result.saveToFile(“C:\Users\Administrator\Desktop\1.jpg”)
    })
    ani.start()
    }
    }

        Rectangle{
            id: rect
            width: parent.width * 0.7
            height: parent.height * 0.7
            anchors.centerIn: parent
            opacity: 0.5
            SequentialAnimation{
                id: ani
                ParallelAnimation{
                    NumberAnimation{
                        target: rect
                        properties: "width"
                        to: rect.width ? 0 : root.width * 0.7
                        duration: 800
                    }
                    NumberAnimation{
                        target: rect
                        properties: "height"
                        to: rect.height ? 0 : root.height * 0.7
                        duration: 800
                    }
                }
                ParallelAnimation{
                    NumberAnimation{
                        target: rect
                        properties: "width"
                        to: rect.width ? 0 : root.width * 0.7
                        duration: 800
                    }
                    NumberAnimation{
                        target: rect
                        properties: "height"
                        to: rect.height ? 0 : root.height * 0.7
                        duration: 800
                    }
                }
            }
        }
    }
    

    }
    我自己定义了一个动画用于检测当抓图是画面是否会卡,实时证明,抓图是不会卡的,但是如果把抓出来的图片储到文件里面就会卡。

    展开全文
  • Qt移动应用开发:实现跨平台的QML和OpenGL混合渲染  上一篇文章讲到了利用C++这个桥梁,我们...接下来的这篇文章讲的是我们使用QML,借助Qt库和OpenGL,实现了使用着色器定义OpenGL的渲染方式,为大家呈现混合渲染

    Qt移动应用开发:实现跨平台的QML和OpenGL混合渲染

              上一篇文章讲到了利用C++这个桥梁,我们实现了QML和Java的交互。Qt 5大力推崇的QML/JS开发,让轻量、快速开发的QML/JS打头阵,让重量的C++撑腰,几乎什么技术都能够实现。接下来的这篇文章讲的是我们使用QML,借助Qt库和OpenGL,实现了使用着色器定义OpenGL的渲染方式,为大家呈现混合渲染的效果。

    原创文章,反对未声明的引用。原博客地址:http://blog.csdn.net/gamesdev/article/details/38024327

             本文难度偏大,适合有经验的Qt开发同行学习交流。

             演示程序下载地址:这里

             源代码下载地址:这里

             演示程序的截图如下(Android):

             首先我们来看简单的QML代码。本例很简单,只有一个界面,没有任何界面的跳转。我们在前面显示一个矩形,上面写了”您好世界!”的文字,后面显示的是一个旋转的矩形。按照规定,先显示的内容在最底层显示,于是我们将Cube放在前面,Rectangle放在了后面。

    1. import QtQuick 2.2  
    2. import QtQuick.Window 2.2  
    3. import OpenGLCube 1.0  
    4.   
    5. Window  
    6. {  
    7.     id: root  
    8.     width: Qt.platform.os === "android"? Screen.width320  
    9.     height: Qt.platform.os === "android"? Screen.height480  
    10.     visible: true  
    11.   
    12.     Cube  
    13.     {  
    14.         id: cube  
    15.         anchors.fill: parent  
    16.         ParallelAnimation  
    17.         {  
    18.             running: true  
    19.             NumberAnimation  
    20.             {  
    21.                 target: cube  
    22.                 property: "rotateAngle"  
    23.                 from: 0  
    24.                 to: 360  
    25.                 duration: 5000  
    26.             }  
    27.   
    28.             Vector3dAnimation  
    29.             {  
    30.                 target: cube  
    31.                 property: "axis"  
    32.                 from: Qt.vector3d( 010 )  
    33.                 to: Qt.vector3d( 100 )  
    34.                 duration: 5000  
    35.             }  
    36.             loops: Animation.Infinite  
    37.         }  
    38.     }  
    39.   
    40.     Rectangle  
    41.     {  
    42.         anchors.centerIn: parent  
    43.         width: textField.width * 1.2  
    44.         height: textField.height * 1.5  
    45.         radius: textField.height / 3  
    46.         color"lightsteelblue"  
    47.         border.color"white"  
    48.         border.width2  
    49.         Text  
    50.         {  
    51.             id: textField  
    52.             anchors.centerIn: parent  
    53.             text: "您好世界!"  
    54.             font.pixelSize: root.width / 20  
    55.         }  
    56.     }  
    57. }  

    我们发现Cube类并不是Qt Quick自带的,而是我们自定义的一个QML模块OpenGLCube。按照第六篇文章上面的方法,我们通过在C++注册QML类实现了让QML访问C++代码。下面是主函数的实现:

    1. #include <QApplication>  
    2. #include <QQmlApplicationEngine>  
    3. #include "Cube.h"  
    4.   
    5. int main( int argc, char** argv )  
    6. {  
    7.     QApplication app( argc, argv );  
    8.   
    9.     qmlRegisterType<Cube>( "OpenGLCube", 1, 0, "Cube" );  
    10.   
    11.     QQmlApplicationEngine engine;  
    12.     engine.load( QUrl( QStringLiteral( "qrc:///main.qml" ) ) );  
    13.   
    14.     return app.exec( );  
    15. }  

             主函数中通过qmlRegisterType函数向QML环境注册了一个QML类。接下来就是Cube类的定义和实现了。

    Cube.h

    1. #ifndef CUBE_H  
    2. #define CUBE_H  
    3.   
    4. #include <QVector3D>  
    5. #include <QMatrix4x4>  
    6. #include <QOpenGLFunctions>  
    7. #include <QOpenGLBuffer>  
    8. #include <QOpenGLShaderProgram>  
    9. #include <QQuickItem>  
    10. #include <QQuickWindow>  
    11.   
    12. #define DECLRARE_Q_PROPERTY( aType, aProperty ) protected:\  
    13.     aType m_ ## aProperty; public:\  
    14.     aType aProperty( void ) { return m_ ## aProperty; } \  
    15.     void set ## aProperty( aType _ ## aProperty ) \  
    16.     {\  
    17.         m_ ## aProperty = _ ## aProperty;\  
    18.         if ( window( ) != Q_NULLPTR )\  
    19.         {\  
    20.             window( )->update( );\  
    21.         }\  
    22.     }  
    23.   
    24. class Cube: public QQuickItem  
    25. {  
    26.     Q_OBJECT  
    27.     Q_PROPERTY( qreal rotateAngle READ RotateAngle  
    28.                 WRITE setRotateAngle NOTIFY RotateAngleChanged )  
    29.     Q_PROPERTY( QVector3D axis READ Axis  
    30.                 WRITE setAxis NOTIFY AxisChanged )  
    31. public:  
    32.     explicit Cube( void );  
    33. signals:  
    34.     void RotateAngleChanged( void );  
    35.     void AxisChanged( void );  
    36. protected slots:  
    37.     void Render( void );  
    38.     void OnWindowChanged( QQuickWindow* pWindow );  
    39.     void Release( void );  
    40. protected:  
    41.     bool RunOnce( void );  
    42.   
    43.     QMatrix4x4                  m_ModelViewMatrix;  
    44.     QMatrix4x4                  m_ProjectionMatrix;  
    45.     QOpenGLBuffer               m_VertexBuffer, m_IndexBuffer;  
    46.     QOpenGLBuffer               m_ColorBuffer;  
    47.     QOpenGLShaderProgram        m_ShaderProgram;  
    48.   
    49.     DECLRARE_Q_PROPERTY( qreal, RotateAngle )  
    50.     DECLRARE_Q_PROPERTY( QVector3D, Axis )  
    51. };  
    52.   
    53. #endif // CUBE_H  

             在Cube.h中,我们让Cube继承QQuickItem。因为Cube也是一个Qt Quick的显示对象。这里顺便说一下,C++的QQuickItem对应QML的Item类,而C++的QObject则是对应QML的QtObject类。在C++中,QQuickItem继承于QObject,在QML中,Item继承QtObject。在类的定义中,我使用了QOpenGLBuffer来保持各种绘图缓存(缓冲区),使用QOpenGLShaderProgram来方便地载入着色器数据。最后我使用了一个方便的宏来定义受QML属性系统控制的成员变量。当这些变量发生变化的时候,让其通知父窗口(QQuickWindow)进行更新。

    Cube.cpp

    1. // Cube.cpp  
    2. #include "Cube.h"  
    3.   
    4. Cube::Cube( void ):  
    5.     m_VertexBuffer( QOpenGLBuffer::VertexBuffer ),  
    6.     m_IndexBuffer( QOpenGLBuffer::IndexBuffer ),  
    7.     m_ColorBuffer( QOpenGLBuffer::VertexBuffer ),  
    8.     m_RotateAngle( 0.0f ),  
    9.     m_Axis( 1.0f, 1.0f, 0.0f )  
    10. {     
    11.     // 初始化  
    12.     connect( this, SIGNAL( windowChanged( QQuickWindow* ) ),  
    13.              this, SLOT( OnWindowChanged( QQuickWindow* ) ) );  
    14. }  
    15.   
    16. void Cube::OnWindowChanged( QQuickWindow* pWindow )  
    17. {  
    18.     if ( pWindow == Q_NULLPTR ) return;  
    19.     connect( pWindow, SIGNAL( beforeRendering( ) ),  
    20.              this, SLOT( Render( ) ), Qt::DirectConnection );  
    21.     pWindow->setClearBeforeRendering( false );  
    22. }  
    23.   
    24. void Cube::Render( void )  
    25. {  
    26.     static bool runOnce = RunOnce( );  
    27.     Q_UNUSED( runOnce );  
    28.   
    29.     // 运动  
    30.     m_ModelViewMatrix.setToIdentity( );  
    31.     m_ModelViewMatrix.translate( 0.0f, 0.0f, -60.0f );  
    32.     m_ModelViewMatrix.rotate( m_RotateAngle, m_Axis.x( ),  
    33.                               m_Axis.y( ), m_Axis.z( ) );  
    34.   
    35.     // 渲染  
    36.     glViewport( 0, 0, window( )->width( ), window( )->height( ) );  
    37.     glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );  
    38.     glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );  
    39.     glEnable( GL_DEPTH_TEST );  
    40.     glEnable( GL_CULL_FACE );  
    41.     glFrontFace( GL_CW );  
    42.   
    43.     m_ShaderProgram.bind( );  
    44.     m_VertexBuffer.bind( );  
    45.     int posLoc = m_ShaderProgram.attributeLocation( "position" );  
    46.     m_ShaderProgram.enableAttributeArray( posLoc );  
    47.     m_ShaderProgram.setAttributeBuffer( posLoc,                 // 位置  
    48.                                         GL_FLOAT,               // 类型  
    49.                                         0,                      // 偏移  
    50.                                         3,                      // 元大小  
    51.                                         0 );                    // 迈  
    52.   
    53.     m_ColorBuffer.bind( );  
    54.     int colorLoc = m_ShaderProgram.attributeLocation( "color" );  
    55.     m_ShaderProgram.enableAttributeArray( colorLoc );  
    56.     m_ShaderProgram.setAttributeBuffer( colorLoc,               // 位置  
    57.                                         GL_FLOAT,               // 类型  
    58.                                         0,                      // 偏移  
    59.                                         4,                      // 元大小  
    60.                                         0 );                    // 迈  
    61.     m_IndexBuffer.bind( );  
    62.     m_ShaderProgram.setUniformValue( "modelViewMatrix", m_ModelViewMatrix );  
    63.     m_ShaderProgram.setUniformValue( "projectionMatrix", m_ProjectionMatrix );  
    64.     glDrawElements( GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, Q_NULLPTR );  
    65.   
    66.     m_ShaderProgram.disableAttributeArray( posLoc );  
    67.     m_ShaderProgram.disableAttributeArray( colorLoc );  
    68.     m_IndexBuffer.release( );  
    69.     m_VertexBuffer.release( );  
    70.     m_ShaderProgram.release( );  
    71. }  
    72.   
    73. bool Cube::RunOnce( void )  
    74. {  
    75.     // 初始化着色器  
    76.     m_ShaderProgram.addShaderFromSourceFile( QOpenGLShader::Vertex,  
    77.                                              ":/shader/Shader.vsh" );  
    78.     m_ShaderProgram.addShaderFromSourceFile( QOpenGLShader::Fragment,  
    79.                                              ":/shader/Shader.fsh" );  
    80.     m_ShaderProgram.link( );  
    81.   
    82.     // 初始化顶点缓存  
    83.     const GLfloat length = 10.0f;  
    84.     const GLfloat vertices[] =  
    85.     {  
    86.         length, -length, length,  
    87.         length, -length, -length,  
    88.         -length, -length, -length,  
    89.         -length, -length, length,  
    90.         length, length, length,  
    91.         length, length, -length,  
    92.         -length, length, -length,  
    93.         -length, length, length  
    94.     };  
    95.   
    96.     m_VertexBuffer.setUsagePattern( QOpenGLBuffer::StaticDraw );  
    97.     m_VertexBuffer.create( );  
    98.     m_VertexBuffer.bind( );  
    99.     m_VertexBuffer.allocate( vertices, sizeof( vertices ) );  
    100.   
    101.     // 初始化颜色的缓存  
    102.     const GLfloat colors[] =  
    103.     {  
    104.         1.0f, 0.0f, 1.0f, 1.0f,  
    105.         1.0f, 0.0f, 0.0f, 1.0f,  
    106.         0.0f, 0.0f, 0.0f, 1.0f,  
    107.         0.0f, 0.0f, 1.0f, 1.0f,  
    108.         1.0f, 1.0f, 1.0f, 1.0f,  
    109.         1.0f, 1.0f, 0.0f, 1.0f,  
    110.         0.0f, 1.0f, 0.0f, 1.0f,  
    111.         0.0f, 1.0f, 1.0f, 1.0f  
    112.     };  
    113.     m_ColorBuffer.setUsagePattern( QOpenGLBuffer::StaticDraw );  
    114.     m_ColorBuffer.create( );  
    115.     m_ColorBuffer.bind( );  
    116.     m_ColorBuffer.allocate( colors, sizeof( colors ) );  
    117.   
    118.   
    119.     // 初始化索引缓存  
    120.     GLubyte indices[] =  
    121.     {  
    122.         0, 1, 2, 0, 2, 3,// 下面  
    123.         7, 6, 4, 6, 5, 4,// 上面  
    124.         7, 4, 3, 4, 0, 3,// 左面  
    125.         5, 6, 1, 6, 2, 1,// 右面  
    126.         4, 5, 0, 5, 1, 0,// 前面  
    127.         3, 2, 6, 3, 6, 7,// 背面  
    128.     };  
    129.   
    130.     m_IndexBuffer.setUsagePattern( QOpenGLBuffer::StaticDraw );  
    131.     m_IndexBuffer.create( );  
    132.     m_IndexBuffer.bind( );  
    133.     m_IndexBuffer.allocate( indices, sizeof( indices ) );  
    134.   
    135.     // 设定模型矩阵和投影矩阵  
    136.     float aspectRatio  = float( window( )->width( ) ) / float( window( )->height( ) );  
    137.     m_ProjectionMatrix.perspective( 45.0f,  
    138.                                     aspectRatio,  
    139.                                     0.5f,  
    140.                                     500.0f );  
    141.   
    142.     connect( window( )->openglContext( ),  
    143.              SIGNAL( aboutToBeDestroyed( ) ),  
    144.              this, SLOT( Release( ) ),  
    145.              Qt::DirectConnection );  
    146.   
    147.     return true;  
    148. }  
    149.   
    150. void Cube::Release( void )  
    151. {  
    152.     qDebug( "Vertex buffer and index buffer are to be destroyed." );  
    153.     m_VertexBuffer.destroy( );  
    154.     m_IndexBuffer.destroy( );  
    155.     m_ColorBuffer.destroy( );  
    156. }  

             类的实现较复杂。大致分为构造阶段、初始化阶段、渲染阶段和释放空间阶段。这里我们使用了OpenGL ES 2.0常用的buffer + attribute array方式来进行高效渲染。有关上述OpenGL的知识,感兴趣的同行们可以看看《OpenGL ES 2.0 Programming Guide》、Qt书籍有关OpenGL的部分、KDAB博客中有关OpenGL的知识以及我的其它博客以获得相关知识。

             上述程序载入了顶点着色器和片断着色器。它们如下所示:

    1. // Shader.vsh  
    2. attribute highp vec3 position;  
    3. attribute highp vec4 color;  
    4.   
    5. uniform mat4 modelViewMatrix;  
    6. uniform mat4 projectionMatrix;  
    7.   
    8. varying highp vec4 v_Color;  
    9.   
    10. void main( void )  
    11. {  
    12.     gl_Position = projectionMatrix *  
    13.             modelViewMatrix *  
    14.             vec4( position, 1.0 );  
    15.     v_Color = color;  
    16. }  

    
    
    1. // Shader.fsh  
    2. varying highp vec4 v_Color;  
    3.   
    4. void main( void )  
    5. {  
    6.     gl_FragColor = v_Color;  
    7. }  

             本例在三大桌面平台上运行正常,同时在Android平台上也能够顺利地运行。

    展开全文
  • Qt移动应用开发(八):实现跨平台的QML和OpenGL混合渲染 上一篇文章讲到了利用C++这个桥梁,我们实现了QML和Java的交互。Qt 5大力推崇的QML/JS开发,让轻量、高速开发...实现了使用着色器定义OpenGL的渲染方式...

    Qt移动应用开发(八):实现跨平台的QML和OpenGL混合渲染

     

             上一篇文章讲到了利用C++这个桥梁,我们实现了QML和Java的交互。Qt 5大力推崇的QML/JS开发,让轻量、高速开发的QML/JS打头阵,让重量的C++撑腰,差点儿什么技术都可以实现。接下来的这篇文章讲的是我们使用QML。借助Qt库和OpenGL。实现了使用着色器定义OpenGL的渲染方式,为大家呈现混合渲染的效果。

    原创文章,反对未声明的引用。

    原博客地址:http://blog.csdn.net/gamesdev/article/details/38024327

             本文难度偏大。适合有经验的Qt开发同行学习交流。

             演示程序下载地址:这里

             源码下载地址:这里

             演示程序的截图例如以下(Android):

             首先我们来看简单的QML代码。本例非常easy。仅仅有一个界面。没有不论什么界面的跳转。我们在前面显示一个矩形,上面写了”您好世界!

    ”的文字。后面显示的是一个旋转的矩形。依照规定。先显示的内容在最底层显示。于是我们将Cube放在前面,Rectangle放在了后面。

    import QtQuick 2.2
    import QtQuick.Window 2.2
    import OpenGLCube 1.0
    
    Window
    {
        id: root
        width: Qt.platform.os === "android"? Screen.width: 320
        height: Qt.platform.os === "android"? Screen.height: 480
        visible: true
    
        Cube
        {
            id: cube
            anchors.fill: parent
            ParallelAnimation
            {
                running: true
                NumberAnimation
                {
                    target: cube
                    property: "rotateAngle"
                    from: 0
                    to: 360
                    duration: 5000
                }
    
                Vector3dAnimation
                {
                    target: cube
                    property: "axis"
                    from: Qt.vector3d( 0, 1, 0 )
                    to: Qt.vector3d( 1, 0, 0 )
                    duration: 5000
                }
                loops: Animation.Infinite
            }
        }
    
        Rectangle
        {
            anchors.centerIn: parent
            width: textField.width * 1.2
            height: textField.height * 1.5
            radius: textField.height / 3
            color: "lightsteelblue"
            border.color: "white"
            border.width: 2
            Text
            {
                id: textField
                anchors.centerIn: parent
                text: "您好世界!"
                font.pixelSize: root.width / 20
            }
        }
    }

    我们发现Cube类并非Qt Quick自带的,而是我们自己定义的一个QML模块OpenGLCube。

    依照第六篇文章上面的方法,我们通过在C++注冊QML类实现了让QML訪问C++代码。以下是主函数的实现:

    #include <QApplication>
    #include <QQmlApplicationEngine>
    #include "Cube.h"
    
    int main( int argc, char** argv )
    {
        QApplication app( argc, argv );
    
        qmlRegisterType<Cube>( "OpenGLCube", 1, 0, "Cube" );
    
        QQmlApplicationEngine engine;
        engine.load( QUrl( QStringLiteral( "qrc:///main.qml" ) ) );
    
        return app.exec( );
    }

             主函数中通过qmlRegisterType函数向QML环境注冊了一个QML类。接下来就是Cube类的定义和实现了。

    Cube.h

    #ifndef CUBE_H
    #define CUBE_H
    
    #include <QVector3D>
    #include <QMatrix4x4>
    #include <QOpenGLFunctions>
    #include <QOpenGLBuffer>
    #include <QOpenGLShaderProgram>
    #include <QQuickItem>
    #include <QQuickWindow>
    
    #define DECLRARE_Q_PROPERTY( aType, aProperty ) protected:\
        aType m_ ## aProperty; public:\
        aType aProperty( void ) { return m_ ## aProperty; } \
        void set ## aProperty( aType _ ## aProperty ) \
        {\
            m_ ## aProperty = _ ## aProperty;\
            if ( window( ) != Q_NULLPTR )\
            {\
                window( )->update( );\
            }\
        }
    
    class Cube: public QQuickItem
    {
        Q_OBJECT
        Q_PROPERTY( qreal rotateAngle READ RotateAngle
                    WRITE setRotateAngle NOTIFY RotateAngleChanged )
        Q_PROPERTY( QVector3D axis READ Axis
                    WRITE setAxis NOTIFY AxisChanged )
    public:
        explicit Cube( void );
    signals:
        void RotateAngleChanged( void );
        void AxisChanged( void );
    protected slots:
        void Render( void );
        void OnWindowChanged( QQuickWindow* pWindow );
        void Release( void );
    protected:
        bool RunOnce( void );
    
        QMatrix4x4                  m_ModelViewMatrix;
        QMatrix4x4                  m_ProjectionMatrix;
        QOpenGLBuffer               m_VertexBuffer, m_IndexBuffer;
        QOpenGLBuffer               m_ColorBuffer;
        QOpenGLShaderProgram        m_ShaderProgram;
    
        DECLRARE_Q_PROPERTY( qreal, RotateAngle )
        DECLRARE_Q_PROPERTY( QVector3D, Axis )
    };
    
    #endif // CUBE_H

             在Cube.h中,我们让Cube继承QQuickItem。由于Cube也是一个Qt Quick的显示对象。这里顺便说一下,C++的QQuickItem相应QML的Item类。而C++的QObject则是相应QML的QtObject类。在C++中,QQuickItem继承于QObject,在QML中。Item继承QtObject。在类的定义中。我使用了QOpenGLBuffer来保持各种画图缓存(缓冲区),使用QOpenGLShaderProgram来方便地加载着色器数据。最后我使用了一个方便的宏来定义受QML属性系统控制的成员变量。当这些变量发生变化的时候,让其通知父窗体(QQuickWindow)进行更新。

    Cube.cpp

    // Cube.cpp
    #include "Cube.h"
    
    Cube::Cube( void ):
        m_VertexBuffer( QOpenGLBuffer::VertexBuffer ),
        m_IndexBuffer( QOpenGLBuffer::IndexBuffer ),
        m_ColorBuffer( QOpenGLBuffer::VertexBuffer ),
        m_RotateAngle( 0.0f ),
        m_Axis( 1.0f, 1.0f, 0.0f )
    {   
        // 初始化
        connect( this, SIGNAL( windowChanged( QQuickWindow* ) ),
                 this, SLOT( OnWindowChanged( QQuickWindow* ) ) );
    }
    
    void Cube::OnWindowChanged( QQuickWindow* pWindow )
    {
        if ( pWindow == Q_NULLPTR ) return;
        connect( pWindow, SIGNAL( beforeRendering( ) ),
                 this, SLOT( Render( ) ), Qt::DirectConnection );
        pWindow->setClearBeforeRendering( false );
    }
    
    void Cube::Render( void )
    {
        static bool runOnce = RunOnce( );
        Q_UNUSED( runOnce );
    
        // 运动
        m_ModelViewMatrix.setToIdentity( );
        m_ModelViewMatrix.translate( 0.0f, 0.0f, -60.0f );
        m_ModelViewMatrix.rotate( m_RotateAngle, m_Axis.x( ),
                                  m_Axis.y( ), m_Axis.z( ) );
    
        // 渲染
        glViewport( 0, 0, window( )->width( ), window( )->height( ) );
        glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
        glEnable( GL_DEPTH_TEST );
        glEnable( GL_CULL_FACE );
        glFrontFace( GL_CW );
    
        m_ShaderProgram.bind( );
        m_VertexBuffer.bind( );
        int posLoc = m_ShaderProgram.attributeLocation( "position" );
        m_ShaderProgram.enableAttributeArray( posLoc );
        m_ShaderProgram.setAttributeBuffer( posLoc,                 // 位置
                                            GL_FLOAT,               // 类型
                                            0,                      // 偏移
                                            3,                      // 元大小
                                            0 );                    // 迈
    
        m_ColorBuffer.bind( );
        int colorLoc = m_ShaderProgram.attributeLocation( "color" );
        m_ShaderProgram.enableAttributeArray( colorLoc );
        m_ShaderProgram.setAttributeBuffer( colorLoc,               // 位置
                                            GL_FLOAT,               // 类型
                                            0,                      // 偏移
                                            4,                      // 元大小
                                            0 );                    // 迈
        m_IndexBuffer.bind( );
        m_ShaderProgram.setUniformValue( "modelViewMatrix", m_ModelViewMatrix );
        m_ShaderProgram.setUniformValue( "projectionMatrix", m_ProjectionMatrix );
        glDrawElements( GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, Q_NULLPTR );
    
        m_ShaderProgram.disableAttributeArray( posLoc );
        m_ShaderProgram.disableAttributeArray( colorLoc );
        m_IndexBuffer.release( );
        m_VertexBuffer.release( );
        m_ShaderProgram.release( );
    }
    
    bool Cube::RunOnce( void )
    {
        // 初始化着色器
        m_ShaderProgram.addShaderFromSourceFile( QOpenGLShader::Vertex,
                                                 ":/shader/Shader.vsh" );
        m_ShaderProgram.addShaderFromSourceFile( QOpenGLShader::Fragment,
                                                 ":/shader/Shader.fsh" );
        m_ShaderProgram.link( );
    
        // 初始化顶点缓存
        const GLfloat length = 10.0f;
        const GLfloat vertices[] =
        {
            length, -length, length,
            length, -length, -length,
            -length, -length, -length,
            -length, -length, length,
            length, length, length,
            length, length, -length,
            -length, length, -length,
            -length, length, length
        };
    
        m_VertexBuffer.setUsagePattern( QOpenGLBuffer::StaticDraw );
        m_VertexBuffer.create( );
        m_VertexBuffer.bind( );
        m_VertexBuffer.allocate( vertices, sizeof( vertices ) );
    
        // 初始化颜色的缓存
        const GLfloat colors[] =
        {
            1.0f, 0.0f, 1.0f, 1.0f,
            1.0f, 0.0f, 0.0f, 1.0f,
            0.0f, 0.0f, 0.0f, 1.0f,
            0.0f, 0.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 0.0f, 1.0f,
            0.0f, 1.0f, 0.0f, 1.0f,
            0.0f, 1.0f, 1.0f, 1.0f
        };
        m_ColorBuffer.setUsagePattern( QOpenGLBuffer::StaticDraw );
        m_ColorBuffer.create( );
        m_ColorBuffer.bind( );
        m_ColorBuffer.allocate( colors, sizeof( colors ) );
    
    
        // 初始化索引缓存
        GLubyte indices[] =
        {
            0, 1, 2, 0, 2, 3,// 以下
            7, 6, 4, 6, 5, 4,// 上面
            7, 4, 3, 4, 0, 3,// 左面
            5, 6, 1, 6, 2, 1,// 右面
            4, 5, 0, 5, 1, 0,// 前面
            3, 2, 6, 3, 6, 7,// 背面
        };
    
        m_IndexBuffer.setUsagePattern( QOpenGLBuffer::StaticDraw );
        m_IndexBuffer.create( );
        m_IndexBuffer.bind( );
        m_IndexBuffer.allocate( indices, sizeof( indices ) );
    
        // 设定模型矩阵和投影矩阵
        float aspectRatio  = float( window( )->width( ) ) / float( window( )->height( ) );
        m_ProjectionMatrix.perspective( 45.0f,
                                        aspectRatio,
                                        0.5f,
                                        500.0f );
    
        connect( window( )->openglContext( ),
                 SIGNAL( aboutToBeDestroyed( ) ),
                 this, SLOT( Release( ) ),
                 Qt::DirectConnection );
    
        return true;
    }
    
    void Cube::Release( void )
    {
        qDebug( "Vertex buffer and index buffer are to be destroyed." );
        m_VertexBuffer.destroy( );
        m_IndexBuffer.destroy( );
        m_ColorBuffer.destroy( );
    }

             类的实现较复杂。大致分为构造阶段、初始化阶段、渲染阶段和释放空间阶段。

    这里我们使用了OpenGL ES 2.0经常使用的buffer + attribute array方式来进行高效渲染。

    有关上述OpenGL的知识,感兴趣的同行们能够看看《OpenGL ES 2.0 Programming Guide》、Qt书籍有关OpenGL的部分、KDAB博客中有关OpenGL的知识以及我的其他博客以获得相关知识。

             上述程序加载了顶点着色器和片断着色器。它们例如以下所看到的:

    // Shader.vsh
    attribute highp vec3 position;
    attribute highp vec4 color;
    
    uniform mat4 modelViewMatrix;
    uniform mat4 projectionMatrix;
    
    varying highp vec4 v_Color;
    
    void main( void )
    {
        gl_Position = projectionMatrix *
                modelViewMatrix *
                vec4( position, 1.0 );
        v_Color = color;
    }

    
    
    // Shader.fsh
    varying highp vec4 v_Color;
    
    void main( void )
    {
        gl_FragColor = v_Color;
    }

             本例在三大桌面平台上执行正常,同一时候在Android平台上也可以顺利地执行。


    转载于:https://www.cnblogs.com/mfrbuaa/p/5386780.html

    展开全文
  • 前面采用了离屏渲染,多线程的方式实现了nv12视频的播放,这次采用在QSG中渲染方式实现,也就是在渲染线程中。原理同样是将图像纹理到一个FBO中,然后通过qt的接口带到QSG中进行显示。 采用opengl渲染并用qml显示...

        前面采用了离屏渲染,多线程的方式实现了nv12视频的播放,这次采用在QSG中渲染的方式实现,也就是在渲染线程中。

    原理同样是将图像纹理到一个FBO中,然后通过qt的接口带到QSG中进行显示。

        采用opengl渲染并用qml显示的接口类为QQuickFramebufferObject,渲染线程会在刷新画面的时候调用其createRenderer()方法用于创建渲染,这里我留了一个设置视频地址的接口,因为是显示视频嘛。

    #ifndef VideoRende_H
    #define VideoRende_H
    #include <QQuickFramebufferObject>
    
    QT_FORWARD_DECLARE_CLASS(QTimer)
    QT_FORWARD_DECLARE_CLASS(DecodeThread)
    class VideoRender : public QQuickFramebufferObject
    {
        Q_OBJECT
        Q_PROPERTY(QString videoSource READ videoSource WRITE setVideoSource NOTIFY videoSourceChanged) //增加一个设置视频地址的属性
    public:
        explicit VideoRender(QQuickItem* parent = nullptr);
        ~VideoRender();
        Renderer* createRenderer() const override; //重写
        void getFrame(uchar **nv12Ptr,int *w, int *h); //用于在创建的Renderer中访问当前帧的图像数据
    
    signals:
        void videoSourceChanged();
    
    private:
        QTimer *m_timer{nullptr};
        QString m_videoSource;
    
        QString videoSource();
        void setVideoSource(QString);
        DecodeThread *m_decodeThr{nullptr};
    };
    
    #endif // VideoRende_H

    基实现如下

    #include "VideoRender.h"
    #include "nv12render.h"
    #include "NvDecode/decodethread.h"
    #include "logorenderer.h"
    #include <QOpenGLFramebufferObjectFormat>
    #include <QTimer>
    #include <QDebug>
    
    class VideoFboRender : public QQuickFramebufferObject::Renderer //自定义一个FBO的渲染
    {
    public:
        VideoFboRender(){
        }
    
        ~VideoFboRender(){
        }
    
        //该函数主要从VideoRender中获取数据,用于在render()函数中的渲染;会先调用此函数再调用render
        void synchronize(QQuickFramebufferObject*item){
            dynamic_cast<VideoRender*>(item)->getFrame(&nv12Ptr,&videoW,&videoH);
                               //此处的item是创建Nv12FboRender的QQuickFramebufferObject对象,在这里可以从QQuickFramebufferObject中获取数据保留下来,用于render中的渲染
    //        item->update(); //GUI线程中刷新,GUI阻塞,会影响画面,应该在QQuickFramebufferObject中用闹钟的方式刷新,避免阻塞,
                            //阻塞GUI线程和渲染线程都不好
        }
    
        void render()override{
            m_nv12Render.render(nv12Ptr,videoW,videoH); //渲染当前帧
    //        update(); //不是在GUI线程中刷新,GUI线程中的阻塞,不会影响画面;
        }
    
        QOpenGLFramebufferObject *createFramebufferObject(const QSize &size){
            QOpenGLFramebufferObjectFormat format;   //当大小发生变化时,会调用此函数生成对应大小的FBO
            format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
            format.setSamples(4);
            return new QOpenGLFramebufferObject(size,format);
        }
    
    private:
        Nv12Render m_nv12Render;
        uchar *nv12Ptr{nullptr};
        int videoW,videoH;
    };
    
    VideoRender::VideoRender(QQuickItem *parent):
        QQuickFramebufferObject(parent)
    {
        m_timer = new QTimer(this);
        m_timer->setInterval(30); //每过30ms刷新一次
        connect(m_timer,SIGNAL(timeout()),this,SLOT(update()));
    
        m_decodeThr = new DecodeThread;
    }
    
    VideoRender::~VideoRender()
    {
        m_decodeThr->requestInterruption();
        m_decodeThr->quit();
        m_decodeThr->wait();
        m_decodeThr->deleteLater();
    }
    
    QQuickFramebufferObject::Renderer *VideoRender::createRenderer() const
    {
        return new VideoFboRender; //返回我们自定义的Renderer。
    }
    
    void VideoRender::getFrame(uchar **nv12Ptr, int *w, int *h) //返回当前帧数据
    {
        *nv12Ptr = m_decodeThr->imgPtr;
        *w = m_decodeThr->videoW;
        *h = m_decodeThr->videoH;
    }
    
    QString VideoRender::videoSource()
    {
        return m_videoSource;
    }
    
    void VideoRender::setVideoSource(QString url)
    {
        if(m_videoSource != url){
            m_decodeThr->setUrl(url);
            m_decodeThr->setTimeInterval(m_timer->interval());
            m_decodeThr->start();
            m_timer->start();
            emit videoSourceChanged();
        }
    
        m_videoSource = url;
    }

    主要的结构就是这样了,接下来要说的是nv12的渲染了,这里和前面的nv12渲染有些不同,有几个坑。代码如下

    #ifndef NV12RENDER_H
    #define NV12RENDER_H
    #include <QOpenGLFunctions>
    #include <QOpenGLShaderProgram>
    
    #include <QtGui/qvector3d.h>
    #include <QtGui/qmatrix4x4.h>
    #include <QtGui/qopenglshaderprogram.h>
    #include <QtGui/qopenglfunctions.h>
    #include <QOpenGLBuffer>
    
    #include <QTime>
    #include <QVector>
    
    class Nv12Render : public QOpenGLFunctions
    {
    public:
        Nv12Render();
        void render(uchar*nv12Ptr, int w, int h); //渲染当前帧
    
    private:
        QOpenGLShaderProgram program;
        GLuint idY,idUV; //Y分量和UV分量的纹理id
        QOpenGLBuffer vbo; //用于在opengl服务端创建数据
        qreal   m_fAngle;
        qreal   m_fScale;
    };
    
    #endif // NV12RENDER_H

    以下是其实现

    #include "nv12render.h"
    #include <QPainter>
    #include <QPaintEngine>
    #include <QOpenGLTexture>
    #include <math.h>
    
    Nv12Render::Nv12Render()
    {
        initializeOpenGLFunctions();
        const char *vsrc =
                "attribute vec4 vertexIn; \
                 attribute vec4 textureIn; \
                 varying vec4 textureOut;  \
                 uniform mediump mat4 matrix;\
                 void main(void)           \
                 {                         \
                     gl_Position = vertexIn * matrix; \
                     textureOut = textureIn; \
                 }";
    
        const char *fsrc =
                "varying mediump vec4 textureOut;\n"
                "uniform sampler2D textureY;\n"
                "uniform sampler2D textureUV;\n"
                "void main(void)\n"
                "{\n"
                "vec3 yuv; \n"
                "vec3 rgb; \n"
                "yuv.x = texture2D(textureY, textureOut.st).r - 0.0625; \n"
                "yuv.y = texture2D(textureUV, textureOut.st).r - 0.5; \n"
                "yuv.z = texture2D(textureUV, textureOut.st).g - 0.5; \n"
                "rgb = mat3( 1,       1,         1, \n"
                            "0,       -0.39465,  2.03211, \n"
                            "1.13983, -0.58060,  0) * yuv; \n"
                "gl_FragColor = vec4(rgb, 1); \n"
                "}\n";
    
        program.addCacheableShaderFromSourceCode(QOpenGLShader::Vertex,vsrc);
        program.addCacheableShaderFromSourceCode(QOpenGLShader::Fragment,fsrc);
        program.link();
    
        GLfloat points[]{
            -0.8f, 0.8f,
             0.8f, 0.8f,
             0.8f, -0.8f,
            -0.8f, -0.8f,
    
            0.0f,1.0f,
            1.0f,1.0f,
            1.0f,0.0f,
            0.0f,0.0f,
        };
    
        vbo.create();
        vbo.bind();
        vbo.allocate(points,sizeof(points));
        //不能在这里直接将program绑定,以及vbo等等,感觉这里的program整个渲染的一部分,还有其它的program,必须在render()函数中进行数据的绑定和纹理的生成
        GLuint ids[2];
        glGenTextures(2,ids);
        idY = ids[0];
        idUV = ids[1];
        m_fAngle = 0.0;
        m_fScale = 1.0;
    }
    
    void Nv12Render::render(uchar *nv12Ptr, int w, int h)
    {
        glClearColor(0.5f, 0.5f, 0.7f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glDisable(GL_DEPTH_TEST);
    
        program.bind(); //使用opengl切换为当前的program以使用shader
        QMatrix4x4 modelview;
        modelview.rotate(m_fAngle, 0.0f, 1.0f, 0.0f);
        modelview.rotate(m_fAngle, 1.0f, 0.0f, 0.0f);
        modelview.rotate(m_fAngle, 0.0f, 0.0f, 1.0f);
        modelview.scale(m_fScale);
        modelview.translate(0.0f, -0.2f, 0.0f);
        program.setUniformValue("matrix", modelview);
    
        vbo.bind(); //切换并使用创建好的顶点和纹理坐标数据
        program.enableAttributeArray("vertexIn");
        program.enableAttributeArray("textureIn");
        program.setAttributeBuffer("vertexIn",GL_FLOAT, 0, 2, 2*sizeof(GLfloat));
        program.setAttributeBuffer("textureIn",GL_FLOAT,2 * 4 * sizeof(GLfloat),2,2*sizeof(GLfloat));
    
        glActiveTexture(GL_TEXTURE0 + 1); //这里我试了有个奇葩的现象,必须先选择1号纹理用来渲染Y分量数据,然后必须使用0号纹理来渲染UV分量的数据,原因我暂时也还没搞清楚
        glBindTexture(GL_TEXTURE_2D,idY); //这真是一个大坑,我整了很久
        glTexImage2D(GL_TEXTURE_2D,0,GL_RED,w,h,0,GL_RED,GL_UNSIGNED_BYTE,nv12Ptr);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    
        glActiveTexture(GL_TEXTURE0 + 0); //使用0号纹理填充UV分量的数据
        glBindTexture(GL_TEXTURE_2D,idUV);
        glTexImage2D(GL_TEXTURE_2D,0,GL_RG,w >> 1,h >> 1,0,GL_RG,GL_UNSIGNED_BYTE,nv12Ptr + w*h);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    
        program.setUniformValue("textureUV",0);
        program.setUniformValue("textureY",1);
        glDrawArrays(GL_QUADS,0,4);
        program.disableAttributeArray("vertexIn");
        program.disableAttributeArray("textureIn");
        program.release(); //去掉program的绑定
    
        m_fAngle += 1.0f;
    }

    以下为qml中的调用

    import QtQuick 2.7
    import QtQuick.Controls 2.0
    import QtQuick.Layouts 1.3
    import QtMultimedia 5.9
    import SceneGraphRendering 1.0
    
    ApplicationWindow {
        visible: true
        width: 640
        height: 480
        title: qsTr("Hello World")
    
        Item{
            id: root
            anchors.fill: parent
            RenderItem{
                anchors.fill: parent
                videoSource: "D:/迅雷下载/香肠派对720p.mp4"
                Text {
                    id: name2
                    anchors.centerIn: parent
                    font.pixelSize: 18
                    color: "green"
                    text: qsTr("texfffffffffffffffsft")
                }
            }
    
            MouseArea{
                anchors.fill: parent
                onClicked: {
                    parent.grabToImage(function(result){
                        console.log(result.image)
    //                    result.saveToFile("C:\\Users\\Administrator\\Desktop\\1.jpg")
                    })
                    ani.start()
                }
            }
    
            Rectangle{
                id: rect
                width: parent.width * 0.7
                height: parent.height * 0.7
                anchors.centerIn: parent
                opacity: 0.5
                SequentialAnimation{
                    id: ani
                    ParallelAnimation{
                        NumberAnimation{
                            target: rect
                            properties: "width"
                            to: rect.width ? 0 : root.width * 0.7
                            duration: 800
                        }
                        NumberAnimation{
                            target: rect
                            properties: "height"
                            to: rect.height ? 0 : root.height * 0.7
                            duration: 800
                        }
                    }
                    ParallelAnimation{
                        NumberAnimation{
                            target: rect
                            properties: "width"
                            to: rect.width ? 0 : root.width * 0.7
                            duration: 800
                        }
                        NumberAnimation{
                            target: rect
                            properties: "height"
                            to: rect.height ? 0 : root.height * 0.7
                            duration: 800
                        }
                    }
                }
            }
        }
    }

    我自己定义了一个动画用于检测当抓图是画面是否会卡,实时证明,抓图是不会卡的,但是如果把抓出来的图片储到文件里面就会卡。




    展开全文
  • 一直在研究 qt 绘制 3D ,觉得 qml 调用 three.js 算是比较方便的,而且网上有很多 three.js 的例子,但是 web 端使用的方式qml 的调用还是有一定的区别的, qml 使用的 three.js 是阉割版的,这个爬了不少的坑,以下...
  • Qml模式视图

    2021-03-09 17:48:43
    一个描述model中每条数据的显示方式的控件(渲染数据方式) View 可视的元素,使用delegate来显示model中的数据 例子 列表 这里将model单独写在MyModel.qml文件中 import QtQuick 2.0 ListModel { id: ...
  • QML_TCP.rar

    2019-08-12 15:13:04
    此资源使用的是qt5.12 ,可直接打开,工程就是使用tcp拉取视频流,使用ffmpeg解码,然后传到qml(自定义)中去渲染 由于基本不写博客,一些注意说明就在这里写了: 1、资源肯定能用,我自己做了3天出来的,但是一...
  • 生态的缺失,支持的不利,基本上看不到移动端有人用这套东西来开发应用,但是这套技术本身是不错的,快速的开发效率,gpu式的渲染方式,在取代传统QWidget 开发桌面应用方面,还是值得学习的。现结合多年使用经验,...
  • QtQuick开发的程序,在虚拟机或者某些环境下,...为什么这么说呢,Qt在某些环境里,比如说虚拟机里,会将渲染方式,从单线程改成多线程渲染。这原本只是想提升一下渲染性能的,但是实际上,尤其是桌面环境,渲染性能
  • QtQuick中集成OSG渲染

    千次阅读 2020-03-10 15:48:55
    从目前网上介绍OSG与Qml集成有两种方式: 在[QtQuick2OSGItem](https://bitbucket.org/leon_manukyan/qtquick2osgitem/src/master/sampleapp/)通过继承抽象类__QQuickFramebufferObject::Renderer__来重写渲染接口...
  • ffmpeg 4.0 解码,Qml/OpenGL转码yuv到RGB并渲染 仓库及镜像 徽章 效果图 说明 Qt版本5.9以上 FFmpeg 版本为4.2.2,已经在qmake中适配msvc x86、msvc x64、macos 64平台。 如果使用其它编译器或者其它平台,请自行...
  • QT基本使用说明

    2017-03-13 10:36:00
    7、QT的渲染方式及控件的绘制方式 8、分析第一个QT程序代码 9、QT窗口之QMainWindow、QDialog和QWidget 10、QT信号和槽 11、QT自定义信号和槽 12、QT moc和元对象系统 13、QT按钮控件 ...
  • qt快速入门简介

    2017-03-28 11:22:39
    内容1来源:http://c.biancheng.net/cpp/qt/文章列表:Qt简介Qt的下载和安装使用C++来创建界面使用Qt Designer使用QML来创建界面使用C++还是QMLQt的渲染机制以及控件绘制方式分析第一个Qt程序代码Qt窗口之...
  • Qt Quick和QML为开发人员提供了多种方式来为用户界面添加视觉效果。Qt Quick Shapes允许您创建各种形状并填充图案。QML有大量的动画类型,这使得使用甚至非线性时间轴来设置任何对象的动画都很容易。OpenGL程序可以...
  • Optimizing Graphical Performance Qt图形界面架构和历史 Qt Widget ...Qt4 中 QML是在QGraphicalView上画的,但是Qt5之后这种方式被抛弃了 QOpenGLWidget 这个类用来渲染OpenGL的 class TestOpenGLWidge
  • 之前一直以为 Qt Quick 里 Canvas 才可以自绘,后来发觉不是,原来还有好几种方式都可以绘图!可以使用原始的 OpenGL(Qt Quick 使用 OpenGL 渲染),可以构造QSGNode 来绘图,还可以使用 QPainter !哇, QPainter ...
  • Qt 3D的研究(五):Gooch Shader

    千次阅读 2015-03-01 22:58:45
    Qt 3D的一个很大的优势就是采用数据驱动的方式,将C++和GLSL使用QML来表示,动态语言的优势尽显。在上一次的研究中,我实现了一个非常简单的着色器,接下来,我们可以在此基础上,通过设定着色器的数据,制作出更加...
  • Qt MinGW版编译使用protobuf

    千次阅读 2017-07-13 13:21:33
    Qt是非常优秀的跨平台UI框架,特别是其Qt Quick框架在移动平台的渲染效率相当不错,C++和QML结合的开发方式可以提高不少开发效率。项目中需要在Qt中使用protobuf, 网上资料大多数不全,使用的开发包版本也较老,走...
  • Jupyter Notebook (IPython):一个能够让你最大限度地以交互式方式使用 Python 的丰富工具包。 awesome-jupyter 文件 文件管理和 MIME(多用途的网际邮件扩充协议)类型检测。 aiofiles:基于 asyncio,提供...
  • miniz:单一的C源文件,紧缩/膨胀压缩库,使用zlib兼容API,ZIP归档读写,PNG写方式。 Minizip:Zlib最新bug修复,支持PKWARE磁盘跨越,AES加密和IO缓冲。 smaz:小型字符压缩库。 Snappy :快速压缩和解压缩。 ...

空空如也

空空如也

1 2
收藏数 29
精华内容 11
关键字:

qml渲染方式