Qt行動裝置 App開發(八):實現跨平台的QML和OpenGL混合渲染

來源:互聯網
上載者:User

標籤:qt   opengl   glsl   android平台   opengl es   

Qt行動裝置 App開發(八):實現跨平台的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放在了後面。

import QtQuick 2.2import QtQuick.Window 2.2import OpenGLCube 1.0Window{    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.vshattribute 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.fshvarying highp vec4 v_Color;void main( void ){    gl_FragColor = v_Color;}

         本例在三大案頭平台上運行正常,同時在Android平台上也能夠順利地運行。


Qt行動裝置 App開發(八):實現跨平台的QML和OpenGL混合渲染

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.