OpenGL. Урок 2. Рисование 2D фигур.

Продолжаем учебный курс по работе с графикой при помощи OpenGL!

И сегодня мы научимся рисовать основные фигуры, такие как треугольник, прямоугольник итд. Первый урок, посвященный OpenGL можно найти тут — ссылка. Итак, приступим…

Создадим пустой проект и добавим в него класс MainScene, как в предыдущей статье, а в сам класс — три пустые функции:

void MainScene::initializeGL()
{
 
}
 
void MainScene::resizeGL(int nWidth, int nHeight)
{
}
 
void MainScene::paintGL()
{
 
}

Напоминаю, что я использую в качестве среды разработки QT Creator, соответственно при создании класса мне нужно наследоваться от QGLWidget.

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

glClearColor(1.0, 1.0, 1.0, 1.0);

Первые три параметра соответствуют трем составляющим цвета — красной, зеленой и голубой (rgb). Единица означает максимум составляющей, таким образом, мы получаем чистейший белый цвет (все составляющие в максимуме = белый).

В функции main() добавляем создание сцены (объекта нашего класса) и задаем его размеры:

MainScene scene;
scene.resize(600, 600);
scene.show();

Собираем проект, запускаем и видим….абсолютно черный экран. В чем же дело?

А дело в том, что командой glClearColor() мы только задали цвет очистки экрана, но не произвели непосредственно очистку. Давайте добавим в функцию paintGL():

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

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

Итак, загружаем в матрицу проекции единичную матрицу и вызываем функцию glOrtho(). Эта функция преобразует изображение в соответствии с плоскостями отсечения, которые передаются в функцию в качестве аргументов. Допустим мы хотим, чтобы левая граница экрана соответствовала координате x = 0, а правая — x = 1. В свою очередь верх экрана — y = 1, а низ — y = 0. Ось z в нашем примере будет отвечать за расположение объектов относительно друг друга (чем ближе к нам объект, тем больше координата z, соответственно, ближние к нам объекты будут заслонять дальние). Зададим отображение по z от -1 — до 1:

void MainScene::resizeGL(int nWidth, int nHeight)
{
    glMatrixMode(GL_PROJECTION);
 
    glLoadIdentity();
 
    glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
 
    glViewport(0, 0, (GLint)nWidth, (GLint)nHeight);
}

Командой glViewport() мы устанавливаем размер сцены равным размеру окна нашего виджета (600 * 600, как мы указали в функции main()). Поскольку весь этот код мы поместили в функцию resizeGL(), теперь при изменениях размеров окна наше изображение также будет изменяться и подстраиваться под новые размеры.

Пришло время перейти к рисованию! Давайте первый делом попробуем нарисовать треугольник. Вот полный код:

void MainScene::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT);
 
    glColor3f(0.25, 0.87, 0.81);
    glBegin(GL_TRIANGLES);
 
    glVertex2f(0.0, 0.0);
    glVertex2f(1.0, 1.0);
    glVertex2f(1.0, 0.0);
 
    glEnd();
}

Для начала задаем цвет — пусть будет бирюзовый 😉 Рисование будет производиться при помощи функций glBegin(), glEnd(). В качестве аргумента первой из этих функций мы передаем тип рисуемой фигуры, а все, что содержится между функциями — точки фигуры, в нашем случае — три вершины треугольника.

Запускаем программу и вот он результат:

Примитивы в OpenGL

С этим разобрались, давайте теперь попробуем реализовать отрисовку квадрата. Принцип тут такой же, даже нечего объяснять =)

void MainScene::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT);
 
    glColor3f(0.25, 0.87, 0.81);
    glBegin(GL_TRIANGLES);
 
    glVertex2f(0.0, 0.0);
    glVertex2f(1.0, 1.0);
    glVertex2f(1.0, 0.0);
 
    glEnd();
 
    glColor3f(0.13, 0.56, 0.13);
    glBegin(GL_QUADS);
 
    glVertex2f(0.0, 0.5);
    glVertex2f(0.0, 1.0);
    glVertex2f(0.5, 1.0);
    glVertex2f(0.5, 0.5);
 
    glEnd();
}

Получаем квадрат, расположенный в соответствии с заданными нами координатами:

Квадрат в OpenGL

И в завершение сегодняшней статьи давайте изобразим что-нибудь при помощи ломаных линий. Принцип снова тот же самый 😉 Поэтому вот он код:

void MainScene::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT);
 
    glColor3f(0.25, 0.87, 0.81);
    glBegin(GL_TRIANGLES);
 
    glVertex2f(0.0, 0.0);
    glVertex2f(1.0, 1.0);
    glVertex2f(1.0, 0.0);
 
    glEnd();
 
    glColor3f(0.13, 0.56, 0.13);
    glBegin(GL_QUADS);
 
    glVertex2f(0.0, 0.5);
    glVertex2f(0.0, 1.0);
    glVertex2f(0.5, 1.0);
    glVertex2f(0.5, 0.5);
 
    glEnd();
 
    glLineWidth(2.0);
    glColor3f(0.65, 0.16, 0.16);
    glBegin(GL_LINE_STRIP);
 
    glVertex2f(0.0, 0.5);
    glVertex2f(0.5, 1.0);
    glVertex2f(1.0, 0.5);
    glVertex2f(0.5, 0);
    glVertex2f(0.0, 0.5);
 
    glEnd();
}

Помимо цвета, также зададим толщину линии.

Ломаная линия а OpenGL

Вот, что в итоге получилось )

Конечно, рисование при помощи glBegin..glEnd является очень простым и удобным, но строго говоря с точки зрения быстродействия этот способ не очень оптимален. Гораздо большего можно добиться, используя массивы вершин, массивы индексов и массивы цветов. Именно этому и будет посвящен следующий наш урок, не пропустите и до скорых встреч на нашем сайте!

Полный проект с примером из статьи — OpenGLTest

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

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

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