Продолжаем учебный курс по работе с графикой при помощи OpenGL! И сегодня мы займемся рисованием основных 2D-фигур, таких как треугольник, прямоугольник, линия итд. Первый урок, посвященный 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(). В качестве аргумента первой из этих функций мы передаем тип рисуемой фигуры, а все, что содержится между функциями - точки фигуры, в нашем случае - три вершины треугольника. Запускаем программу и вот он результат:
С этим разобрались, давайте теперь попробуем реализовать отрисовку квадрата. Принцип тут такой же, даже нечего объяснять:
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(); }
Получаем квадрат, расположенный в соответствии с заданными нами координатами:
И в завершение сегодняшней статьи давайте изобразим что-нибудь при помощи ломаных линий. Принцип снова тот же самый, поэтому вот он код:
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(); }
Помимо цвета, также зададим толщину линии, и вот, что в итоге получилось:
Конечно, рисование при помощи glBegin() / glEnd() является очень простым и удобным, но строго говоря с точки зрения быстродействия этот способ не очень оптимален. Гораздо большего можно добиться, используя массивы вершин, массивы индексов и массивы цветов. Именно этому и будет посвящен следующий наш урок, не пропустите и до скорых встреч на нашем сайте!
Полный проект с примером из статьи - OpenGLTest.
У меня всплывает два окна и два белых
Спасибо за урок!!!