summaryrefslogtreecommitdiffstats
path: root/doc/src/examples/cube.qdoc
blob: 4aeee1f6458ba67d6e66a3e9a476b0e943a6ab91 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

/*!
    \example opengl/cube
    \group all-examples
    \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
	\o \c MainWidget extends QGLWidget and contains OpenGL ES 2.0
		initialization and drawing and mouse and timer event handling
	\o \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 examples/opengl/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 examples/opengl/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 examples/opengl/cube/mainwidget.cpp 3

	The following code enables depth buffering and back face culling.

	\snippet examples/opengl/cube/mainwidget.cpp 2

	\section1 Loading textures from Qt Resource files

	\c QGLWidget 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 examples/opengl/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
	OpenGL provided functions.

	\snippet examples/opengl/cube/geometryengine.cpp 0

	\snippet examples/opengl/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 examples/opengl/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 examples/opengl/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 examples/opengl/cube/mainwidget.cpp 0

	\c QBasicTimer is used to animate scene and update cube orientation. Rotations
	can be concatenated simply by multiplying quaternions.

	\snippet examples/opengl/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 examples/opengl/cube/mainwidget.cpp 6

*/