OpenGL. Урок 1. Введение.

Всем доброго дня!

Сегодняшней статьей я положу начало новому учебному курсу на нашем сайте и посвящен он будет программированию с использованием графической библиотеки OpenGL. Начнем с основных концепций OpenGL, затем плавно перейдем к 2D и 3D-графике. В общем, будем много интересного 😉 Постараюсь все объяснять максимально подробно и понятно, чтобы статьи оказались действительно полезными.

Уроки OpenGL

Начнем с инструментария. Я, будучи большим любителем Qt, буду использовать модуль QtOpenGL. В принципе, его функционал не сильно отличается от библиотеки GLUT, так что думаю особых ограничений на изучение материала использование именно Qt не наложит )

Подключается библиотека максимально просто — надо всего лишь добавить в .pro файл проекта строку:

QT += opengl

Согласитесь, проще уже некуда 😉 Двигаемся дальше…

Базовым классом для работы с OpenGL в Qt является класс QGLWidget. Соответственно, класс виджета, в котором мы будем работать с OpenGL должен наследоваться от класса QGLWidget. Давайте сразу же параллельно с теорией рассматривать пример, чтобы лучше понимать как все устроено.

Итак, создаем проект, подключаем библиотеку и добавляем в наш проект новый класс. Дадим ему название MainScene. В проекте получаем два файла для нашего нового класса. Вот минимальный необходимый код для работы с OpenGL.

MainScene.h:

#include <QGLWidget>
 
class MainScene : public QGLWidget
{ 
   protected:
      void initializeGL();         
      void resizeGL(int w, int h);  
      void paintGL();
 
   public: 
      Scene3D(QWidget* parent = 0);
};

MainScene.cpp:

#include "MainScene.h"
 
MainScene::MainScene(QWidget* parent) : QGLWidget(parent) 
{ 
}
 
void MainScene::initializeGL()
{
}
 
void MainScene::resizeGL(int w, int h)
{ 
}
 
void MainScene::paintGL()
{ 
}

Итак, что мы тут имеем? А всего лишь пустой конструктор класса и три пока неизвестные нам функции. Сейчас будем разбираться, как эти функции работают и зачем они вообще нужны.

Итак, функции

  • initializeGL()
  • resizeGL()
  • paintGL()

это виртуальные функции, относящиеся именно к OpenGL, а не к классу QGLWidget. И именно через них и будет осуществляться все взаимодействие с OpenGL — инициализация, настройка, непосредственно отрисовка графических примитивов, фигур итд. Изначально эти функции абсолютно пустые и в них необходимо добавить весь нужный функционал.

Рассмотрим немного подробнее каждую из этих функций в отдельности.

Функция initializeGL(), как следует из ее названия, нужна для того, чтобы произвести в ней всю необходимую инициализацию, настроить параметры отображения, изменить режим работы OpenGL. Со всем перечисленным мы обязательно столкнемся при написании практических примеров в следующих статьях курса. Вот, например, таким образом можно изменить цвет фона окна:

void MainScene::initializeGL()
{
    qglClearColor(Qt::green);
}

Эту функцию не надо вызывать явно в теле конструктора виджета или в любом другом месте, она вызывается автоматически при создании виджета. Как и положено функции инициализации она вызывается только один раз, как уже сказано выше — при создании виджета. На самом деле тут все очень логично, даже особо нечего обсудить )

Следующая на очереди — функция resizeGL().

Эта функция вызывается каждый раз при изменении размеров окна. То есть когда пользователь запустил приложение и решил, к примеру, увеличить окно программы сразу же выполнится код, содержащийся в функции resizeGL(). Кроме этого случая, функция вызывается один раз после функции initializeGL():
Создание виджета => initializeGL() => resizeGL().

В эту функцию мы при работе с OpenGL будем помещать код, который будет обновлять наше графическое изображение в соответствии с новыми размерами окна.

Функция resizeGL() работает с двумя параметрами:

  • w — новое значение ширина окна виджета
  • h — новое значение высоты окна виджета

С resizeGL() вроде бы разобрались) Идем дальше!

Следующая на очереди функция paintGL(). Она вызывается каждый раз после вызова функции resizeGL() и запускает перерисовку сцены. Кроме этого случая, paintGL() вызывается каждый раз после вызова еще одной функции, а именно updateGL():
updateL() => paintGL()

Строго говоря это процесс протекает несколько иначе. На самом деле и при создании виджета, и при изменении размеров окна, и при вызове функции updateGL() вызывается функция glDraw(), принадлежащая классу QGLWidget. Но при написании программы непосредственно с этой функцией работать не надо, все действия связаны с функциями initializeGL(), resizeGL() и paintGL().

Таким образом, если мы хотим следить за каким то определенным событием и после его наступления выполнять перерисовку сцены мы должны использовать функцию updateGL(), вызов которой повлечет за собой вызов функции paintGL() и перерисовку сцены. Рассмотрим небольшой пример.

Пусть нам надо нарисовать фигуру и реализовать простейшею анимацию — перемещение нашей фигуры по экрану. Для того, чтобы получить нужный эффект будем периодически перерисовывать нашу фигуру, располагая ее в новом месте. Как все это сделать? А очень просто! Берем таймер, по сигналу таймера (допустим каждые 50 мс) вызывается слот, в котором мы изменяем координаты фигуры и вызываем функцию updateGL(). Эта функция в свою очередь вызовет paintGL(), которая уже перерисует всю сцену и нарисует нашу фигуру в соответствии с новыми координатами.

На словах вроде бы понятно, обязательно еще вернемся к этому практическому примеру и тогда уже поработаем с кодом 😉

А на сегодня, пожалуй, на этом закончим, разобрались мы в общих чертах со структурой проекта, использующего OpenGL, а также рассмотрели механизмы прорисовки. Для вводной статьи думаю этого вполне достаточно, так что до скорых встреч на нашем сайте!

Понравилась статья? Поделись с друзьями!

OpenGL. Урок 1. Введение.: 2 комментария

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *