Real Tennis 2009 Harbor Master - убийца Flight Control?
Июн 18

firstrotationВ этом уроке, базируясь на уже изученном материале, мы одновременно выведем на экран треугольник и квадрат — с перемещением. Перемещение объекта — один из видов трансформации.

К модели (объекту) в 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);

Перед тем, как продолжить, вновь вернемся к моему рисунку трехмерного пространства:

worldspace1

Если помните, “камера” находится в точке (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” — экран должен выглядеть так, как показано ниже:

triandsquare

Обратите внимание: координата 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“, получив на экране следующий результат:

firstrotation

Вращение вдоль оси 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“. Что произойдет в этом случае?

Исходный код скачать можно [здесь]

Текст оригинальной статьи на английском языке [здесь]

Уважаемые читатели, данный материал был переведен и подготовлен к публикации проектом LookApp.ru, при публикации на другом сайте ссылка на LookApp.ru обязательна.

1 звезда2 звезд3 звезд4 звезд5 звезд (3 голосов, средний: 5.00 из 5)
Загрузка ... Загрузка ...


One Response to “Уроки iPhone SDK: (Часть 4) OpenGL ES: трансформации”

  1. 1. Алексей Says:

    Спасибо за отличный перевод классной статьи,
    после прочтения стало понятно многое

Оставьте комментарий