|
Июн
18
|
В этом уроке, базируясь на уже изученном материале, мы одновременно выведем на экран треугольник и квадрат — с перемещением. Перемещение объекта — один из видов трансформации.
К модели (объекту) в OpenGL ES применимы три разных вида трансформаций:
- Перемещение Translate — движение объекта в трехмерном пространстве.
- Вращение Rotate — вращение вокруг оси X, Y или Z.
- Масштабирование — изменение размеров объекта. Применяется преимущественно в системах двухмерной ортографической проекции, т.к. в трехмерном пространстве размер визуализируемого объекта уменьшается с его отдалением (т.е. с возрастанием негативного значения по координате Z). Подходит для “спецэффектов”.
Для демонстрации функциональных возможностей сначала одновременно выведем на экран квадрат и треугольник с помощью функции “Translate“, а после перейдем к двум следующим.
Перемещение
За эффект перемещения в OpenGL ES отвечает одна единственная функция с говорящим за себя названием — “glTranslatef()“. Обратили внимание на букву “f” после слова “translate”? Значит, OpenGL будет принимать данные с плавающей запятой. Для обработки данных с фиксированной точкой вызывается функция “glTranslatex()“. Этот вариант применим там, где аппаратное обеспечение не предусматривает сопроцессора для вычислений с плавающей точкой, но в iPhone он есть, поэтому будем придерживаться первой опции.
Рассказываю все это на тот случай, если Xcode предложит работу с “glTranslatex()“, а вы не уверены, в чем между ними разница.
Приступаем к программированию. Запустив Xcode, откройте проект. Надеюсь, как я и просил, вместо удаления все откомментировали данные по треугольнику и запросам визуализации — иначе сейчас придется набирать их заново.
Для начала обратимся к двум массивам вершин. Мы изменим данные — но только для координат Z, установив их все на 0.0, как показано ниже:
1 2 3 4 5 6 7 8 9 10 11 12 | const GLfloat triangleVertices[] = { 0.0, 1.0, 0.0, // Верхняя центральная точка треугольника -1.0, -1.0, 0.0, // Нижняя левая 1.0, -1.0, 0.0 // Нижняя правая }; const GLfloat squareVertices[] = { -1.0, 1.0, 0.0, // Верхняя левая -1.0, -1.0, 0.0, // Нижняя левая 1.0, -1.0, 0.0, // Верхняя правая 1.0, 1.0, 0.0 // Нижняя правая }; |
Помните, почему для координат Z мы задали значение -6.0? Нужно было отодвинуть их вглубь экрана, подальше от “камеры”, находящейся в точке (0.0, 0.0, 0.0). Сейчас вместо того, чтобы задавать смещение в координатах вершин, отодвинем их на шесть пунктов с помощью функции “glTranslatef()“.
Для начала сообщим OpenGL, что именно мы собираемся перемещать — проекцию Projection (представление World) или объекты Objects (модели в рамках World). В нашем случае это треугольник и квадрат: в методе “drawView“, под обращением к “glClear()“, вызываем следующую функцию OpenGL:
1 2 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); |
Запрос к “glMatrixMode” сообщает OpenGL о необходимости работать с данными вершин вместо проекции. В методе “setupView” мы обращаемся к той же функции, но в качестве параметра используем перечень “GL_PROJECTION“. Не забывайте, что OpenGL останется в прежнем состоянии, пока не будет задано иное. Следовательно, режим “Matrix Mode“сохранится как “GL_PROJECTION“, пока вызовом “glMatrixMode(GL_MODELVIEW)” мы не перейдем в представление Model. Соответственно, теперь OpenGL находится в состоянии “GL_MODELVIEW” до тех пор, пока не будет указано иное.
На самом деле, для максимальной производительности этот вызов стоило поместить в конец созданного в первом уроке метода “setupView“. Но поскольку мы только учимся, пусть он останется в методе “drawView“.
Я помню, что пока подробно не останавливался на работе с OpenGL ES в режиме проекции, но путь не расстраиваются те, кто не понял всего, сказанного выше. Мы всего лишь помещаем объекты на экран, экспериментируя с ними в рамках изучения OpenGL ES.
Удаляем комментарии вокруг кода рисования треугольника, который выглядит примерно так:
1 2 3 | glVertexPointer(3, GL_FLOAT, 0, triangleVertices); glEnableClientState(GL_VERTEX_ARRAY); glDrawArrays(GL_TRIANGLES, 0, 3); |
Перед этими тремя строками кода добавьте еще две:
1 2 3 4 5 | glLoadIdentity(); glTranslatef(-1.5, 0.0, -6.0); glVertexPointer(3, GL_FLOAT, 0, triangleVertices); glEnableClientState(GL_VERTEX_ARRAY); glDrawArrays(GL_TRIANGLES, 0, 3); |
Функция “glLoadIdentity()” возвращает все к исходным условиям. Без нее запрос “glTranslatef()” смещал бы объект влево и назад до исчезновения с экрана. Позже (через пару уроков) я расскажу о более удобном способе выполнения данной задачи, а пока просто восстановим данные объекта.
Следующий вызов функции приводит к активным действиям:
glTranslatef()” принимает три параметра:
glTranslatef(GLfloat xtrans, GLfloat ytrans, GLfloat Ztrans);
Перед тем, как продолжить, вновь вернемся к моему рисунку трехмерного пространства:

Если помните, “камера” находится в точке (0.0, 0.0, 0.0). В отправленном выше вызове “glTranslatef()” присутствуют следующие значения:
xtrans = -1.5
ytrans = 0.0
ztrans = -6.0
Теперь вспоминаем, что при рисовании квадрата и треугольника оба они появлялись в центре экрана. Если вновь нарисовать им тем же способом, объекты будут наложены друг на друга.
Чтобы избежать этого, я сместил координату X центра треугольника влево на 1,5 пункта. Согласно схеме вверху левая часть экрана соответствует отрицательным значениям, поэтому значение составит -1,5.
-6.0 для трансформации Z заменит исходное значение -6.0 из массива вершин объекта.
Итак, мы сместили треугольник влево на 1,5 и назад на 6 пунктов.
Переходим к квадрату
Код для квадрата практически ничем не отличается от треугольника:
1 2 3 4 5 | glLoadIdentity(); glTranslatef(1.5, 0.0, -6.0); glVertexPointer(3, GL_FLOAT, 0, squareVertices); glEnableClientState(GL_VERTEX_ARRAY); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); |
Квадрат мы смещаем вправо, передавая положительную величину значению “xtrans” для функции “glTranslatef()“.
Щелкаем на кнопке “Build and Go” — экран должен выглядеть так, как показано ниже:

Обратите внимание: координата Y по-прежнему в центре экрана, размер фигур не изменился, поскольку мы отодвинули их назад (-6.0) и аккуратно разместили рядом.
Перед тем, как продолжить
Поэкспериментируйте, меняя значения “xtrans“, “ytrans” и “ztrans” в “glTranslatef()“, чтобы проверить, как это отобразится на результате.
Вращение
После экспериментов верните код в первоначальный вид — пора знакомиться с вращением. Вращение у нас будет двухмерным, как и объекты (но в трехмерном пространстве). Позже, создав полноценный 3D, получим реальное трехмерное вращение (ну и текстуры — куда без них).
С вращением все просто:
glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
Первым аргументом функции указываем угол вращения, потом определяем вращаемую ось (или оси).
Я продемонстрирую два способа вращения. Сначала выполним статичное вращение, потом добавим к нему анимацию, получив крутящийся эффект.
Первой рассмотрим простую анимацию. Перейдите к методу “drawView” и отредактируйте код рисования треугольника и квадрата, как показано ниже:
1 2 3 4 5 6 7 8 9 10 11 12 13 | glLoadIdentity(); glTranslatef(-1.5, 0.0, -6.0); glRotatef(45.0, 0.0, 0.0, 1.0); // Добавьте строку glVertexPointer(3, GL_FLOAT, 0, triangleVertices); glEnableClientState(GL_VERTEX_ARRAY); glDrawArrays(GL_TRIANGLES, 0, 3); glLoadIdentity(); glTranslatef(1.5, 0.0, -6.0); glRotatef(45.0, 0.0, 0.0, 1.0); // Добавьте строку glVertexPointer(3, GL_FLOAT, 0, squareVertices); glEnableClientState(GL_VERTEX_ARRAY); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); |
Мы просто повернули треугольник и квадрат на 45º вдаль оси Z. Эту команду передает OpenGL значение 1.0 для параметра Z.
Внеся изменения в код, щелкните на кнопке “Build and Run“, получив на экране следующий результат:

Вращение вдоль оси Z “крутит” объект на экране по аналогии с видом автомобильного колеса сбоку. Надеюсь, все помнят, что ось Z, вдоль которой осуществляется вращение, идет вглубь экрана.
Вращение вдоль оси X будет напоминать колесо направляющейся к вам машины, а вдоль оси Y — ситуацию, когда водитель выворачивает руль, чтобы объехать вас (шутка). Если пока не все понятно, не спешите впадать в панику — после экспериментов все встанет на свои места.
Раскручиваем объекты
Чтобы квадрат и треугольник стали “крутиться”, нужно увеличивать угол при каждой прорисовке фрейма. Переключитесь на файл “EAGLView.h” и добавьте следующую переменную:
1 | GLfloat rota; |
Переходим обратно к файлу “EAGLView.m” и в методе “initWithCoder” вставляем приведенную ниже строку под назначением “animationInterval“:
1 | rota = 0.0; |
Мы только что создали переменную, которая будет хранить текущий угол вращения.
Возвращаемся к “drawView” и перед первым вызовом функции “glLoadIdentity()” добавляем следующую строку кода:
1 | rota += 0.5; |
Таким образом, при каждом рисовании двух объектов угол вращения увеличивается на 0,5º. После этого меняем оба вызова функции “glRotatef()“, как показано ниже:
1 | glRotatef(rota, 0.0, 0.0, 1.0); |
Каждый раз, рисуя объекты, мы увеличиваем угол вращения, получая вертящийся объект. При первой прорисовке объекты повернутся на 0,5º, при второй — на 1,0º и т.д.
Щелчком на кнопке “Build and Run” заставьте объекты крутиться, как колесо при взгляде на него сбоку.
Для экспериментов
В завершение урока предлагаю выполнить пару заданий, проанализировав результат:
1. Поменяйте ось вращения. Задайте для оси Z значения 0.0 и по очереди подключите оси X и Y, чтобы лучше понять способы вращения.
2. Измените значение 1.0 для текущей оси вращения на -1,0 — теперь объекты крутятся в противоположном направлении.
3. Параметр “rota” в функции “glRotatef()” поменяйте на “-rota“. Что произойдет в этом случае?


Октябрь 1st, 2009 at 15:52
Спасибо за отличный перевод классной статьи,
после прочтения стало понятно многое