Как правильно вращать кватернион GLM?

Я хочу повернуть свою машину на 90 градусов влево в игре, которая у меня есть.

Когда я использую этот код:

            glm::quat rot(info.Rotation.w,info.Rotation.x,info.Rotation.y,info.Rotation.z);
glm::quat done(glm::rotate(rot,glm::eulerAngles(rot)+glm::vec3(90.0f,0.0,0.0)));
info.Rotation.x = done.x;
info.Rotation.y = done.y;
info.Rotation.z = done.z;
info.Rotation.w = done.w;

Машина получает странное вращение.

Тем не менее, следующие коды не изменяют вращение машины вообще (то, что я ожидал, просто чтобы быть уверенным, что GLM совместим с кватами из игры):

            glm::quat rot(info.Rotation.w,info.Rotation.x,info.Rotation.y,info.Rotation.z);
glm::quat done(rot);
info.Rotation.x = done.x;
info.Rotation.y = done.y;
info.Rotation.z = done.z;
info.Rotation.w = done.w;

и всякий раз, когда я пытаюсь это проверить, если вращение изменяется с ним:

            glm::quat rot(info.Rotation.w,info.Rotation.x,info.Rotation.y,info.Rotation.z);
glm::quat done(glm::rotate(rot,vec3(0.0,0.0,0.0)));
info.Rotation.x = done.x;
info.Rotation.y = done.y;
info.Rotation.z = done.z;
info.Rotation.w = done.w;

Вращение машины просто установлено на 0,0,0,0 оборота в игре. Я ожидал, что повороты останутся нетронутыми с этим кодом, потому что я ожидал, что следующий код повернёт машину на 90 градусов влево:

            glm::quat rot(info.Rotation.w,info.Rotation.x,info.Rotation.y,info.Rotation.z);
glm::quat done(glm::rotate(rot,vec3(90.0,0.0,0.0)));
info.Rotation.x = done.x;
info.Rotation.y = done.y;
info.Rotation.z = done.z;
info.Rotation.w = done.w;

но это не работает так, как я хочу. Он просто устанавливает вращение, а не добавляет его в «гниль».

Что я делаю неправильно?

7

Решение

Если вас не волнует замок карданного подвеса, чем это должно работать.

glm::quat rot(info.Rotation.w,info.Rotation.x,info.Rotation.y,info.Rotation.z);
glm::quat rot_euler_angles = glm::gtx::quaternion::eulerAngles(rot);
rot_euler_angles.x += 90;

glm::quat done(glm::rotate(rot,rot_euler_angles));
info.Rotation.x = done.x;
info.Rotation.y = done.y;
info.Rotation.z = done.z;
info.Rotation.w = done.w;

Я думаю, что это также верно

glm::vec3 rot(90.0*(float)M_PI/180.0, 0, 0);
info.Rotation = glm::normalize(info.Rotation * glm::quat(rot));

Кватернионы являются фантастическими, потому что они могут быть составлены, чтобы сделать очень сложные вращения.

0

Другие решения

[Хотя это не GLM, заказ кватернионов в умножении все еще довольно ясно, и это обычно проблема]

Я использовал такой код, чтобы избежать блокировки карданного подвеса (поскольку любое решение, вводящее блокировку карданного кодирования в код, который уже содержит кватернионы, слишком иронично, чтобы обдумывать).

Это код C, а QuaternionFromAngles () и QuaternionMultiply () перезаписывают цель первого параметра. world->axis6_input_rotation это просто Quaternionf_t. Входной сигнал поступает от 6-осевого контроллера, который является более свободной формой, чем симулятор вашего транспортного средства, если вы на самом деле не передаете векторы в своем коде.

typedef struct { float w, x, y, z; } Quaternionf_t;

void GuiMotion6axis(World_t *world, Port_t *port,
int x,  int y,  int z,
int xr, int yr, int zr)
{
// convert spaceball input to World->rotation (a quaternion)
//    Source http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToQuaternion/index.htm
const float scale = 0.0004; // should factor in the time delta it covers as well.
float xrf = (float)xr * scale;
float yrf = (float)yr * scale;
float zrf = (float)zr * scale;

QuaternionFromAngles(& world->axis6_input_rotation, xrf, yrf, zrf);
QuaternionMultiply(& world->rotation,  // worldrot = inputrot * worldrot
& world->axis6_input_rotation,  // a read-only use
& world->rotation               // a read-only use
);

world->position.x += (float)x * scale;  // really should factor in the
world->position.y += (float)y * scale;  //   elasped time.
world->position.z += (float)z * scale;
return;
}
0

По вопросам рекламы [email protected]