OpenGL в Qt

OpenGL в Qt

Для начала немного википедии

OpenGL (Open Graphics Library) — спецификация, определяющая платформонезависимый (независимый от языка программированияпрограммный интерфейс для написания приложений, использующих двумерную и трёхмерную компьютерную графику.

Включает более 300 функций для рисования сложных трёхмерных сцен из простых примитивов. Используется при создании компьютерных игрСАПРвиртуальной реальности, визуализации в научных исследованиях. На платформе Windows конкурирует с Direct3D.

Окей начнем с самого простого, все уроки будут в одном оконном приложении, а каждый урок будет просто новым классом.

Тк что создаем оконное приложение:

И сразу добавляем в него класс:

ППодключение OpenGL к Qt

Итак чтобы подключить OpenGL добавьте opengl в профайле проекта (.pro)

В заголовочном файле нового класса иклюднем QGLWidget

А также укажем что весь наш класс это потомок класса QGLWidget ООП, все дела.

Вот его краткое описание:

QGLWidget обеспечивает вывод OpenGL графики, интегрированной в Qt приложения. Вы наследуете свой класс и используете его как любой другой QWidget, но для рисования используется не QPainter или другие классы, а стандартные команды OpenGL.

Окей теперь нам нужно перегрузить 3 стандартных метода OpenGL и добавить еще один, который потребуется потом:

Обратите внимание что методы выделились курсивом, что означает что они перегружены, в отличии от scene().

Если вы знаете что такое перегрузка, пропустите следующий блок.

Перегрузка функций это типичный прием в си. Вот простейший пример, допустим у нас есть функция read(), мы хотим чтобы она умела читать какие то данные от пользователя, но ой йёёой, пользователь может ввести цифру, а может букву, будет очень неудобно преобразовывать одно в другое через например ASCII таблицу, поэтому мы можем перегрузить функцию чтобы она работала по разному в зависимости от того какой аргумент поступил к ней на вход, выглядеть это будет так.

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

Итак, теперь об этих методах

initializeGL();

initializeGL() … и тут я понял что сначала придется объяснить что такое контекст рендера, так что тут надо вникнуть в немного сухой теории, на самом деле чтобы использовать необязательно понимать устройство, тк что смело пропускайте следующие 3 абзаца ^^

Контекст графического устройства (Device Context) указывает плоскость отображения, на которую осуществляется графический вывод: окно программы на экране дисплея, страница принтера или другое место, куда может быть направлен графический вывод. Если программа вызывает различные графические функции, такие как рисование точек, линий, фигур и др., необходимо указывать идентификатор контекста (hdc – handle of device context) и координаты. Смысл использования контекста устройства заключается в том, что вывод на различные устройства осуществляется одними и теми же функциями, изменяется лишь значение hDC. «Контекст устройства является структурой, которая определяет комплект графических объектов и связанных с ними атрибутов и графические режимы, влияющие на вывод». При составлении программы необходимо получить это числовое значение перед рисованием, а после рисования – освободить контекст.

В OpenGL существует понятие контекст воспроизведения (контекст рендеринга), аналогичное понятию контекст устройства. Графическая система OpenGL также нуждается в ссылке на устройство, на которое будет осуществляться вывод. Это специальная ссылка на контекст воспроизведения – величина типа HGLRC (handle openGL rendering context, ссылка на контекст воспроизведения OpenGL) — hRC.

Прежде чем получить контекст воспроизведения, сервер OpenGL должен получить детальные характеристики используемого оборудования. Эти характеристики хранятся в специальной структуре – описание формата пиксела. Формат пиксела определяет конфигурацию буфера цвета и вспомогательных буферов.

Тк вот, функция initializeGL() как раз и задает тот самый контекст в котором будет рендерить OpenGL. Для начала просто установим фон черным:

Четвертый параметр в RGB это альфа канал, он отвечает за прозрачность

Вот еще несколько примеров что тут можно сделать

glEnable(GL_DEPTH_TEST);  // устанавливает режим проверки глубины пикселей
glShadeModel(GL_FLAT); // отключает режим сглаживания цветов
glEnable(GL_CULL_FACE); // устанавливаем режим, когда строятся только внешние поверхности(если мы работаем с 3D)

Далее идет resizeGL(), она вызывается во время изменения размеров окна

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

PaintGL рисует картинку не сразу на экран, а заносит в буфер, а по запросу swapBuffers() заменяет текущие изображение на то, что появилось в буфере. Сама по себе буфериция позволяет более корректно заменять изображение, чтоб не происходили скачки на экране.

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

И последняя перегруженная функция — paintGL()

Все движки как бы рисуют виртуальными кисточками, что qpaint, что opengl, так вот здесь мы как бы задаем для нее параметры.

Команда glMatrixMode() задает текущую матрицу. Т.е. ту матрицу, на которую будут воздействовать последующие вызовы команд отрисовки.

В OpenGL есть три матрицы (точнее три стека матриц):
1) Текстурные.
2) Преобразования модели.
3) Проекции.
1. При задании текстурных координат эти координаты перемножаются на матрицу 1.
2. При задании координат геометрии (glVertex, и т.д.) координаты перемножаются сначала на матрицу 2, потом на матрицу 3.

glCleat — стандартная очистка буфера о которой я уже говорил, может принимать следующие параметры:

GL_COLOR_BUFFER_BIT Очистка буфера цвета
GL_DEPTH_BUFFER_BIT Очистка буфера глубины
GL_ACCUM_BUFFER_BIT Очистка буфера накопления
GL_STENCIL_BUFFER_BIT Очистка буфера трафарета

О SwapBuffers() я тоже уже рассказывал, но повторю SwapBuffers() меняет буферы местами для двойной буферизации, а glLoadIndentyfy() загружает матрицу в буфер.

Тааакс, вы еще здесь? отлично, лан шучу до сюда разумеется никто не дойдет, ннно, мы начинаем самое интересное — рисовать в той самой матрице/контексте/поверхности. В самом начале мы объявляли функцию scene(), тк вот в ней мы и рисуем.

Чтобы так сказать опустить перо на поверхность есть команда glBegin(); которая в своем параметре принимает одну из множества вещей которые мы как раз собрались рисовать. glEnd() наоборот поднимает это воображаемое перо над поверхностью.

Наконец то рисуем

Итак нарисуем мы синий квадрат, да так просто. Ибо статья уже получилось огромной, а так кк это серия статей, то рисовать что-то посложнее и пополезней мы научимся потом.

точки указаны в процентом

Мы передали в glBegin GL_QUADS что означает что через каждые 4 точки по ним будет рисоваться четырехугольник.

С помощью glVertex2d() мы как раз и указываем эти самые точки.

Координаты выставляются относительно центра. Для большей очевидности смещу одну из координат на 0.1

Так же чисто для примера нарисую куб:

Похож на квадрат не так ли:

Думаю в одном из следующих уроков мы его покрутим.

Кстати советую обратить внимание как все классно перерисовывается благодаря той самой resizeGL()

Кстати забыл важную вещь, для запуска просто киньте кнопку на форму, и добавьте в обработчик ее нажатия это:

создать элемент нашего класса, и собственно показать его

Поздравляем, вы дочитали эту статью!

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

Войти с помощью: 
avatar
5000
1 Comment threads
0 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
1 Comment authors
alex90723 Recent comment authors
новые старые лучшие
alex90723
Гость
alex90723

Здравствуйте, вы пишете статьи на сайты сами? Мы занимаемся восстановлением уникальных статьей, из удаленных из интернета сайтов. Предлагаем снабжать вас… Читать дальше »