Камера. Движение. Видовая матрица. | |||||||||||||||||
Сразу предупрежу читателя - все то, о чем говорится в этом обзоре, часто можно выполнить используя стандартные вспомогательные библиотеки, например GLU в OpenGL или библиотеки почившего нас Retained режима в Direct3D. Но ведь лишние знания никому не помешают ? :) Тогда вперед. Немного вспомним о самой как ее называют видовой матрице. В общем видовая матрица выполняет при умножении на нее всю основную работу по:
Решение назревает само собой - мы должны сохранить локальные оси модели. При выполнении вращения по одной из осей - вращать на соответствующий угол две других локальных оси. Сразу же перейдем к ПРИМЕРУ этой статьи. Написан он с использованием OpenGL на основе все того шаблона. Локальные оси координат определены в примере тремя векторами - vlook,vup,vright. Предназначение всех трех понятно даже интуитивно.
Продолжим. Для того, что бы повернуть соответствующую локальную ось на определенный угол, нужно подготовить матрицу вращения на данный угол, а затем перемножить полученную матрицу на вектор оси.
Все идет достаточно неплохо, но это только на первый взгляд. Из-за погрешностей в операциях с плавающей точкой, уже после пары вращений локальные оси координат теряют свою перпендикулярность. Для того, что бы компенсировать это явление, необходимо выполнить регенирацию или как ее еще называют рекалибрацию векторов: (Внимание ! В первой версии этой статьи здесь была допущена ошибка - не нужно забывать, что операция векторного произведения векторов не коммутативна, а соответственно порядок следования аргументов для CrossProduct() ВАЖЕН !) void RegenerateVectors(void) { NormalizeVector(vlook); CrossProduct(vup,vlook,vright); // векторно перемножим VUP на VLOOK NormalizeVector(vright); CrossProduct(vlook,vright,vup); // векторно перемножим VLOOK на VRIGHT NormalizeVector(vup); return; }Идея калибрации видна из самого текста программы - необходимо выполнить серию нормализаций и векторных произведений векторов. Обрати внимание на то, что вектор vlook лишь нормализуется - но не регенерируется из других. Эту операцию необходимо выполнять первой - до формирования самой матрицы или операций с осями. Немного отвлекусь и скажу в кратце о движении - поскольку после регенерации все три вектора осей являются еденичными (нормализованными, то есть их значения не привышают еденицы), мы можем достаточно просто, отталкиваясь от текущего положения в пространстве и вектора направления вычислить смещение по этому вектору. Например для того, чтобы имитировать движение вперед (вдоль вектора vlook) нам необходимо каждую компоненту координаты текущего положения увеличить на произведение соответствующей компоненты вектора на текущую "скрость": for (int j=0;j<3;j++) { cur_pos[j] += speed * vlook[j]; }Вот мы и подошли к тому, с чего начали - построению видовой матрицы. Все достаточно просто - мы должны сделать активной матрицу, построив ее исходя из следующего правила:
где DotProduct - скалярное произведение векторов. А теперь это же в программе: glLoadIdentity(); glGetFloatv(GL_MODELVIEW_MATRIX,mview); mview[0] = vright[0]; mview[1] = vup[0]; mview[2] = vlook[0]; mview[4] = vright[1]; mview[5] = vup[1]; mview[6] = vlook[1]; mview[8] = vright[2]; mview[9] = vup[2]; mview[10] = vlook[2]; mview[12] = -DotProduct(vright,cur_pos); mview[13] = -DotProduct(vup,cur_pos); mview[14] = -DotProduct(vlook,cur_pos); glLoadMatrixf(mview); // сделаем активной новоиспеченную матрицу...Важно то, что скалярное произведение векторов для членов 12,13,14 видовой матрицы должно быть отрицательным. |
|||||||||||||||||
Эта статья является интеллектуальной собственностью автора (JM). Перепечатка или публикация отдельных ее частей или целиком разрешена с обязательным указанием источника. |