Множення
Принаймні з точки зору реалізації Unity Quaternions, порядок множення, описаний у запитанні, не є правильним. Це важливо, оскільки обертання 3D не є комутативним .
Отже, якщо я хочу обертати об'єкт, rotationChange
починаючи з його, currentOrientation
я напишу його так:
Quaternion newOrientation = rotationChange * currentOrientation;
(тобто. Перетворення складаються вліво - те саме, що і матрична конвенція Unity. Найправіше обертання застосовується спочатку / на "найбільш локальному" кінці)
І якби я хотів перетворити вектор напрямку чи зміщення обертанням, я б написав це так:
Vector3 rotatedOffsetVector = rotationChange * currentOffsetVector;
(Unity створить помилку компіляції, якщо ви зробите навпаки)
Змішування
У більшості випадків ви можете піти від обертів Лерпінга. Це тому, що кут, що використовується «під капотом» у кватерніоні, - це половина кута повороту, що робить його істотно ближчим до лінійного наближення Лерпа, ніж щось подібне до Матриці (що взагалі не буде Лерпа добре!). Перегляньте приблизно 40 хвилин цього відео, щоб отримати додаткові пояснення .
Єдиний випадок, коли вам дійсно потрібен Slerp, це коли вам потрібна послідовна швидкість у часі, як інтерполяція між ключовими кадрами на часовій шкалі анімації. У випадках, коли вам просто важливо, щоб вихід був проміжним між двома входами (наприклад, змішування шарів анімації), зазвичай Lerp служить досить добре.
Що ще?
Скалярний твір двох одиничних кватерніонів дає косинус кута між ними, так що ви можете використовувати продукт крапки в якості міри схожості , якщо вам потрібно порівняти ротацію. Це трохи незрозуміло, тому для більш розбірливого коду я часто використовую Quaternion.Angle (a, b) замість цього, що більш чітко виражає, що ми порівнюємо кути, у знайомих одиницях (градусах).
Такі типи зручностей, які Unity забезпечує для Quaternions, дуже корисні. Майже в кожному проекті я використовую цей принаймні кілька разів :
Quaternion.LookRotation(Vector3 forward, Vector3 up)
Це створює кватерніон, який:
- обертає локальну вісь z +, щоб вказувати точно вздовж
forward
векторного аргументу
- обертає локальну вісь y +, щоб вказувати якомога ближче до
up
векторного аргументу, якщо він наданий, або до того, (0, 1, 0)
якщо його не було
Причиною "вгору" стає "як можна ближче" є те, що система переопределена. Облицювання z + до forward
використання двох ступенів свободи (тобто позіхання і крок), тому у нас залишається лише один ступінь свободи (рулон).
Мені досить часто здається, що я хочу щось із властивостями, що мають протилежну точність: я хочу, щоб локальний y + вказував точно уздовж up
, а локальний z + максимально наблизився до forward
решти свободи.
Це з'являється, наприклад, при спробі сформувати відносно камери координатний кадр для введення руху: я хочу, щоб мій локальний напрямок вгору залишався перпендикулярним до підлоги чи похилої поверхні нормальним, тому мій вхід не намагається тунель персонажа на місцевість або левити їх від цього.
Ви також можете отримати це, якщо хочете, щоб корпус башти танка стикався з ціллю, не відколюючись від тіла танка, коли прицілювався вгору / вниз.
Ми можемо створити власну функцію зручності для цього, використовуючи LookRotation
для важкого підйому:
Quaternion TurretLookRotation(Vector3 approximateForward, Vector3 exactUp)
{
Quaternion rotateZToUp = Quaternion.LookRotation(exactUp, -approximateForward);
Quaternion rotateYToZ = Quaternion.Euler(90f, 0f, 0f);
return rotateZToUp * rotateYToZ;
}
Тут ми спочатку обертаємо локальні y + to z +, а локальні z + to y-.
Тоді ми повертаємо новий z + до нашого напрямку вгору (таким чином, чистий результат є локальним y + точок прямо вздовж exactUp
), а новий y + максимально наближений до запереченого напрямку вперед (тому чистий результат є локальним z + точок, як можна ближче уздовж approximateForward
)
Ще один зручний метод зручності Quaternion.RotateTowards
, який я часто використовую так:
Quaternion newRotation = Quaternion.RotateTowards(
oldRotation,
targetRotation,
maxDegreesPerSecond * Time.deltaTime
);
Це дозволяє нам увімкнутись targetRotation
із послідовною, керованою швидкістю незалежно від частоти кадрів - важливо для обертів, які впливають на результат / справедливість механіки ігрового процесу (як, наприклад, повернення руху персонажа чи відстеження башти гравця). Наївно Лерпінг / Сперпінг у цій ситуації може легко призвести до випадків, коли рух стає сприятливішим у високих рамках, впливаючи на ігровий баланс. (Це не означає, що ці методи неправильні - є способи їх правильного використання, не змінюючи справедливості. Це просто вимагає обережності. RotateTowards
Дає зручний ярлик, який береться за це для нас)
n
різні орієнтації (ставлення, пози тощо). Тоді ви можете їх порівняти за допомогою ваг, ефективно узагальнюючи slerp / lerp. Ви також можете перетворити кватерніон у ротор, що еквівалентно застосуванню кутової швидкості протягом певного часу до жорсткого тіла. Отже, ви можете описати інтеграцію кутових швидкостей також з кватерніонами. Ви також можете оцінити, наскільки дві орієнтації відрізняються (обчисліть довжину дуги, що охоплюється двома кватерніонами на гіперсфері).