|
Июл
05
|
В этот раз небольшое дополнение к прошлому уроку. Вернуться к основам математики меня заставили электронные письма с вопросами о том, что я имел в виду под рисованием круга и как это относится к поворотам и вращению в трехмерном пространстве.
Я начну с самого начала — с прямоугольных треугольников — и постепенно подойду к тому, как с помощью круга и треугольника осуществляется поворот в функции “gluLookAt()“.
Прямоугольный треугольник
Я не собираюсь вдаваться в объяснения. Вам нужно знать, что представляет собой прямоугольный (правильный) треугольник, что такое гипотенуза, прилежащие катеты и противолежащий катет. Чтобы все мы придерживались единой терминологии, приведу изображение с терминами:

Гипотенуза (hypotenuse)
Противолежащий (opposite)
Прилежащий (adjacent)
Предлагаю вспомнить все, пройденное в старших классах школы, а после забытое за ненадобностью. Длину любой стороны легко узнать по следующим формулам:
Гипотенуза: гипотенуза2 = прилежащий катет2 + противолежащий катет2
в С: hypoenuse = sqrt(adjacent*adjacent + opposite*opposite);
Длина прилежащего катета: косинус (Ɵ) * гипотенузу
в С: adjacent = cos(angleInRadians) * hypotenuse;
Длина противолежащего катета: синус (Ɵ) * гипотенузу
в C: oppositeLength = sin(angleInRadians) * hypotenuse.
Для начала запомните, что математические функции С работают не с градусами, а с радианами. Волновать это особенно не должно — главное знать два макроса для преобразования:
1 2 | #define DEGREES_TO_RADIANS(__ANGLE) ((__ANGLE) / 180.0 * M_PI) #define RADIANS_TO_DEGREES(__RADIANS) ((__RADIANS) * 180 / M_PI) |
Вот как легко запомнить соотношение между радианами и градусами: в круге 360º или 2 х π радиана. Соответственно, полукруг равен π радианам.
Согласно математической библиотеке GCC, M_PI в файле “math.h” определяется как 3.14-любое значение. Стандарту С это не совсем соответствует — возможностей для определения числа пи здесь нет. Технически, от вас требуется самостоятельный расчет, поэтому соблюдайте максимально возможную для конкретной аппаратной реализации точность (это всего лишь acos(-1) от памяти). Занимаясь программированием столько лет, я всегда за недостатком времени обходился исключительно определенными значениями.
Если не можете вспомнить принцип работы функций sin(), cos() и tan() — не страшно. Не обязательно знать особенности двигателя внутреннего сгорания, чтобы водить машину — главное знать, как (и когда) его задействовать.
Возвращаемся к программированию графики
Если помните, обсуждая в прошлом уроке перемещения и повороты в 3D, я сравнивал этот процесс с рисованием круга. Сейчас остановится на этом моменте подробнее, построив этот самый круг.
Ниже изображен круг с двумя отложенными на нем точками.

Ничего не заметили? Взгляните еще раз.
Ну конечно же, прямоугольные треугольники!
Зная радиус и угол, можно вычислить положение любой точки на окружности. А уже располагая этими данными — приступать к рисованию круга.
Мы знаем длину гипотенузы, поскольку она равна радиусу круга. Осталось вычислить точки X и Y. С учетом приведенных выше функций для синего треугольника координата X будет прилегающим катетом, а Y — противоположным.
Само собой, прилегающая и противоположная стороны меняются в зависимости от сектора, но пока этот момент не должен нас волновать. Код рисования круга:
1 2 3 4 5 | for (angle = 0; angle < 2*M_PI; angle += 0.01) { point[0] = RADIUS * cos(angle); point[1] = RADIUS * sin(angle); glDrawArrays(GL_POINTS, 0, 1); } |
Не забывайте, что значения sin() и cos() передаются не в градусах, а в радианах (в круге 360º или 2 х π радиана). Чем меньше прирост угла в рамках цикла, тем аккуратнее формируется круг. Для получения красивых, ровных кругов по большей части достаточно не точек, а очень коротких линий.
Переходим от кругов к поворотам из прошлого урока
Для определения объекта взгляда в трехмерном пространстве на прошлом уроке мы использовали функцию “glLookAt()“. Именно тогда я и сравнил ее работу с рисованием круга.
Если сейчас пользователь решит повернуться в направлении против часовой стрелки, результат будет следующим:

Уверен, все поняли, куда я клоню — к описанию круга посредством правильных треугольников.
Надеюсь, никто не забыл, что у нас была локация взгляда и направление взгляда. Локация взгляда не меняется — при повороте взгляд перемещается по окружности.
Код выглядел следующим образом:
1 2 3 4 | facing[0] = position[0] + cos(-TURN_SPEED)*vector[0] - sin(-TURN_SPEED)*vector[2]; facing[2] = position[2] + sin(-TURN_SPEED)*vector[0] + cos(-TURN_SPEED)*vector[2]; |
Переменная “facing” — объект взгляда, точка на окружности. Переменная “position” — положение зрителя, точка, из которой исходит взгляд. В трехмерном пространстве все несколько сложнее по сравнению с рисунком на плоском листе бумаги. Даже не рассчитывая жестко зафиксированную координату Y, мы должны узнать координаты X и Z.
Урок окончен
Вот мы и рассмотрели эту тему подробнее. В следующем уроке вернемся к основной теме — как только мне удастся подобрать подходящий фрагмент бесплатного кода.
Поскольку на этот раз мы ограничились исключительно теорией, кода к уроку не будет.


Сентябрь 20th, 2009 at 20:14
opposite = Противолежащий (под изображением [1])
Сентябрь 21st, 2009 at 01:01
Исправил, спасибо.
Сентябрь 22nd, 2009 at 19:59
если будет время,переведите пожалуйста вот эти статьи
http://web.me.com/smaurice/AppleCoder/iPhone_OpenGL/Entries/2009/6/17_OpenGL_ES_14_-_Getting_Access_to_Blender_Models__Part_1.html
http://web.me.com/smaurice/AppleCoder/iPhone_OpenGL/Entries/2009/7/25_OpenGL_ES_17_-_Collision_Detection.html
Сентябрь 22nd, 2009 at 23:11
Хорошо. Займемся.
Март 14th, 2012 at 11:51
Напишите пожалуйста про отображение поверхностей, например поверхностей Безье