Qt mobile application development (8): Implements cross-platform QML and OpenGL hybrid rendering, and mobile application qml

Source: Internet
Author: User

Qt mobile application development (8): Implements cross-platform QML and OpenGL hybrid rendering, and mobile application qml

Qt mobile application development (8): cross-platform QML and OpenGL hybrid Rendering

 

In the previous article, we talked about the interaction between QML and Java by using C ++. The QML/JS development highly praised by Qt 5 enables lightweight and rapid development of QML/JS to Support lightweight C ++ and almost any technology. In the following article, we will use QML and use the Qt library and OpenGL to implement the rendering method that defines OpenGL using the coloring tool, so as to present the mixed rendering effect for everyone.

Original article, opposed to unstated reference. Original blog address: http://blog.csdn.net/gamesdev/article/details/38024327

This article is too difficult and suitable for experienced Qt developers to learn and communicate with each other.

Demo program: here

Source code: here

The demo program is as follows (Android ):

First, let's look at the simple QML code. This example is very simple. There is only one interface and there is no interface jump. We will display a rectangle in front of it, with "Hello World!" written on it !" Text, followed by a rotating rectangle. According to the regulations, the first display content is displayed at the bottom layer, so we put the Cube in front and the Rectangle in the back.

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. w Idth * 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: "Hello world! "Font. pixelSize: root. width/20 }}}

We found that the Cube class is not built-in with Qt Quick, but a custom QML module OpenGLCube. According to the above method in the sixth article, we registered the QML class in C ++ to enable QML to access the C ++ code. The implementation of the main function is as follows:

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

The main function registers a QML class to the QML environment through the qmlRegisterType function. The next step is the definition and implementation of the Cube class.

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
 

In Cube. h, let Cube inherit QQuickItem. Because Cube is also a display object of Qt Quick. By the way, the QQuickItem of C ++ corresponds to the Item class of QML, while the QObject of C ++ corresponds to the QtObject class of QML. In C ++, QQuickItem inherits from QObject, and in QML, Item inherits from QtObject. In the class definition, I used QOpenGLBuffer to maintain various drawing caches (buffers) and QOpenGLShaderProgram to easily load the shader data. Finally, I used a convenient macro to define the member variables controlled by the QML attribute system. When these variables change, let them notify the parent window (QQuickWindow) for updates.

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) {// initialize 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 ); // motion trim (); m_ModelViewMatrix.translate (0.0f, 0.0f,-601_f); m_ModelViewMatrix.rotate (m_RotateAngle, m_Axis.x (), m_Axis.y (), m_Axis.z ()); // render glViewport (0, 0, window ()-> width (), window ()-> height (); glClearColor (0.0f, 0.0f, 0.0f, 1.0f ); glClear (distinct | distinct); glable (GL_DEPTH_TEST); glable (GL_CULL_FACE); glFrontFace (GL_CW); m_ShaderProgram.bind (); Round (); int posLoc = trim ("position "); m_ShaderProgram.enableAttributeArray (posLoc); m_ShaderProgram.setAttributeBuffer (posLoc, // location GL_FLOAT, // Type 0, // offset 3, // element size 0); // Mai m_ColorBuffer.bind (); int colorLoc = m_ShaderProgram.attributeLocation ("color"); reverse (colorLoc); m_ShaderProgram.setAttributeBuffer (colorLoc, // location GL_FLOAT, // Type 0, // offset 4, // element size 0); // Mai m_IndexBuffer.bind (); values ("modelViewMatrix", m_ModelViewMatrix); values ("projectionMatrix", m_ProjectionMatrix); glDrawElements (GL_TRIANGLES, 36, expires, q_NULLPTR); iterator (posLoc); iterator (colorLoc); m_IndexBuffer.release (); m_VertexBuffer.release (); m_ShaderProgram.release ();} bool Cube: RunOnce (void) {// initialize the shader m_ShaderProgram.addShaderFromSourceFile (QOpenGLShader: Vertex, ":/Shader/shader. vsh "); m_ShaderProgram.addShaderFromSourceFile (QOpenGLShader: Fragment,":/shader/Shader. sh "); m_ShaderProgram.link (); // initialize the vertex cache const GLfloat length = 10.0f; const GLfloat vertices [] = {length,-length,-length, -length, length, -length,-length, length, length}; buffers (QOpenGLBuffer: StaticDraw); m_VertexBuffer.create (); m_VertexBuffer.bind (); m_VertexBuffer.allocate (vertices, sizeof )); // initialize color cache const GLfloat colors [] = {1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.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, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; initialize (QOpenGLBuffer: StaticDraw); m_ColorBuffer.create (); m_ColorBuffer.bind (); initialize (colors, sizeof (colors); // initialize the index cache GLubyte indices [] = {0, 1, 2, 0, 2, 3, // The following 7, 6, 4, 6, 5, 4, // above 7, 4, 3, 4, 0, 3, // 5, 6, 1, 6, 2, 1 on the left, // 4, 5, 0, 5, 1, 0 on the right, // front 3, 2, 6, 3, 6, 7, // back}; reverse (QOpenGLBuffer: StaticDraw); m_IndexBuffer.create (); m_IndexBuffer.bind (); m_IndexBuffer.allocate (indices, sizeof (indices )); // set the model matrix and projection matrix float aspectRatio = float (window ()-> width ()/float (window ()-> height (); m_ProjectionMatrix.perspective (45.0f, aspectRatio, 0.5f, 500366f); 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 ();}

Class implementation is complicated. It can be divided into the construction phase, initialization phase, rendering phase, and space release phase. Here we use the buffer + attribute array method commonly used by OpenGL ES 2.0 for efficient rendering. About OpenGL, if you are interested, you can refer to OpenGL ES 2.0 Programming Guide, Qt books about OpenGL, KDAB blogs about OpenGL, and other blogs to obtain relevant knowledge.

The above program loads the vertex and part pasters. They are as follows:

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

This example runs normally on the three major desktop platforms and runs smoothly on the Android platform.





Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

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.