179 lines
7.3 KiB
Plaintext
179 lines
7.3 KiB
Plaintext
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
|
** All rights reserved.
|
|
** Contact: Nokia Corporation (qt-info@nokia.com)
|
|
**
|
|
** 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
|
|
|
|
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
|
|
|
|
*/
|