OpenGL. Урок 4. Создание 3D-объектов.

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

OpenGL

За основу давайте возьмем проект из предыдущего урока (ссылка), как и тогда, для построения изображения мы сегодня будем использовать массивы вершин, индексов и цветов. Давайте разберем нашу задачу…

Что из себя представляет куб? Ответ прост — 6 граней (квадратов) и 8 вершин 😉 Именно так мы и будем строить фигуру — построим по отдельности 6 его граней, а эта задача для нас уже не представляет никакой сложности.

Но прежде, чем приступать к рисованию, добавим в функцию initializeGL() следующее:

glShadeModel(GL_FLAT);
glEnable(GL_CULL_FACE);

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

Вторая функция устанавливает режим, когда строятся только внешние поверхности фигур. И вот тут есть один важный момент. Для корректного отображения объекта вершины в массиве вершин должны задаваться против(!) часовой стрелки.

Собственно, с приготовлениями на этом заканчиваем, начинаем отрисовку. Нам понадобятся три массива:

GLfloat cubeVertexArray[8][3];
GLfloat cubeColorArray[8][3];
GLubyte cubeIndexArray[6][4];

С размерами массивов мы разобрались на прошлом уроке, не буду повторяться, поэтому сразу же переходим к заполнению их данными. Кстати ребро нашего куба будет равно единице, в соответствии с этим задаем координаты вершин в трехмерном пространстве:

cubeVertexArray[0][0] = 0.0;
cubeVertexArray[0][1] = 0.0;
cubeVertexArray[0][2] = 1.0;
 
cubeVertexArray[1][0] = 0.0;
cubeVertexArray[1][1] = 1.0;
cubeVertexArray[1][2] = 1.0;
 
cubeVertexArray[2][0] = 1.0;
cubeVertexArray[2][1] = 1.0;
cubeVertexArray[2][2] = 1.0;
 
cubeVertexArray[3][0] = 1.0;
cubeVertexArray[3][1] = 0.0;
cubeVertexArray[3][2] = 1.0;
 
cubeVertexArray[4][0] = 0.0;
cubeVertexArray[4][1] = 0.0;
cubeVertexArray[4][2] = 0.0;
 
cubeVertexArray[5][0] = 0.0;
cubeVertexArray[5][1] = 1.0;
cubeVertexArray[5][2] = 0.0;
 
cubeVertexArray[6][0] = 1.0;
cubeVertexArray[6][1] = 1.0;
cubeVertexArray[6][2] = 0.0;
 
cubeVertexArray[7][0] = 1.0;
cubeVertexArray[7][1] = 0.0;
cubeVertexArray[7][2] = 0.0;
 
cubeColorArray[0][0] = 0.0;
cubeColorArray[0][1] = 0.0;
cubeColorArray[0][2] = 1.0;
 
cubeColorArray[1][0] = 0.6;
cubeColorArray[1][1] = 0.98;
cubeColorArray[1][2] = 0.6;
 
cubeColorArray[2][0] = 1.0;
cubeColorArray[2][1] = 0.84;
cubeColorArray[2][2] = 0.8;
 
cubeColorArray[3][0] = 0.8;
cubeColorArray[3][1] = 0.36;
cubeColorArray[3][2] = 0.36;
 
cubeColorArray[4][0] = 1.0;
cubeColorArray[4][1] = 0.27;
cubeColorArray[4][2] = 0.0;
 
cubeColorArray[5][0] = 0.82;
cubeColorArray[5][1] = 0.13;
cubeColorArray[5][2] = 0.56;
 
cubeColorArray[6][0] = 0.54;
cubeColorArray[6][1] = 0.17;
cubeColorArray[6][2] = 0.89;
 
cubeColorArray[7][0] = 0.0;
cubeColorArray[7][1] = 1.0;
cubeColorArray[7][2] = 1.0;

Мы задали координаты и цвета вершин куба. Давайте для наглядности посмотрим на рисунок:

Рисуем куб в OpenGL

Номера вершин на рисунке полностью соответствуют тому, как мы их задали в нашей программе. Теперь, глядя на картинку можно с легкостью пройтись по всем 6 граням куба и заполнить массив индексов. Давайте смотреть:

  • Грань 1 — вершины 0, 3, 2, 1
  • Грань 2 — вершины 0, 1, 5, 4
  • Грань 3 — вершины 7, 4, 5, 6
  • Грань 4 — вершины 3, 7, 6, 2
  • Грань 5 — вершины 1, 2, 6, 5
  • Грань 6 — вершины 0, 4, 7, 3

Теперь тоже самое делаем в программе =)

cubeIndexArray[0][0] = 0;
cubeIndexArray[0][1] = 3;
cubeIndexArray[0][2] = 2;
cubeIndexArray[0][3] = 1;
 
cubeIndexArray[1][0] = 0;
cubeIndexArray[1][1] = 1;
cubeIndexArray[1][2] = 5;
cubeIndexArray[1][3] = 4;
 
cubeIndexArray[2][0] = 7;
cubeIndexArray[2][1] = 4;
cubeIndexArray[2][2] = 5;
cubeIndexArray[2][3] = 6;
 
cubeIndexArray[3][0] = 3;
cubeIndexArray[3][1] = 7;
cubeIndexArray[3][2] = 6;
cubeIndexArray[3][3] = 2;
 
cubeIndexArray[4][0] = 1;
cubeIndexArray[4][1] = 2;
cubeIndexArray[4][2] = 6;
cubeIndexArray[4][3] = 5;
 
cubeIndexArray[5][0] = 0;
cubeIndexArray[5][1] = 4;
cubeIndexArray[5][2] = 7;
cubeIndexArray[5][3] = 3;

Теперь осталось только вызвать функцию рисования:

glVertexPointer(3, GL_FLOAT, 0, cubeVertexArray);
glColorPointer(3, GL_FLOAT, 0, cubeColorArray);
glDrawElements(GL_QUADS, 24, GL_UNSIGNED_BYTE, cubeIndexArray);

Запускаем программу и видим наш куб!

3D изображение в OpenGL

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

Сделаем так — при перемещении указателя мыши от левого края до правого будем поворачивать куб на 180 градусов. Осталось вычислить, на сколько градусов нужно повернуть фигуру при произвольном перемещении курсора. С этим все просто, получаем формулу:

yAngle = 180 * d / w;

Здесь d — это расстояние, на которое мы переместили курсор, w — ширина нашего окна. Обратите внимание, что при движении мыши вдоль оси x поворот будет осуществляться вокруг оси y, и наоборот, перемещение вдоль y — поворот вокруг x.

Итак, сейчас нам нужно получить в программе данные о перемещениях мыши. Для этого переопределим методы:

void MainScene::mousePressEvent(QMouseEvent *event)
{
    pressPosition = event->pos();
}
 
void MainScene::mouseMoveEvent(QMouseEvent *event)
{
    xAxisRotation += (180 * ((GLfloat)event->y() - (GLfloat)pressPosition.y())) / (currentHeight);
    yAxisRotation += (180 * ((GLfloat)event->x() - (GLfloat)pressPosition.x())) / (currentWidth);
 
    pressPosition = event->pos();
 
    updateGL();
}

При нажатии кнопки мыши (mousePressEvent()) сохраняем в переменную pressPosition текущие координаты курсора. При перемещениях указателя производим расчет углов поворота, на которые необходимо развернуть куб, а затем вызываем функцию updateGL() для перерисовки сцены в соответствии с полученными данными. Не забываем объявить все используемые методы и переменные в файле MainScene.h.

Функцию updateGL() то мы вызвали, но само собой ничего, естественно, не повернется )

Для поворота фигуры OpenGL предлагает нам следующую функцию:

glRotatef(angle, x, y, z);

Здесь первый параметр — угол поворота, а три остальных определяют, вокруг какой из осей необходимо выполнить вращение. То есть если мы сделаем так:

glRotatef(45, 1, 0, 0);

То фигура повернется вокруг оси x на 45 градусов.

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

void MainScene::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
    glMatrixMode(GL_MODELVIEW);
 
    glLoadIdentity();
 
    glRotatef(yAxisRotation, 0.0, 1.0, 0.0);
    glRotatef(xAxisRotation, 1.0, 0.0, 0.0);
    // Далее продолжается функция paintGL()
    .......................................

Как видите, все оказалось довольно-таки просто )

Теперь нам предстоит собрать проект и проверить результат:

Поворот изображения в OpenGL

На этом заканчиваем сегодняшнюю статью! А уже скоро, а именно в следующем уроке, мы разберемся с текстурами в OpenGL — создадим собственные текстуры и нанесем их на 3D объекты, так что до скорого, не пропустите новую статью 😉

Как и обещал прилагаю архив с полным проектом этого примера: OpenGLTest_Cube

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

OpenGL. Урок 4. Создание 3D-объектов.: 9 комментариев
  1. Отличный курс. С интересом слежу за ним и думаю не только я. В дальнейшем планируется затрагивать тему редактирования объектов? Например, было бы интересно узнать, как при наведении мыши на грань куба подсветить ее, как цепляться за узел и перетаскивать его.

  2. Великолепная вводная в OpenGL — с благодарностью жду от автора продолжения. Однозначно респект.

  3. Здравствуйте, можно ли Вам задавать вопросы? У меня проблема с массивами данных. У меня задание — построить полигонами деталь. координаты и как соединить их в элементы заданы. Не знаю как задать массив нормалей , и почему строиться невероятно большая деталь, хотя координаты в пределах [0.5;2] . Вы можете что то посоветовать? Как менять масштаб например

    • На самом деле так сложно что-то конкретное и определенное сказать… Надо хотя бы код или пример полностью посмотреть.

  4. Здравствуйте! У меня такая проблема: нужно научиться конвертировать любую плоскую фигуру в объёмную opengl c++. Не подскажете? Пжл

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

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