Графические средства OpenGL
Графические средства OpenGL
OpenGL является стандартным программным интерфейсом, предназначенным для воспроизведения графики 2D и 3D. Приложения Qt могут отображать графику 3D, используя модуль QtOpenGL, который рассчитан на применение системной библиотеки OpenGL. При изложении данного раздела предполагается, что вы знакомы с OpenGL. Если вы не знакомы с OpenGL, хорошо начинать его изучение с посещения сайта http://www.opengl.org/.
Рис. 8.17. Приложение Тетраэдр.
Вывод графики при помощи OpenGL в приложении Qt выполняется достаточно просто: мы должны создать подкласс QGLWidget, переопределить несколько виртуальных функций и собрать приложение вместе с библиотеками QtOpenGL и OpenGL. Из-за того, что QGLWidget наследует QWidget, большая часть наших знаний остается применимой и здесь. Основное отличие заключается в том, что вместо QPainter для выполнения графических операций мы используем стандартные функции библиотеки OpenGL.
Для демонстрации этого подхода мы рассмотрим программный код приложения Тетраэдр, показанного на рис. 8.17. Это приложение отображает в пространстве тетраэдр или четырехгранник, грани которого имеют различные цвета. Пользователь может поворачивать тетраэдр, нажимая кнопку мышки и перемещая ее. Пользователь может задавать цвет поверхности грани путем двойного щелчка с последующим выбором цвета в диалоговом окне QColorDialog, которое выдается на экран.
01 class Tetrahedron : public QGLWidget
02 {
03 Q_OBJECT
04 public:
05 Tetrahedron(QWidget *parent = 0);
06 protected:
07 void initializeGL();
08 void resizeGL(int width, int height);
09 void paintGL();
10 void mousePressEvent(QMouseEvent *event);
11 void mouseMoveEvent(QMouseEvent *event);
12 void mouseDoubleClickEvent(QMouseEvent *event);
13 private:
14 void draw();
15 int faceAtPosition(const QPoint &pos);
16 GLfloat rotationX;
17 GLfloat rotationY;
18 GLfloat rotationZ;
19 QColor faceColors[4];
20 QPoint lastPos;
21 }
Класс Tetrahedron наследует QGLWidget. Функции класса QGLWidget initializeGL(), resizeGL() и paintGL() переопределяются. Обработчики событий мышки класса QWidget переопределяются обычным образом.
01 Tetrahedron::Tetrahedron(QWidget *parent)
02 : QGLWidget(parent)
03 {
04 setFormat(QGLFormat(QGL::DoubleBuffer | QGL::DepthBuffer)
05 rotationX = -21.0;
06 rotationY = -57.0;
07 rotationZ = 0.0;
08 faceColors[0] = Qt::red;
09 faceColors[1] = Qt::green;
10 faceColors[2] = Qt::blue;
11 faceColors[3] = Qt::yellow;
12 }
В конструкторе мы вызываем функцию QGLWidget::setFormat() для установки контекста экрана OpenGL и инициализируем закрытые переменные этого класса.
01 void Tetrahedron::initializeGL()
02 {
03 qglClearColor(Qt::black);
04 glShadeModel(GL_FLAT);
05 glEnable(GL_DEPTH_TEST);
06 glEnable(GL_CULL_FACE);
07 }
Функция initializeGL() вызывается только один раз перед вызовом функции paintGL(). Именно в этом месте мы можем задавать контекст воспроизведения OpenGL, определять списки отображаемых элементов и выполнять остальную инициализацию.
Весь программный код является стандартным кодом OpenGL, за исключением вызовов функции qglClearColor() класса QGLWidget. Если бы мы захотели строго придерживаться стандартных возможностей OpenGL, мы вместо этого вызывали бы функцию glClearColor() при использовании режима RGBA и glClearIndex() при использовании режима индексированных цветов.
01 void Tetrahedron::resizeGL(int width, int height)
02 {
03 glViewport(0, 0, width, height);
04 glMatrixMode(GL_PROJECTION);
05 glLoadIdentity();
06 GLfloat x = GLfloat(width) / height;
07 glFrustum(-x, x, -1.0, 1.0, 4.0, 15.0);
08 glMatrixMode(GL_MODELVIEW);
09 }
Функция resizeGL() вызывается один раз перед первым вызовом функции paintGL(), но после вызова функции initializeGL(). Oнa также всегда вызывается при изменении размера виджета. Именно в этом месте мы можем задавать область отображения OpenGL, ее проекцию и делать любые другие настройки, зависящие от размера виджета.
01 void Tetrahedron::paintGL()
02 {
03 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
04 draw();
05 }
Функция paintGL() вызывается всякий раз, когда необходимо перерисовать виджет. Это напоминает функцию QWidget::paintEvent(), но вместо функций класса QPainter здесь мы используем функции библиотеки OpenGL. Реальное рисование выполняется закрытой функцией draw().
01 void Tetrahedron::draw()
02 {
04 static const GLfloat P1[3]= { 0.0, -1.0, +2.0 };
05 static const GLfloat P2[3] = { +1.73205081, -1.0, -1.0 };
06 static const GLfloat P3[3] = { -1.73205081, -1.0, -1.0 };
07 static const GLfloat P4[3] = { 0.0, +2.0, 0.0 };
08 static const GLfloat * const coords[4][3] = {
09 { P1, P2, РЗ }, { P1, РЗ, P4 }, { P1, P4, P2 }, { P2, P4, РЗ }
10 };
11 glMatrixMode(GL_MODELVIEW);
12 glLoadIdentity();
13 glTranslatef(0.0, 0.0, -10.0);
14 glRotatef(rotationX, 1.0, 0.0, 0.0);
15 glRotatef(rotationY, 0.0, 1.0, 0.0);
16 glRotatef(rotationZ, 0.0, 0.0, 1.0);
17 for (int i = 0; i < 4; ++i) {
18 glLoadName(i);
19 glBegin(GL_TRIANGLES);
20 qglColor(faceColors[i]);
21 for (int j = 0; j < 3; ++j) {
22 glVertex3f(coords[i][j][0],
23 coords[i][j][1], coords[i][j][2]);
24 }
25 glEnd();
26 }
27 }
В функции draw() мы рисуем тетраэдр, учитывая повороты по осям x, у и z, а также цвета в массиве faceColors. Везде вызываются стандартные функции библиотеки OpenGL, за исключением вызова qglColor(). Вместо этого мы могли бы использовать одну из функций OpenGL — glColor3d() или glIndex() — в зависимости от используемого режима.
01 void Tetrahedron::mousePressEvent(QMouseEvent *event)
02 {
03 lastPos = event->pos();
04 }
05 void Tetrahedron::mouseMoveEvent(QMouseEvent *event)
06 {
07 GLfloat dx = GLfloat(event->x() - lastPos.x()) / width();
08 GLfloat dy = GLfloat(event->y() - lastPos.y()) / height();
09 if (event->buttons() & Qt::LeftButton) {
10 rotationX += 180 * dy;
11 rotationY += 180 * dx;
12 updateGL();
13 } else if (event->buttons() & Qt::RightButton) {
14 rotationX += 180 * dy;
15 rotationZ += 180 * dx;
16 updateGL();
17 }
18 lastPos = event->pos();
19 }
Функции класса QWidget mousePressEvent() и mouseMoveEvent() переопределяются, чтобы разрешить пользователю поворачивать изображение щелчком мышки и ее перемещением. Левая кнопка мышки позволяет пользователю поворачивать вокруг осей x и у, а правая кнопка мышки — вокруг осей x и z.
После модификации переменных rotationX и rotationY или rotationZ мы вызываем функцию updateGL() для перерисовки сцены.
01 void Tetrahedron::mouseDoubleClickEvent(QMouseEvent *event)
02 {
03 int face = faceAtPosition(event->pos());
04 if (face != -1) {
05 QColor color = QColorDialog::getColor(faceColors[face], this);
06 if (color.isValid()) {
07 faceColors[face] = color;
08 updateGL();
09 }
10 }
11 }
Функция mouseDoubleClickEvent() класса QWidget переопределяется, чтобы разрешить пользователю устанавливать цвет грани тетраэдра с помощью двойного щелчка. Мы вызываем закрытую функцию faceAtPosition() для определения той грани, на которой находится курсор (если он вообще находится на какой-нибудь грани). При двойном щелчке по грани тетраэдра мы вызываем функцию QColorDialog::getColor() для получения нового цвета для этой грани. Затем мы обновляем массив цветов faceColors новым цветом, и мы вызываем функцию updateGL() для перерисовки экрана.
01 int Tetrahedron::faceAtPosition(const QPoint &pos)
02 {
03 const int MaxSize = 512;
04 GLuint buffer[MaxSize];
05 GLint viewport[4];
06 glGetIntegerv(GL_VIEWPORT, viewport);
07 glSelectBuffer(MaxSize, buffer);
08 glRenderMode(GL_SELECT);
09 glInitNames();
10 glPushName(0);
11 glMatrixMode(GL_PROJECTION);
12 glPushMatrix();
13 glLoadIdentity();
14 gluPickMatrix(GLdouble(pos.x()),
15 GLdouble(viewport[3] - pos.y()),
16 5.0, 5.0, viewport);
17 GLfloat x = GLfloat(width()) / height();
18 glFrustum(-x, x, -1.0, 1.0, 4.0, 15.0);
19 draw();
20 glMatrixMode(GL_PROJECTION);
21 glPopMatrix();
22 if (!glRenderMode(GL_RENDER))
23 return -1;
24 return buffer[3];
25 }
Функция faceAtPosition() возвращает номер грани для заданной точки виджета или —1, если данная точка не попадает на грань. Программный код этой функции, выполненной с помощью средств OpenGL, немного сложен. Фактически мы переводим работу в режим GL_SELECT, чтобы воспользоваться возможностями OpenGL по идентификации элементов изображения, и затем получаем номер грани (ее «имя») из записи нажатия OpenGL.
Ниже приводится файл main.cpp:
01 #include <QApplication>
02 #include <iostream>
03 #include "tetrahedron.h"
04 using namespace std;
05 int main(int argc, char *argv[])
06 {
07 QApplication app(argc, argv);
08 if (!QGLFormat::hasOpenGL()) {
09 cerr << "This system has no OpenGL support" << endl;
10 return 1;
11 }
12 Tetrahedron tetrahedron;
13 tetrahedron.setWindowTitle(QObject::tr("Tetrahedron"));
14 tetrahedron.resize(300, 300);
15 tetrahedron.show();
16 return app.exec();
17 }
Если система пользователя не поддерживает OpenGL, мы выдаем на консоль сообщение об ошибке и сразу же возвращаем управление.
Для сборки приложения совместно с модулем QtOpenGL и системной библиотекой OpenGL файл .pro должен содержать следующий элемент:
QT += opengl
Этим заканчивается разработка приложения Тетраэдр. Более подробную информацию о модуле QtOpenGL вы найдете в справочной документации по классам QGLWidget, QGLFormat, QGLContext, QGLColormap и QGLPixelBuffer.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
(7.6) При работе полноэкраных Direct3D и OpenGL приложений, очень низкий refresh rate, как можно это исправить?
(7.6) При работе полноэкраных Direct3D и OpenGL приложений, очень низкий refresh rate, как можно это исправить? Сделать это можно, и связано это с тем КАК NT работает со своей графической подсистемой. Есть несколько способов. Если драйвера видеокарты позволяют, то делается это легко и
Графические редакторы
Графические редакторы Существует множество графических редакторов, позволяющих изменять цифровые фотографии. Компания Adobe традиционно поставляет на рынок хороший графический редактор Adobe Photoshop. Но, несмотря на его великолепные возможности, у многих пользователей не
6.4. При работе полноэкранных Direct3D и OpenGL приложений, очень низкий refresh rate, как можно это исправить?
6.4. При работе полноэкранных Direct3D и OpenGL приложений, очень низкий refresh rate, как можно это исправить? Сделать это можно, и связано это с тем КАК NT работает со своей графической подсистемой. Есть несколько способов. Если драйвера видеокарты позволяют, то делается это легко и
Графические гиперссылки
Графические гиперссылки В начале этой главы говорилось, что гиперссылка может быть в виде не только фрагмента текста, но и картинки или даже представлять собой фрагмент графического изображения. Вот графическими гиперссылками мы сейчас и
Графические объекты
Графические объекты Наиболее распространенными в Интернете графическими объектами являются GIF– и JPEG-файлы. Методы сжатия, используемые в них, позволяют размещать на веб-страницах изображения высокого качества и (что очень важно) небольшого размера. ПРИМЕЧАНИЕ Понятно
4.6.1. Графические редакторы
4.6.1. Графические редакторы Редактор растровой графики GIMP — обрабатываем фотоThe GIMP (The GNU Image Manipulation Program) — свободно распространяемый редактор растровой графики, по своим функциям ставший достойной заменой программе Photoshop. Вот некоторые возможности GIMP (далеко не
5. Графические редакторы
5. Графические редакторы Графический редактор, который нам помогает в работе, – это SnagIt (программа для создания скриншотов). PhotoShop поставьте обязательно, чтобы работать с
Основные возможности OpenGL
Основные возможности OpenGL · Набор базовых примитивов: точки, линии, многоугольники и т.п.· Видовые и координатные преобразования· Удаление невидимых линий и поверхностей (z-буфер)· Использование сплайнов для построения линий и поверхностей· Наложение текстуры и
Графические утилиты
Графические утилиты При помощи APT в репозитарии Ubuntu можно найти несколько утилит с графическим интерфейсом для копирования Audio CD.В файловый менеджер Konqueror встроена возможность автоматического перекодирования Audio CD. Первоначально это был только Ogg Vorbis, в последних версиях
Графические методы
Графические методы В предыдущих примерах уже были использованы несколько методов для работы с графикой. Но сейчас следует поговорить о них более подробно. Прежде всего нужно помнить, что для работы с графическими методами необходимо сначала создать объект Graphics.
OpenGL vs. Direct3D
OpenGL vs. Direct3D OpenGL и Direct3D - две основные на сегодняшний день аппаратно-ускоряемые библиотеки для создания компьютерной трехмерной графики. Перед каждым начинающим 3D-программистом встает вопрос: какой из двух вариантов API выбрать? Вопрос этот совсем не прост, собственного
Графические планшеты
Графические планшеты Если ваши художественные способности выше средних, а по вашим будущим художественным шедеврам плачут Третьяковская галерея и Лувр, возможно, есть смысл приобрести графический планшет (он же – дигитайзер). С помощью данного устройства вы сможете
Графические соглашения
Графические соглашения Для разминки начнем с небольшой проблемы, связанной с нотацией. Это конечно деталь, но из деталей складывается общая картина. Речь идет о наборе соглашений, используемых для графического представления классов и объектов. В предшествующей лекции
5.1.11. Графические объекты
5.1.11. Графические объекты Растровые изображенияК растровым (точечным) изображениям относятся: рисунки, созданные в растровом графическом редакторе, цифровые фотографии, отсканированные схемы, открытки, обложки, фрагменты документов и т. п. Для Pages растровые изображения