Как и обещал в конце второго урока (ссылка), сегодняшняя статья будет посвящена построению 2D-примитивов в OpenGL при помощи массивов вершин. Поставим такую задачу - реализовать все то, что мы сделали в прошлый раз, но только без использования функций glBegin() / glEnd().
Итак, для решения поставленной задачи нам понадобится создать три массива:
- массив вершин
- массив индексов
- массив цветов
Но для начала разберемся что это такое и зачем вообще эти массивы нужны.
В массивы вершин мы заносим декартовы координаты вершин фигуры, которую мы собираемся нарисовать. С этим все ясно. Но мало знать координаты, необходимо еще определить, в какой последовательности эти вершины нужно соединять линиями. И для этого как раз и нужен массив индексов вершин. Ну а с массивом цветов и так понятно, там мы будем задавать цвета вершин нашей 2D-фигуры. Сейчас напишем небольшой пример, и все сразу станет наглядно видно.
Итак, объявляем массивы:
GLfloat triangleVertexArray[3][3]; GLfloat triangleColorArray[3][3]; GLubyte triangleIndexArray[1][3];
У нашего треугольника три вершины, а у каждой вершины по три координаты, следовательно двумерный массив вершин должен иметь размер - 3 * 3. Аналогично с массивом цветов - три вершины по три составляющие цвета на каждую (RGB). Треугольник у нас будет всего один, поэтому triangleIndexArray имеет размер - 1 * 3. Теперь заполним их данными:
triangleVertexArray[0][0] = 0.0; triangleVertexArray[0][1] = 0.0; triangleVertexArray[0][2] = 0.0; triangleVertexArray[1][0] = 1.0; triangleVertexArray[1][1] = 1.0; triangleVertexArray[1][2] = 0.0; triangleVertexArray[2][0] = 1.0; triangleVertexArray[2][1] = 0.0; triangleVertexArray[2][2] = 0.0; triangleColorArray[0][0] = 0.25; triangleColorArray[0][1] = 0.87; triangleColorArray[0][2] = 0.81; triangleColorArray[1][0] = 0.25; triangleColorArray[1][1] = 0.87; triangleColorArray[1][2] = 0.81; triangleColorArray[2][0] = 0.25; triangleColorArray[2][1] = 0.87; triangleColorArray[2][2] = 0.81; triangleIndexArray[0][0] = 0; triangleIndexArray[0][1] = 1; triangleIndexArray[0][2] = 2; glVertexPointer(3, GL_FLOAT, 0, triangleVertexArray); glColorPointer(3, GL_FLOAT, 0, triangleColorArray); glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, triangleIndexArray);
Задаем все координаты вершин и цвет (цвет треугольника у нас будет однородным, так что все вершины должны иметь одинаковый цвет). В массив индексов просто заносим последовательные номера вершин. С исходными данными на этом все. Двигаемся дальше!
Помимо, собственно, заполнения массивов необходимо вызвать функции, непосредственно отвечающие за прорисовку фигуры.
Функция glVertexPointer() делает активным созданный массив вершин. Первый параметр функции - количество координат на каждую вершину, у нас их три (x, y, z), хотя строго говоря в нашем примере можно было обойтись и двумя координатами (мы пока работаем в 2D-пространстве). Второй параметр - тип данных, сохраненных в массиве. Третий - определяет шаг (в байтах) между данными с координатами для вершин, у нас данные идут плотно друг за другом, поэтому передаем в функцию аргумент 0. Ну и последний, четвертый, параметр - собственно наш массив вершин.
Полностью аналогичные параметры и у функции glColorPointer().
И, наконец, третья функция - glDrawElements(). В качестве аргументов мы передаем тип рисуемой фигуры, количество элементов в массиве индексов, тип данных и сам массив.
Казалось бы на этом все, но нет, необходимо еще активировать массивы вершин и цветов. Для этого в функции initializeGL() вызовем:
glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY);
Напоминаю, что в прошлых статьях курса по OpenGL мы уже создали пустой проект, а потом заполнили его всем необходимым, поэтому в сегодняшней статье я буду комментировать только то, что касается нашей сегодняшней темы. Подразумевается, что все нужное из проекта прошлой статьи перенесено и в этот новый проект. Собираем проект, запускаем и видим:
Треугольник на месте, давайте двигаться дальше. Отрисовка одного треугольника на самом деле не позволяет нам в полной мере почувствовать, как используется массив индексов вершин, поэтому давайте нарисуем следующее:
У нас имеется 6 вершин и 3 треугольника. Сразу же меняем размеры массивов:
GLfloat triangleVertexArray[6][3]; GLfloat triangleColorArray[6][3]; GLubyte triangleIndexArray[3][3];
Забиваем координаты вершин, а также цвета. Первоначальные три вершины (0, 1 и 2) оставим прежнего цвета, вершина 3 у нас будет красная, а вершины 4 и 5 - зеленые:
triangleVertexArray[0][0] = 0.0; triangleVertexArray[0][1] = 0.0; triangleVertexArray[0][2] = 0.0; triangleVertexArray[1][0] = 1.0; triangleVertexArray[1][1] = 1.0; triangleVertexArray[1][2] = 0.0; triangleVertexArray[2][0] = 1.0; triangleVertexArray[2][1] = 0.0; triangleVertexArray[2][2] = 0.0; triangleVertexArray[3][0] = 0.0; triangleVertexArray[3][1] = 1.0; triangleVertexArray[3][2] = 0.0; triangleVertexArray[4][0] = 0.75; triangleVertexArray[4][1] = 0.75; triangleVertexArray[4][2] = 0.0; triangleVertexArray[5][0] = 0.25; triangleVertexArray[5][1] = 0.25; triangleVertexArray[5][2] = 0.0; triangleColorArray[0][0] = 0.25; triangleColorArray[0][1] = 0.87; triangleColorArray[0][2] = 0.81; triangleColorArray[1][0] = 0.25; triangleColorArray[1][1] = 0.87; triangleColorArray[1][2] = 0.81; triangleColorArray[2][0] = 0.25; triangleColorArray[2][1] = 0.87; triangleColorArray[2][2] = 0.81; triangleColorArray[3][0] = 1.0; triangleColorArray[3][1] = 0.0; triangleColorArray[3][2] = 0.0; triangleColorArray[4][0] = 0.0; triangleColorArray[4][1] = 1.0; triangleColorArray[4][2] = 0.0; triangleColorArray[5][0] = 0.0; triangleColorArray[5][1] = 1.0; triangleColorArray[5][2] = 0.0;
Теперь самое интересное - массив индексов вершин. Необходимо определить, какие именно вершины участвуют при создании наших трех треугольников. Итак:
- Первый треугольник - вершины 0, 1, 2
- Второй треугольник - вершины 0, 3, 5
- Третий треугольник - вершины 1, 3, 4
Так и задаем в массиве индексов, а заодно немного корректируем аргументы функций:
triangleIndexArray[0][0] = 0; triangleIndexArray[0][1] = 1; triangleIndexArray[0][2] = 2; triangleIndexArray[1][0] = 0; triangleIndexArray[1][1] = 3; triangleIndexArray[1][2] = 5; triangleIndexArray[2][0] = 1; triangleIndexArray[2][1] = 3; triangleIndexArray[2][2] = 4; glVertexPointer(3, GL_FLOAT, 0, triangleVertexArray); glColorPointer(3, GL_FLOAT, 0, triangleColorArray); glDrawElements(GL_TRIANGLES, 9, GL_UNSIGNED_BYTE, triangleIndexArray);
Запускаем программу и видим результат, абсолютно совпадающий с нашим заданием ) Значит все сделано правильно, и сегодняшнюю статью на этом заканчиваем, в ближайших уроках по OpenGL начнем строить объемные 3D фигуры и разберемся с текстурами, оставайтесь на связи!
Лучшее объяснение этих glмассивов в рунете, СПАСИБО!!!))))
Спасибо! Рад, что полезно! =)
Добрый день.
Не раз читал, что использование связки glBegin() / glEnd() - это вроде как устаревший стиль написания. И еще вроде бы это работает несколько медленнее. Здесь увидел работу с массивами вершин индексов и цветов. Но есть же еще функции glNewList() / glEndList() / glCallList(). В какой-то степени это похоже на что-то среднее между первым и вторым вариантом? Или я ошибаюсь? Можно ли как-то сравнить скорость исполнения кода отрисовки с помощью этих функций и с помощью массивов вершин/индексов?