The QDoc command `\tableofcontents` was rendered useless by a change more than a decade ago. Remove the use of `\tableofcontents` as it serves no purpose, and ensure that the surrounding context still makes sense for the reader, by removing preceding text that refers to a non-existing table of contents, such as `Contents:`. Task-number: QTBUG-128173 Pick-to: 6.8 Change-Id: Ibb5a6af0e80f70fa487cdf6a7e38009a9ef60cbf Reviewed-by: Safiyyah Moosa <safiyyah.moosa@qt.io> Reviewed-by: Venugopal Shivashankar <Venugopal.Shivashankar@qt.io>
144 lines
6.1 KiB
Plaintext
144 lines
6.1 KiB
Plaintext
// Copyright (C) 2020 The Qt Company Ltd.
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
|
|
|
/*!
|
|
\example cube
|
|
\ingroup examples-widgets-opengl
|
|
\title Cube OpenGL ES 2.0 example
|
|
\examplecategory {3D}
|
|
|
|
\brief Shows how to manually rotate a textured 3D cube with user input.
|
|
|
|
The Cube OpenGL ES 2.0 example shows how to manually rotate a textured 3D
|
|
cube with user input, using OpenGL ES 2.0 with Qt. It shows how to
|
|
handle polygon geometries efficiently and how to write a simple vertex and
|
|
fragment shader for a 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.
|
|
|
|
\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 QOpenGLShaderProgram 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
|
|
|
|
The \c QOpenGLWidget interface implements methods for loading textures from QImage
|
|
to OpenGL texture memory. We still need to use OpenGL provided functions for
|
|
specifying the OpenGL 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
|
|
|
|
*/
|