如何缩放四元数的旋转

时间:2015-10-17 02:58:39

标签: c++ opengl glm-math

我试图相当于将速度乘以帧之间的时间。我想这样做四元数就可以通过提升它们来实现。我有基于鼠标移动旋转对象的代码。它有一个以一帧速率运行的主循环和一个以固定帧速率运行的物理循环。这是主循环的相关部分:

glfwPollEvents();
Input::update();
window.clear(0,0,0,1);

rigidBody.angularVelocity *= glm::angleAxis(0.001f * Input::deltaMouse().x, glm::vec3(0,1,0));
rigidBody.angularVelocity *= glm::angleAxis(0.001f * Input::deltaMouse().y, glm::vec3(1,0,0));

if(Input::getKey(Input::KEY_A))
{
    rigidBody.velocity -= float(Time::getDelta()) * glm::vec3(1,0,0);
}
if(Input::getKey(Input::KEY_D))
{
    rigidBody.velocity += float(Time::getDelta()) * glm::vec3(1,0,0);
}
if(Input::getKey(Input::KEY_W))
{
    rigidBody.velocity -= float(Time::getDelta()) * glm::vec3(0,0,1);
}
if(Input::getKey(Input::KEY_S))
{
    rigidBody.velocity += float(Time::getDelta()) * glm::vec3(0,0,1);
}
if(Input::getKey(Input::KEY_LCONTROL))
{
    rigidBody.velocity -= float(Time::getDelta()) * glm::vec3(0,1,0);
}
if(Input::getKey(Input::KEY_LSHIFT))
{
    rigidBody.velocity += float(Time::getDelta()) * glm::vec3(0,1,0);
}

以下是物理循环的相关部分:

for(int i = 0; i < *numRigidBodies; i++)
{
    rigidBodies[i].transform->getPos() += rigidBodies[i].velocity;
    rigidBodies[i].transform->getRot() *= rigidBodies[i].angularVelocity;
}
rigidBodies[0].angularVelocity = glm::quat();
rigidBodies[0].velocity = glm::vec3();

这很好用,但是当我尝试使用glm :: pow将角速度提高到一个幂时,对象随机旋转并且不跟随我的鼠标。我意识到我可以使用像

这样的代码行来做到这一点
rigidBodies[i].transform->getRot() *= glm::angleAxis((float)Time::getFixedDelta() * glm::angle(rigidBodies[i].angularVelocity), glm::axis(rigidBodies[i].angularVelocity));

但这对任务来说似乎毫无疑问。是什么导致了这个问题,我该如何解决?

2 个答案:

答案 0 :(得分:1)

不确定如何使用您正在使用的API,但基本上,您将使用Quaternion :: Slerp()。 Slerp表示“球形线性插值”。

像这样的东西(伪代码)应该可以工作:

auto& rot = rigidBodies[i].transform->getRot();

auto goal = rigidBodies[i].angularVelocity * rot;
rot = rot.slerp(rot, goal, Time::deltaTime);


修改
我应该注意,这不是我将如何处理这个问题。我只是将围绕X和Y轴的旋转存储为标量,并从每个帧构造一个新的四元数。

请原谅伪造的伪代码:

// previous x and y positions, could probably be set in MouseDown event
float lastX = ...; 
float lastY = ...;

float xRotation = 0;
float yRotation = 0;

float rotationSpeed = 1.0;

void OnMouseMove(float x, float y) {
    float dx = x - lastX;
    float dy = y - lastY;
    lastX = x;
    lastY = y;

    xRotation += dy * rotationSpeed * Time::deltaTime;
    yRotation += dx * rotationSpeed * Time::deltaTime;

    rigidBodies[i].transform->getRot() = eulerQuat(xRotation, yRotation, 0);
}

答案 1 :(得分:0)

结果表示角速度通常表示为3d矢量,其中矢量是轴,幅度是角速度。这行代码:

rigidBodies[i].transform->getRot() *= rigidBodies[i].angularVelocity;

用这个:

if(rigidBodies[i].angularVelocity != glm::vec3())
    rigidBodies[i].transform->getRot() *= glm::quat(rigidBodies[i].angularVelocity * float(Time::getFixedDelta()));

并且物理系统按预期工作。 if检查确保角速度不为0.