Преобразование поворота угла Эйлера в ось + угол

Моя цель — позволить пользователям загружать 3D-модели и размещать их с помощью веб-браузера. Для этого я использую BabylonJS, и он отлично работает. После этого я хочу, чтобы мои пользователи могли просматривать ту же модель в собственном приложении с тем же позиционированием, которое установлено с помощью веб-браузера. Фреймворк, который я использую для нативного приложения, — OpenSceneGraph (OSG). Моя проблема заключается в том, что я не могу заставить правильно работать вращение, чтобы OpenSceneGraph правильно отражал то, что происходит в BabylonJS.

Я использую углы Эйлера в BabylonJS, так как их легко понять пользователям веб-сайта (например, повернуть его на 90 градусов вокруг оси X, на 180 градусов вокруг оси Y и на 0 градусов вокруг Z; например, model.rotation = new BABYLON .Vec3(90,180,0)). Однако OSG использует функцию OpenGL glrotate(), для которой требуется ось вращения и угол поворота. Для этого я использую BabylonJS для создания кватерниона из углов Эйлера; а затем с помощью функции, которую я написал на основе примера Java на этой странице:

http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm

function getAxisAngle(){
    var q = BABYLON.Quaternion.RotationYawPitchRoll(m.rotation.y,     m.rotation.x, m.rotation.z),s,r={};
    /*Convert quaternion to axis+angle*/
    if(q.w > 1){
        q = q.normalise();
    }
    r.angle = BABYLON.Tools.ToDegrees(2 * Math.acos(q.w));
    s = Math.sqrt(1-q.w*q.w);
    if(s < 0.001){
       r.ax = q.x;
       r.ay = q.y;
       r.az = q.z;
    }else{
       r.ax = q.x / s;
       r.ay = q.y / s; 
       r.az = q.z / s;
    }
    return r;
}

Я понимаю, что фундаментальное различие между BJS и OSG заключается в том, что BJS — левосторонняя система координат; а OSG правша; поэтому я сделал OSG левосторонним, установив лицевую обмотку по часовой стрелке; и масштабирование оси z моих моделей на -1.

Он работает на базовом уровне, если я изолирую 1 ось за раз; например если я только вращаюсь вокруг оси Y; и не вращайте вокруг какой-либо другой оси - это выглядит нормально. Однако, если я попытаюсь объединить два или три угла Эйлера одновременно; Я не могу заставить его выглядеть так же в OSG.

Я читал, что углы Эйлера не рекомендуются; отчасти потому, что порядок, в котором вращение применяется к каждой оси, имеет значение. Это возможная причина?


person Reece    schedule 30.09.2016    source источник
comment
Я предполагаю, что, поскольку вы используете кватернионы на одном конце и используете углы Эйлера на другом конце, вы знакомы с разницей преимуществ между использованием кватернионов и углов Эйлера из-за Gimbal Lock. Если ваше приложение использует углы Эйлера для вращения по нескольким осям вращения и происходит блокировка карданного подвеса, ваши вращения перестают работать. Если вы предпочитаете продолжать использовать углы Эйлера для вращения вокруг своей оси, вам нужно будет ограничить их между ними, чтобы предотвратить блокировку карданного подвеса, например [-89,99, 89,99]. (...продолжение)   -  person Francis Cugler    schedule 30.09.2016
comment
(...продолжение) Причина блокировки карданного подвеса связана с тем, что 90 градусов или PI/4 являются прямым углом или ортогональны. Синус (90) или синус (PI/4) = 1, косинус (90) или косинус (PI/4) = 0, и поскольку тангенс = синус/косинус, здесь ваш тангенс не определен из-за деления на 0. Итак, когда вы вращаете объект на оси X на 90, затем на Y или Z либо на 90, либо на -90, что происходит, когда эти две оси становятся заблокированными, и когда вы снова начинаете вращаться от любой из двух заблокированных осей; функция не может определить, какую ось вращать. (...продолжение)   -  person Francis Cugler    schedule 30.09.2016
comment
(...продолжение) Вы можете просмотреть это видео, чтобы получить четкое представление о кватернионах, может быть, не столько математически, сколько визуально. youtube.com/watch?v=zc8b2Jo7mno   -  person Francis Cugler    schedule 30.09.2016
comment
@Francis Cugler Вы должны сделать это ответом.   -  person eldo    schedule 30.09.2016
comment
Да, я знаком с концепцией карданного замка и с тем, как кватернионы лучше в этом отношении. На самом деле я использую кватернионы и Эйлеры на одном конце и ось + угол на другом конце. Я просто использую кватернион в качестве формата обмена, из которого можно вычислить поворот оси + угол на основе углов Эйлера.   -  person Reece    schedule 30.09.2016


Ответы (1)


На мой взгляд, не пытайтесь сделать OSG левосторонней, а лучше переведите «логическое» значение ваших углов поворота и примените их к OSG так, как она предназначена для использования.

Поместите загруженную модель в osg::PositionAttitudeTransform (или MatrixTransform), а затем вычислите правильное вращение (отношение), чтобы применить к ней, объединив 2 кватерниона для 2 углов поворота, которые вы предоставляете пользователю.
Например, если вы рассмотрите «качку» как вращение вокруг оси X и «направление» вокруг оси Y, сделайте что-то вроде:

osg::Quat attitude = osg::Quat(pitchAngle, osg::X_AXIS) * osg::Quat(headAngle, osg::Y_AXIS);
transform->setAttitude(attitude);

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

person rickyviking    schedule 30.09.2016
comment
Спасибо за ваше предложение, попробуем и сообщим! - person Reece; 30.09.2016