Нахождение кратчайшего вращения между кватернионами - PullRequest
0 голосов
/ 10 января 2020

Моя проблема:

Я пытаюсь выровнять Gameobject A с вращением GameObject B, хотя важная деталь в том, что GoA может либо выровнять 1: 1 с вращением GoB, либо обратное вращению GoB (ie. Рука, берущая карандаш кончиком вверх или противоположной стороной вниз).

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

Пример:

Сценарий A и B, где красная линия представляет GoA, а черная линия представляет GoB

В приведенном выше примере сценария A красная линия (GoA) должна найти ближайшее вращение как 1: 1 с черной линией (GoB), тогда как в сценарии B красная линия должна найти ближайшее вращение в качестве обратная к черной линии.

Это решение должно работать в трехмерном пространстве и избегать блокирования gimble.

Большое спасибо за любую помощь, если потребуется дополнительная информация, я отредактирую это на этот оригинальный пост! * 101 7 *

Спасибо,

Тим

1 Ответ

0 голосов
/ 10 января 2020

Зависит от того, что вы подразумеваете под «ближе».

Предположим, что цель находится в комнате с дверью и windows напротив нее.

Цель находится вертикально и смотрит на дверь, а обратная цель смотрит на windows, но вверх ногами.

Объект смотрит между дверью и windows, только чуть ближе к windows и находится в вертикальном положении.

Какой кандидат "ближе" для ваших нужд?


Если вы считаете, что цель здесь «ближе», поскольку объект уже находится в вертикальном положении, и вы заботитесь обо всей разнице вращения между объектом и целью, вы можете использовать Quaternion.Angle, чтобы определить, какая имеет меньшее отличие от поворота идентификатора:

Transform target;
Transform subject;

Quaternion subjectRot = subject.rotation;
Quaternion targetRot = target.rotation;

// however you define "inverse" here
Qutaternion invTargetRot = targetRot * Quaternion.Euler(180f,0f,0f);

float angleToTarget = Quaternion.Angle(subjectRot, targetRot);
float angleToInvTarget = Quaternion.Angle(subjectRot, invTargetRot);

if (angleToTarget <= angleToInvTarget) 
{
    // alignment with target is closer
}
else 
{
    // alignment with inverse of target is closer
}

Если вы считаете, что обратная цель здесь «ближе», потому что вы заботитесь только об одном местном направлении объекта / цели (например, вперед) и не заботятся о других (например, вверх / вправо), тогда вы можете просто использовать Vector3.Angle для сравнения направлений, и если угол меньше 90 градусов, он ближе к выравниванию:

Transform target;
Transform subject;

// or *.up, or *.right depending on your needs
float angleToTarget = Vector3.Angle(subject.forward, target.forward);

if (angleToTarget <= 90f) 
{
    // alignment with target is closer
}
else 
{
    // alignment with inverse of target is closer
}
...