Базовые фигуры (примитивы) — основные элементы, из которых при рисовании выстраиваются сложные объекты. В OpenGL ES такими примитивами выступают объекты Point (Точка), Line (Линия), Triangle (Треугольник). Думаю, их названия говорят сами за себя.В этом уроке мы будем анализировать код, на основании которого впоследствии можно будет создавать собственные проекты.
Примитив №1 — треугольники
Треугольники — самые сложные из базовых фигур, но они настолько удобны и полезны, что с них мы и начнем. Чтобы нарисовать треугольник, необходимо указать OpenGL три координаты трехмерного пространства — остальное программа сделает сама.
Первым делом создайте копию проекта из урока "OpenGL ES: настройка проекта в Xcode" или загрузите исходный код отсюда. Открыв проект в Xcode, перейдите к файлу "EAGLView.m" и найдите метод "drawView". Начинается настоящее волшебство!
Первым шагом зададим параметры треугольника. Сразу обращаю внимание на то, что мы будем работать с координатами двух типов: Model и World. Координаты Model относятся к отрисовываемому примитиву, а координаты World сообщают OpenGL о его местонахождении относительно зрителя (который в пространстве World всегда находится в точке (0.0, 0.0, 0.0)).
Итак, задаем координаты треугольника в пространстве Model через три трехмерные координаты (X, Y, Z):
const GLfloat triangleVertices[] = {
0.0, 1.0, -6.0,// Верхняя центральная точка треугольника
-1.0, -1.0, -6.0,// нижняя левая
1.0, -1.0, -6.0,// нижняя правая
};
Заметьте, что координаты описаны последовательно, в направлении против часовой стрелки (оно может быть и противоположным — главное, задавать их последовательно и придерживаться единой схемы). Для начала я бы рекомендовал работу по схеме «против часовой стрелки», поскольку именно такой порядок требуется для некоторых рассматриваемых ниже функций.
Хотя наш урок посвящен технологии iPhone OpenGL ES, для новичков я вкратце остановлюсь на трехмерной системе координат. Взгляните на рисунок:

Отвлечемся от моих художественных способностей и посмотрим, как выглядит пространство Model (или World). Представьте себе, что это компьютерный монитор, где X и Y — соответственно, горизонтальная и вертикальная оси, а Z — глубина. Центральная точка соответствует координатам (0.0, 0.0, 0.0).
Если теперь рассмотреть треугольник в применении к этим осям, то первая точка (0.0, 1.0, -6.0) будет его центром на оси Y, смещенная вверх на один пункт и на шесть пунктов в глубину экрана. Вторая координата находится на один пункт правее оси Y, ниже оси X (поскольку значение Y составляет -1.0) и на шесть пунктов в глубину экрана (-6.0). Точно по такому же принципу анализируется и третья координата.
Величина Z сделана отрицательной, чтобы отодвинуть объект назад и сделать его видимым (не забывайте, что «камера» находится в точке (0.0, 0.0, 0.0), поэтому в ином случае объект не пройдет тест OpenGL на глубину и не будет визуализирован).
Кое-кто сразу заметит: «Так ведь сказано было, что мы работаем с координатами Model, а не World!» Это действительно так, но когда мы доберемся до визуализации треугольника, OpenGL сразу поместит объект в точку (0.0, 0.0, 0.0). Поэтому уже сейчас отодвигаем его в глубину экрана, делая видимым. Позже, рассматривая трансформации (перемещение, вращение и пр.), что добиться такого результата можно, не прибегая к отрицательным величинам. А до тех пор оставим для координаты Z значение -6.0.
Код рисования
Теперь мы готовы описывать треугольник, сообщив OpenGL, где хранятся данные и как рисовать примитив. Для этого нам хватит нескольких строк кода. Вернитесь к методу "drawView" и реализуйте его, как показано ниже:
- (void)drawView {
const GLfloat triangleVertices[] = {
0.0, 1.0, -6.0, // Верхняя центральная точка треугольника
-1.0, -1.0, -6.0, // нижняя левая
1.0, -1.0, -6.0 // нижняя правая
};
[EAGLContext setCurrentContext:context];
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
glViewport(0, 0, backingWidth, backingHeight);
// -- НАЧАЛО НОВОГО КОДА
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glVertexPointer(3, GL_FLOAT, 0, triangleVertices);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawArrays(GL_TRIANGLES, 0, 3);
// -- КОНЕЦ НОВОГО КОДА
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
[self checkGLError:NO];
}
Как видите, для визуализации треугольника достаточно четырех строк кода. Разберем каждую их них, чтобы убедиться, что все очень просто.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Эта строка очищает экран. Управляющие биты сообщают OpenGL о необходимости использовать черный цвет, заданный на прошлом уроке в методе "setupView", и очистить буфер глубины. Если буфер подключить, не сделав этого, сцена визуализирована не будет. Если буфер не подключать, в передаче glClear() сообщения GL_DEPTH_BUFFER_BIT необходимости нет.
Итак, мы очистили все, что прежде рисовалось в буфере (Не забыли о двойной буферизации? В одном буфере рисуем, другой отображаем).
glVertexPointer(3, GL_FLOAT, 0, triangleVertices);
Функция сообщает OpenGL о местонахождении данных и их формате. У нее четыре параметра, которые максимально просты:
1. Размер: число значений в каждой координате. В нашем случае их три (X, Y, Z). При рисовании двухмерных объектов без глубины (т.е. величины Z) будет указана цифра 2.
2. Тип данных: GL_FLOAT означает величину с плавающей запятой. При желании допустимы и целые числа, но в трехмерных пространствах без плавающих точек не обойтись.
3. Величина шага вычислений: сообщает OpenGL об игнорировании определенного количества байт между координатами. Пусть этот параметр пока не волнует — оставьте его равным нулю. Работать с ним будете при загрузке данных по вершинам из файла, формат которого предусматривает заполняющую пробелы информацию или данные по цвету, например, из 3D-приложения Blender.
4. Указатель данных — собственно, сами данные.
Итак, мы предложили OpenGL очистить буфер, указали данные для объекта и сообщили его формат. Настало время крайне важного сообщения.
glEnableClientState(GL_VERTEX_ARRAY);
OpenGL работает с состояниями. Это означает, что функции активируются и отключаются соответствующими командами. Выше мы применили команду "glEnable()", работающую с «серверным» режимом OpenGL. Команда "glEnableClientState()" включает «программный» режим (т.е. клиентское состояние). На текущий момент мы сообщили OpenGL, что данные по вершинам находятся в отдельном массиве и активировали функцию OpenGL для рисования вершины. Теоретически, вершина может быть массивом цвета (в этом случае стоит обратиться к "glEnableClientState(GL_COLOR_ARRAY)") или массивом текстурных координат при наложении текстур (хватит вздыхать! чтобы накладывать текстуры, нужно для начала освоить основы!).
По мере освоения OpenGL нам предстоит работа с разными клиентскими состояниями, поэтому время на разбор данной темы еще будет.
Настало время команды для визуализации треугольника:
glDrawArrays(GL_TRIANGLES, 0, 3);
При вызове данной функции OpenGL обрабатывает полученную из двух предыдущих функций информацию. На экране появится треугольник с белой заливкой (белый — цвет по умолчанию при рисовании). Треугольники — объекты с заливкой. Для рисования пустого треугольника понадобится иная техника.
Разбираем три аргумента данной функции:
1. Метод рисования: в данном случае "GL_TRIANGLES", название которого само по себе достаточно красноречиво. Возможность оценить потенциал первого аргумента нам представится позже, когда с помощью этой функции мы будем рисовать квадрат.
2. Первая вершина: наш массив состоит всего из трех точек. Мы хотим, чтобы OpenGL отталкивался от первой точки в массиве, указанной как ноль (стандартный доступ к массиву). Если бы в массиве вершин содержалось несколько примитивов, было бы уместным смещение. Подробнее об этом — в последующих уроках, где речь пойдет о создании сложных объектов. Пока пусть будет ноль.
3. Количество вершин: сообщает OpenGL, сколько в массиве рисуемых вершин. Для треугольника их, само собой, три, для квадрата — 4, для линии — 3 (и более), для точки — одна (и более при визуализации многочисленных точек).
После того, как код набран, а метод "drawView" приведен к указанному выше виду, кнопкой "Build and Go" запустите проект в симуляторе. Результат будет выглядеть примерно так, как и предполагалось — белый треугольник в центре экрана.

Перед переходом к следующим примитивам попробуйте изменить величину Z, и увидите, что при значении 0.0 визуализация не выполняется.
Для нескольких строк кода пояснений получилось немало, но, думаю, это того стоило. Надеюсь, что те, кому уже приходилось спотыкаться о «типовые» уроки по OpenGL, уже поняли разницу между OpenGL и OpenGL ES.
Исходный код к уроку можно скачать здесь.
