У меня есть самолет в 3D-мире, и его ориентация сохраняется любым способом (например, тангаж, рыскание и крен). Теперь, когда я хочу, чтобы самолет повернул налево, но glRotatef не выполняет свою работу, поскольку придерживается глобальных координат и не заботится о вращении плоскости, и простое изменение рыскания также не помогает, так как это тоже не относительно плоскостей фактическое вращение и будет означать «влево» только тогда, когда самолет летит прямо к горизонту. То, что мне нужно, было бы так:
float pitch = 10 , yaw = 20, roll = 30; //some initial values
Turn(&pitch, &yaw, &roll , 5, 0 , 0 ) //calculate new pitch, yaw and roll as if
//the plane had turned 5 degrees to the right (relative to its current orientation and roll!)
//pitch, yaw and roll are updated to reflect the new orientation.
Многие люди предлагают использовать кватернионы, но я понятия не имею, как реализовать их в функции Turn (один рабочий пример — Blitz3D, у которого есть функция «RotateEntity» для глобального вращения, такого как glRotatef и «TurnEntity» для вращения, основанного на ориентации) Я думаю, что внутренняя функция работает так:
Я наконец-то решил проблему, переключившись на ношение матрицы для каждого корабля. Высота тона, рыскание и крен рассчитываются только при необходимости, что редко бывает. В заключение, glRotatef делает работу — вам нужно только применить его к уже повернутой матрице — и сохранить результат, чтобы изменение не пропало.
Следующий код — моя реализация структуры корабля, которая содержит x, y, z, Matrix [16], dx, dy, dz. (Обратите внимание, что все массивы кораблей должны быть инициализированы с помощью IdentityMatrix):
//*************************** Turn Ship **********************************
void TurnShip(long nr,float yaw, float pitch=0,float roll=0) {
//Turns ship by pitch, yaw and roll degrees.
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(&ship[nr].Matrix[0]);
glRotatef(yaw,0,1,0);
glGetFloatv(GL_MODELVIEW_MATRIX,&ship[nr].Matrix[0]);
glLoadMatrixf(&ship[nr].Matrix[0]);
glRotatef(pitch,1,0,0);
glGetFloatv(GL_MODELVIEW_MATRIX,&ship[nr].Matrix[0]);
glLoadMatrixf(&ship[nr].Matrix[0]);
glRotatef(roll,0,0,1);
glGetFloatv(GL_MODELVIEW_MATRIX,&ship[nr].Matrix[0]);
}
Функция загружает матрицу кораблей, хранящуюся в простом массиве с плавающей точкой, манипулирует ею и затем сохраняет ее обратно в массив. В графическом разделе игры этот массив будет загружен с помощью glLoadMatrixf и, следовательно, будет применен к кораблю без каких-либо хлопот или математики.
//*************************** Accelerate Ship relative to own orientation **
void AccelerateShip(long nr,float speedx,float speedy, float speedz)
{ //use speedz to move object "forward".
ship[nr].dx+= speedx*ship[nr].Matrix[0]; //accelerate sidewards (x-vector)
ship[nr].dy+= speedx*ship[nr].Matrix[1]; //accelerate sidewards (x-vector)
ship[nr].dz+= speedx*ship[nr].Matrix[2]; //accelerate sidewards (x-vector)
ship[nr].dx+= speedy*ship[nr].Matrix[4]; //accelerate upwards (y-vector)
ship[nr].dy+= speedy*ship[nr].Matrix[5]; //accelerate upwards (y-vector)
ship[nr].dz+= speedy*ship[nr].Matrix[6]; //accelerate upwards (y-vector)
ship[nr].dx+= speedz*ship[nr].Matrix[8]; //accelerate forward (z-vector)
ship[nr].dy+= speedz*ship[nr].Matrix[9]; //accelerate forward (z-vector)
ship[nr].dz+= speedz*ship[nr].Matrix[10]; //accelerate forward (z-vector)
}
Это лучшая часть того, что я выучил сегодня — часть, в которой учебные пособия часто не говорят вам, поскольку они все о математике — Я могу вытащить векторы, которые указывают вверх, влево и перед моим кораблем, прямо из матрицы. и применить на них ускорение, чтобы мой корабль мог двигаться влево, вправо, вверх, вниз, ускоряться и тормозить — и glRotatef заботится о них, чтобы они всегда обновлялись, и никакой математики на нашей стороне вообще не было 🙂
Других решений пока нет …