1 /****************************************************************************
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
6 ** This file is part of the documentation of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
45 \title Cube OpenGL ES 2.0 example
47 \brief The Cube OpenGL ES 2.0 example shows how to write mouse rotateable
48 textured 3D cube using OpenGL ES 2.0 with Qt.
50 It shows how to handle
51 polygon geometries efficiently and how to write simple vertex and
52 fragment shader for programmable graphics pipeline. In addition it
53 shows how to use quaternions for representing 3D object orientation.
55 This example has been written for OpenGL ES 2.0 but it works also on
56 desktop OpenGL because this example is simple enough and for the
57 most parts desktop OpenGL API is same. It compiles also without OpenGL
58 support but then it just shows a label stating that OpenGL support is
61 \image cube.png Screenshot of the Cube example running on N900
63 The example consist of two classes:
66 \o \c MainWidget extends QGLWidget and contains OpenGL ES 2.0
67 initialization and drawing and mouse and timer event handling
68 \o \c GeometryEngine handles polygon geometries. Transfers polygon geometry
69 to vertex buffer objects and draws geometries from vertex buffer objects.
72 We'll start by initializing OpenGL ES 2.0 in \c MainWidget.
76 \section1 Initializing OpenGL ES 2.0
78 Since OpenGL ES 2.0 doesn't support fixed graphics pipeline anymore it has to
79 be implemented by ourselves. This makes graphics pipeline very flexible but
80 in the same time it becomes more difficult because user has to implement graphics
81 pipeline to get even the simplest example running. It also makes graphics pipeline
82 more efficient because user can decide what kind of pipeline is needed for the
85 First we have to implement vertex shader. It gets vertex data and
86 model-view-projection matrix (MVP) as parameters. It transforms vertex position
87 using MVP matrix to screen space and passes texture coordinate to
88 fragment shader. Texture coordinate will be automatically interpolated on polygon
91 \snippet examples/opengl/cube/vshader.glsl 0
93 After that we need to implement second part of the graphics pipeline - fragment
94 shader. For this exercise we need to implement fragment shader that handles
95 texturing. It gets interpolated texture coordinate as a parameter and looks up
96 fragment color from the given texture.
98 \snippet examples/opengl/cube/fshader.glsl 0
100 Using \c QGLShaderProgram we can compile, link and bind shader code to
101 graphics pipeline. This code uses Qt Resource files to access shader source code.
103 \snippet examples/opengl/cube/mainwidget.cpp 3
105 The following code enables depth buffering and back face culling.
107 \snippet examples/opengl/cube/mainwidget.cpp 2
109 \section1 Loading textures from Qt Resource files
111 \c QGLWidget interface implements methods for loading textures from QImage to GL
112 texture memory. We still need to use OpenGL provided functions for specifying
113 the GL texture unit and configuring texture filtering options.
115 \snippet examples/opengl/cube/mainwidget.cpp 4
117 \section1 Cube Geometry
119 There are many ways to render polygons in OpenGL but the most efficient way is
120 to use only triangle strip primitives and render vertices from graphics hardware
121 memory. OpenGL has a mechanism to create buffer objects to this memory area and
122 transfer vertex data to these buffers. In OpenGL terminology these are referred
123 as Vertex Buffer Objects (VBO).
125 \image cube_faces.png Cube faces and vertices
127 This is how cube faces break down to triangles. Vertices are ordered this way
128 to get vertex ordering correct using triangle strips. OpenGL determines triangle
129 front and back face based on vertex ordering. By default OpenGL uses
130 counter-clockwise order for front faces. This information is used by back face
131 culling which improves rendering performance by not rendering back faces of the
132 triangles. This way graphics pipeline can omit rendering sides of the triangle that
133 aren't facing towards screen.
135 Creating vertex buffer objects and transferring data to them is quite simple using
136 OpenGL provided functions.
138 \snippet examples/opengl/cube/geometryengine.cpp 0
140 \snippet examples/opengl/cube/geometryengine.cpp 1
142 Drawing primitives from VBOs and telling programmable graphics pipeline how to
143 locate vertex data requires few steps. First we need to bind VBOs to be used.
144 After that we bind shader program attribute names and configure what
145 kind of data it has in the bound VBO. Finally we'll draw triangle
146 strip primitives using indices from the other VBO.
148 \snippet examples/opengl/cube/geometryengine.cpp 2
150 \section1 Perspective projection
152 Using \c QMatrix4x4 helper methods it's really easy to calculate perpective
153 projection matrix. This matrix is used to project vertices to screen space.
155 \snippet examples/opengl/cube/mainwidget.cpp 5
157 \section1 Orientation of the 3D object
159 Quaternions are handy way to represent orientation of the 3D object. Quaternions
160 involve quite complex mathematics but fortunately all the necessary mathematics
161 behind quaternions is implemented in \c QQuaternion. That allows us to store
162 cube orientation in quaternion and rotating cube around given axis is quite
165 The following code calculates rotation axis and angular speed based on mouse events.
167 \snippet examples/opengl/cube/mainwidget.cpp 0
169 \c QBasicTimer is used to animate scene and update cube orientation. Rotations
170 can be concatenated simply by multiplying quaternions.
172 \snippet examples/opengl/cube/mainwidget.cpp 1
174 Model-view matrix is calculated using the quaternion and by moving world by Z axis.
175 This matrix is multiplied with the projection matrix to get MVP matrix for shader
178 \snippet examples/opengl/cube/mainwidget.cpp 6