Top.Mail.Ru

Уроки OpenGL. Часть 1. Введение.

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

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

Начнем с инструментария. Я, будучи большим любителем 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() работает с 2-мя аргументами:

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

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

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

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

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

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

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

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

Следующий урок доступен по ссылке - https://microtechnics.ru/opengl-urok-2-risovanie-2d-figur/

Подписаться
Уведомить о
guest

2 комментариев
Старые
Новые
Межтекстовые Отзывы
Посмотреть все комментарии
Владимир
Владимир
10 лет назад

Не ожидал увидеть на сайте электроники раздел с OpenGL.

2
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x