2015-10-17 3 views
1

Я пытаюсь сделать эквивалент умножения скорости на время между кадрами. Я бы предположил, что сделать это для кватернионов будет сделано, привлекая их к власти. У меня есть код для поворота объекта на основе движений мыши. Он имеет основной цикл, работающий с одной частотой кадров, и физический цикл, работающий с фиксированной частотой кадров. Вот соответствующая часть главного цикла:Как масштабировать поворот кватерниона

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(); 

Это прекрасно работает, но при попытке повышения угловой скорости к мощности с ГЖС :: pow, объект вращается случайным образом и не следует за моей мышью. Я понимаю, что мог бы сделать это с помощью строки кода, например

rigidBodies[i].transform->getRot() *= glm::angleAxis((float)Time::getFixedDelta() * glm::angle(rigidBodies[i].angularVelocity), glm::axis(rigidBodies[i].angularVelocity)); 

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

+0

Не существует уникального квадратного корня кватерниона или вращения. Вращение на 10 градусов может составлять два оборота 5 градусов или два оборота 185 градусов. Оба, когда они составлены, производят поворот на 10 градусов. В общем случае n-й корень вращения k градусов представляет собой множество x 360/n + k/n для x от 0 до n-1. Я не знаю, что делает ваша библиотека, я просто указываю, что математика неоднозначна. – Yakk

ответ

1

Не уверен точно, как это сделать с использованием API, который вы используете, но в основном вы бы использовали Quaternion :: Slerp(). Slerp означает «сферическая линейная интерполяция».

Что-то вроде этого (псевдокод) должно работать:

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

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


Edit:
я должен отметить, что это не так, как я бы подойти к этой проблеме. Я бы просто сохранил вращение вокруг оси 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); 
} 
+0

Прошу прощения за то, что я не говорю, какой API я использую. Время - это класс, который я реализовал, и так преображается. Я использую математическую библиотеку GLM, и это важно для этого. Я хочу избежать поворотов x и y, потому что Euler Angles, потому что это должно работать для всех объектов физики. – msik314

+0

поэтому используйте первое решение – bitwise

+0

Это решение работает до определенной точки, но когда я получаю выше определенной угловой скорости, он также становится неустойчивым, а – msik314

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.