| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the documentation of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:FDL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU Free Documentation License Usage |
| ** Alternatively, this file may be used under the terms of the GNU Free |
| ** Documentation License version 1.3 as published by the Free Software |
| ** Foundation and appearing in the file included in the packaging of |
| ** this file. Please review the following information to ensure |
| ** the GNU Free Documentation License version 1.3 requirements |
| ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| /*! |
| \example cube |
| \ingroup examples-widgets-opengl |
| \title Cube OpenGL ES 2.0 example |
| |
| \brief The Cube OpenGL ES 2.0 example shows how to write mouse rotateable |
| textured 3D cube using OpenGL ES 2.0 with Qt. It shows how to handle |
| polygon geometries efficiently and how to write simple vertex and |
| fragment shader for programmable graphics pipeline. In addition it |
| shows how to use quaternions for representing 3D object orientation. |
| |
| This example has been written for OpenGL ES 2.0 but it works also on |
| desktop OpenGL because this example is simple enough and for the |
| most parts desktop OpenGL API is same. It compiles also without OpenGL |
| support but then it just shows a label stating that OpenGL support is |
| required. |
| |
| \image cube.png Screenshot of the Cube example running on N900 |
| |
| The example consist of two classes: |
| |
| \list |
| \li \c MainWidget extends QOpenGLWidget and contains OpenGL ES 2.0 |
| initialization and drawing and mouse and timer event handling |
| \li \c GeometryEngine handles polygon geometries. Transfers polygon geometry |
| to vertex buffer objects and draws geometries from vertex buffer objects. |
| \endlist |
| |
| We'll start by initializing OpenGL ES 2.0 in \c MainWidget. |
| |
| \tableofcontents |
| |
| \section1 Initializing OpenGL ES 2.0 |
| |
| Since OpenGL ES 2.0 doesn't support fixed graphics pipeline anymore it has to |
| be implemented by ourselves. This makes graphics pipeline very flexible but |
| in the same time it becomes more difficult because user has to implement graphics |
| pipeline to get even the simplest example running. It also makes graphics pipeline |
| more efficient because user can decide what kind of pipeline is needed for the |
| application. |
| |
| First we have to implement vertex shader. It gets vertex data and |
| model-view-projection matrix (MVP) as parameters. It transforms vertex position |
| using MVP matrix to screen space and passes texture coordinate to |
| fragment shader. Texture coordinate will be automatically interpolated on polygon |
| faces. |
| |
| \snippet cube/vshader.glsl 0 |
| |
| After that we need to implement second part of the graphics pipeline - fragment |
| shader. For this exercise we need to implement fragment shader that handles |
| texturing. It gets interpolated texture coordinate as a parameter and looks up |
| fragment color from the given texture. |
| |
| \snippet cube/fshader.glsl 0 |
| |
| Using \c QGLShaderProgram we can compile, link and bind shader code to |
| graphics pipeline. This code uses Qt Resource files to access shader source code. |
| |
| \snippet cube/mainwidget.cpp 3 |
| |
| The following code enables depth buffering and back face culling. |
| |
| \snippet cube/mainwidget.cpp 2 |
| |
| \section1 Loading Textures from Qt Resource Files |
| |
| \c QOpenGLWidget interface implements methods for loading textures from QImage to GL |
| texture memory. We still need to use OpenGL provided functions for specifying |
| the GL texture unit and configuring texture filtering options. |
| |
| \snippet cube/mainwidget.cpp 4 |
| |
| \section1 Cube Geometry |
| |
| There are many ways to render polygons in OpenGL but the most efficient way is |
| to use only triangle strip primitives and render vertices from graphics hardware |
| memory. OpenGL has a mechanism to create buffer objects to this memory area and |
| transfer vertex data to these buffers. In OpenGL terminology these are referred |
| as Vertex Buffer Objects (VBO). |
| |
| \image cube_faces.png Cube faces and vertices |
| |
| This is how cube faces break down to triangles. Vertices are ordered this way |
| to get vertex ordering correct using triangle strips. OpenGL determines triangle |
| front and back face based on vertex ordering. By default OpenGL uses |
| counter-clockwise order for front faces. This information is used by back face |
| culling which improves rendering performance by not rendering back faces of the |
| triangles. This way graphics pipeline can omit rendering sides of the triangle that |
| aren't facing towards screen. |
| |
| Creating vertex buffer objects and transferring data to them is quite simple using |
| QOpenGLBuffer. MainWidget makes sure the GeometryEngine instance is created and |
| destroyed with the OpenGL context current. This way we can use OpenGL resources |
| in the constructor and perform proper cleanup in the destructor. |
| |
| \snippet cube/geometryengine.cpp 0 |
| |
| \snippet cube/geometryengine.cpp 1 |
| |
| Drawing primitives from VBOs and telling programmable graphics pipeline how to |
| locate vertex data requires few steps. First we need to bind VBOs to be used. |
| After that we bind shader program attribute names and configure what |
| kind of data it has in the bound VBO. Finally we'll draw triangle |
| strip primitives using indices from the other VBO. |
| |
| \snippet cube/geometryengine.cpp 2 |
| |
| \section1 Perspective Projection |
| |
| Using \c QMatrix4x4 helper methods it's really easy to calculate perpective |
| projection matrix. This matrix is used to project vertices to screen space. |
| |
| \snippet cube/mainwidget.cpp 5 |
| |
| \section1 Orientation of the 3D Object |
| |
| Quaternions are handy way to represent orientation of the 3D object. Quaternions |
| involve quite complex mathematics but fortunately all the necessary mathematics |
| behind quaternions is implemented in \c QQuaternion. That allows us to store |
| cube orientation in quaternion and rotating cube around given axis is quite |
| simple. |
| |
| The following code calculates rotation axis and angular speed based on mouse events. |
| |
| \snippet cube/mainwidget.cpp 0 |
| |
| \c QBasicTimer is used to animate scene and update cube orientation. Rotations |
| can be concatenated simply by multiplying quaternions. |
| |
| \snippet cube/mainwidget.cpp 1 |
| |
| Model-view matrix is calculated using the quaternion and by moving world by Z axis. |
| This matrix is multiplied with the projection matrix to get MVP matrix for shader |
| program. |
| |
| \snippet cube/mainwidget.cpp 6 |
| |
| */ |