Как получить" стандартные " вращения из трех.js при использовании кватернионов?

Новичок участник stackoverflow, новичок 3D программист, и далеко от математики wiz... поэтому я постараюсь сформулировать этот вопрос как можно яснее, надеясь, что он имеет смысл, и надеясь на ответ, который не будет в миле над моей головой.

Я написал очень классное приложение, используя три.js, который позволяет пользователю летать через 3D-пространство и исследовать Солнечную систему. Модель полета свободно основана на Fly.Пример контроллера/расширение в трех.пакет js, который научил меня использовать кватернионы для сохраняя все вращения осей относительно друг друга. Летающая часть все работает отлично.

вот моя дилемма: при использовании кватернионов, как я могу вывести "нормальные" (я не знаю, как еще это назвать) значения вращения, чтобы определить, в каком направлении я смотрю? При использовании кватернионов структура "вращения" внутри объекта камеры остается на уровне 0,0,0. Поэтому, хотя я могу свободно летать в пространстве под любым углом, я не могу понять, как определить, в каком направлении я на самом деле смотрю. Есть встроенный в три.функция js или другой простой способ конвертировать это?

Я нашел несколько похожих, запутанных указателей в интернете, но ничего не могу расшифровать и использовать в трех.js. Спасибо.

2 ответов


Это хороший вопрос.

когда объект находится в ориентации по умолчанию, его можно считать смотрящим в направлении его внутренней, положительной оси Z. (Исключение составляет камера, который смотрит в направлении своего внутреннего отрицательный ось z.)

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

var zVec = new THREE.Vector3( 0, 0, 1 );
zVec.applyQuaternion( object.quaternion );

это вернет единичный вектор, указывающий в направлении, в котором объект "обращен".

Если объект является дочерним объектом другого повернутого объекта, то ситуация более сложная.

EDIT: обновлено для r.58. Спасибо @цзяньшуй.


// Pass the obj.quaternion that you want to convert here:
//*********************************************************
function quatToEuler (q1) {
    var pitchYawRoll = new THREE.Vector3();
     sqw = q1.w*q1.w;
     sqx = q1.x*q1.x;
     sqy = q1.y*q1.y;
     sqz = q1.z*q1.z;
     unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor
     test = q1.x*q1.y + q1.z*q1.w;
    if (test > 0.499*unit) { // singularity at north pole
        heading = 2 * Math.atan2(q1.x,q1.w);
        attitude = Math.PI/2;
        bank = 0;
        return;
    }
    if (test < -0.499*unit) { // singularity at south pole
        heading = -2 * Math.atan2(q1.x,q1.w);
        attitude = -Math.PI/2;
        bank = 0;
        return;
    }
    else {
        heading = Math.atan2(2*q1.y*q1.w-2*q1.x*q1.z , sqx - sqy - sqz + sqw);
        attitude = Math.asin(2*test/unit);
        bank = Math.atan2(2*q1.x*q1.w-2*q1.y*q1.z , -sqx + sqy - sqz + sqw)
    }
    pitchYawRoll.z = Math.floor(attitude * 1000) / 1000;
    pitchYawRoll.y = Math.floor(heading * 1000) / 1000;
    pitchYawRoll.x = Math.floor(bank * 1000) / 1000;

    return pitchYawRoll;
}        

// Then, if I want the specific yaw (rotation around y), I pass the results of
// pitchYawRoll.y into the following to get back the angle in radians which is
// what can be set to the object's rotation.

//*********************************************************
function eulerToAngle(rot) {
    var ca = 0;
    if (rot > 0)
        { ca = (Math.PI*2) - rot; } 
    else 
        { ca = -rot }

    return (ca / ((Math.PI*2)/360));  // camera angle radians converted to degrees
}