Как рассчитать углы Эйлера по векторам вперед, вверх и вправо?

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

Факты:

  • Я использую Unity.
  • Я могу легко получить векторы вперед, вверх и вправо из любого вращения Quaternion.
  • Я не могу просто записать свои собственные углы Эйлера, изменить их и применить вращение через новый кватернион, потому что объект управляется физикой.
  • Я не очень хорошо разбираюсь в математике, если она не написана в коде (или псевдокоде), так что это было бы для меня наиболее полезно.
  • Мне было бы легче понять ответ в стиле C ++, но я могу разработать практически любой код.
  • Я НЕ пытаюсь заставить кого-нибудь написать код за меня! Я прошу только ответ в коде или псевдокоде, потому что я так и не научился читать обычные математические закорючки; Я программист, а не математик.
  • Unity использует левостороннюю систему координат. X = вправо, Y = вверх, Z = вперед.

Что я пытаюсь сделать:

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

Проблема:

Я могу полностью работать с Quaternion вплоть до момента, когда мне нужно приложить крутящий момент к твердым телам. Функция AddTorque эффективно работает с углами Эйлера, что означает, что я не могу использовать кватернионы. Я легко могу извлечь углы Эйлера из кватернионов, но они ненадежны и вызывают сильное разбухание тряпичной куклы.

Что мне нужно:

Мне нужно рассчитать надежные трехмерные углы Эйлера (например, те, которые не меняются с + на - «случайным образом») из векторов вперед, вверх и вправо. Я понимаю, что это немного сложно, но вот почему я спрашиваю здесь: мне не хватает знаний и опыта, чтобы решить эту проблему самостоятельно.

Учитывая, что сами векторы надежны, я не вижу причин, по которым нельзя было бы вычислить по ним надежные углы Эйлера. Кроме того, я не знаю, какой порядок вращения мне нужен или нужен для углов Эйлера, но я считаю, что позже его будет довольно легко изменить.

Любая помощь приветствуется!


person Clonkex    schedule 14.06.2014    source источник
comment
Я уже отвечал на подобные вопросы раньше; Я не думаю, что вы сможете реализовать решение, не разбираясь в математике. Извините, но физика такая.   -  person Beta    schedule 14.06.2014
comment
Может ты попробуешь меня. Я понимаю изрядную часть математики, но только когда пишу на языке кода.   -  person Clonkex    schedule 14.06.2014
comment
В видео на YouTube говорится, что вы эффективно задаете вектор крутящего момента в локальном кадре. твердого тела. Это не имеет ничего общего с углами Эйлера!   -  person Tobias    schedule 14.06.2014
comment
Хорошо, у вас есть аккуратный приемочный тест для функции преобразования?   -  person Beta    schedule 14.06.2014
comment
@Tobias Не прямо, нет. Однако вы пытаетесь использовать эту функцию, чтобы подтолкнуть твердое тело к вращению Quaternion и рассказать мне, как у вас дела. Эмм ... если тебе это удастся, можешь вообще-то рассказать мне, как у тебя дела? Мне бы очень понравилось, если бы был способ подтолкнуть твердое тело к вращению кватерниона с помощью этой функции! :)   -  person Clonkex    schedule 14.06.2014
comment
@Beta Вы имеете в виду простой тест, который служит для проверки того, работает ли код или нет? Ну да, но это Unity, так что я не думаю, что смогу вам легко его передать.   -  person Clonkex    schedule 14.06.2014
comment
Это слишком сложный тест, но, возможно, мы сможем с ним поработать. У вас есть какая-то пара ввода-вывода, которую он использует? Я спрашиваю, потому что существуют разные соглашения об углах Эйлера, и я не знаю, что такое Forward, Up and Right, поэтому мы должны перепроектировать тест.   -  person Beta    schedule 14.06.2014
comment
Хм ... хм, я могу понять математику, но я не понимаю термины анализа, которые вы используете. Все, что у меня есть, это пустой уровень с кубиком. Я назначаю ему тестовый сценарий, запускаю игру, а затем вращаю куб в редакторе, чтобы увидеть, соответствует ли вывод отладки сценария тому, что я ожидал. Unity использует левостороннее вращение. X = вправо, Y = вверх, Z = вперед. Надеюсь, это поможет.   -  person Clonkex    schedule 14.06.2014
comment
Это ваша идея простого теста? Мне очень жаль, но это безнадежно.   -  person Beta    schedule 14.06.2014
comment
@Beta Эй !! :( Это очень неприятно! Почему это плохой тест? Он чрезвычайно прост, легко настраивается и отлично справляется со своей задачей. Что в нем не так? Какая ваша основная область знаний, и вы думаете, что это безнадежно, когда для меня кажется, действительно хорошее начало?   -  person Clonkex    schedule 14.06.2014
comment
Я физик и программист, и приемочный тест, требующий 1) взаимодействия с пользователем, 2) запуска всего исполняемого файла, 3) невоспроизводимых тестовых данных и 4) бог знает, сколько вызовов тестируемой функции - это не крайне просто. Если вы хотите добиться этого, хорошо, попробуйте несколько небольших вращений вокруг разных осей (не все перпендикулярно), и для каждой запишите свое описание вращения, результирующие векторы [Вперед, вверх, вправо] , углы Эйлера и ваше описание результирующего движения модели, затем добавьте все это к своему вопросу, и, возможно, мы сможем это использовать.   -  person Beta    schedule 14.06.2014
comment
Ах, физик. Послушайте, я не вижу причин, по которым эти сложные и утомительные научные тесты необходимы. Мой способ сделать это значительно быстрее, чем ваш. Никаких вычислений вручную, никаких записей, просто нажмите F5 и посмотрите, работает ли это. Это действительно просто, если вы не разделите его на каждое действие, требуемое компьютером: это просто в том смысле, что мне нужно только щелкнуть Go и посмотреть, что произойдет. Это все, что мне нужно, и это все, что я хочу. Однако, глядя на то, что я только что сказал, с вашей точки зрения, я могу понять, почему вы сказали, что это безнадежно (мои тесты не воспроизводятся ... продолжение   -  person Clonkex    schedule 14.06.2014
comment
... любым способом, формой или формой, для начала). Я не дурак и хорошо знаю причины научного подхода к экспериментам. Но в данном случае я не просил кого-то проводить для меня эксперименты, я спрашивал, есть ли известный способ достижения конкретной цели. Я не ищу теоретического решения, я искал практическое (псевдокод считается практическим). А пока я просто перейду к Unity Answers и посмотрю, есть ли у них для меня более специфичный для Unity ответ. Если там никто не может помочь, тогда я подумаю о том, чтобы вернуться сюда. Спасибо, в любом случае.   -  person Clonkex    schedule 14.06.2014
comment
Я никогда этого не делал. Но вот как это выглядит для меня: вы можете соединить два заданных кватерниона с помощью Slerp. Найдите Slerp в course.cms.caltech.edu/cs171/quatut.pdf . Вы можете параметризовать t в нем как t(tSmooth), чтобы получить плавную кривую в зависимости от вашего сглаженного времени tSmooth, для которого вы можете рассчитать угловое ускорение (формула для угловой скорости приведена в документе). Угловое ускорение, выраженное в местных координатах, - это то, что вам нужно для AddTorque.   -  person Tobias    schedule 14.06.2014
comment
@Tobias Звучит очень полезно. Судя по всему, вы раньше не использовали Unity и даете более общий ответ. Просто чтобы вы знали, Unity имеет встроенную Slerp функцию для своих четверок. Ваш комментарий вселяет во меня большую надежду, потому что это позволит мне полностью работать с четвертями и никогда не придется пытаться получить углы Эйлера. Я не очень разбираюсь в математике, особенно когда пишу в стандартной форме (как в той статье), хотя, как ни странно, я действительно знаю, что такое лента Мебиуса, так как недавно был в университете на дне открытых дверей. Интересно, не могли бы вы дать полный ответ, который уточняет ... продолжение   -  person Clonkex    schedule 14.06.2014
comment
... подробнее о том, что мне нужно сделать, чтобы найти то угловое ускорение, о котором вы говорите. То есть в псевдокоде, как мне этого добиться? Моя самая большая проблема в том, что я недостаточно понимаю математические закорючки в бумаге. Если бы это было написано в коде, у меня было бы гораздо больше шансов понять это. Во всяком случае, пока что вы, кажется, лучше всего понимаете мою проблему, и я очень надеюсь, что вы можете мне помочь! : D   -  person Clonkex    schedule 14.06.2014
comment
@Tobias Просто перечитайте два моих последних комментария - сбивает с толку! Резюме того, что я пытался сказать: Unity имеет встроенную функцию Slerp, так что этот бит несложный, и мне понадобится ответ на основе кода (или на основе псевдокода), чтобы я его понял. Прямо сейчас я делаю все возможное, чтобы попытаться понять ваш комментарий, но я борюсь, потому что не знаю, что означает параметризация. Схожу в Google и вижу, что могу лучше понять.   -  person Clonkex    schedule 14.06.2014
comment
Мне это кажется на самом деле довольно простым. Для угловой скорости в глобальных координатах необходимо вычислить $ q_ {10}: = q_1 q_0 ^ {- 1} $ (Гамильтон-умножение). Это должен быть кватернион единицы (возможно, вам нужно нормализовать). Отсюда вы можете определить ось вращения $ v $ и необходимую скорость вращения в единицу времени $ \ Omega $. Вы можете использовать $ v $ для вращения, но вам нужно преобразовать его в локальный фрейм. Для начала сделайте это и приложите импульсный крутящий момент в этом направлении, чтобы посмотреть, что произойдет.   -  person Tobias    schedule 14.06.2014
comment
Возможно, в единстве уже существует какая-то функция для обращения кватернионов и умножения кватернионов.   -  person Tobias    schedule 14.06.2014
comment
@Tobias Нет, мне не хватает математических навыков, чтобы интерпретировать, как это должно выглядеть;) Однако в Unity есть встроенные функции для quat inverse и quat mult. Я не могу понять, что вы там делаете, но если бы я угадал ... вы понимаете разницу между двумя четвертями? Потому что у меня уже есть код для этого. Теперь я не понимаю, что мне нужно делать с четвереньками.   -  person Clonkex    schedule 14.06.2014
comment
q10 - это не разница. Это произведение q1 на обратное к q0. После этого нормализовать q10. (Unity должен иметь нормализацию.) Векторная часть - это направление вектора вращения. Норма векторной части - cos (Омега). Просто начните с векторной части, преобразуйте ее в локальные координаты и примените к ней крутящий момент. Посмотрите, вращается ли он хоть в правильном направлении.   -  person Tobias    schedule 14.06.2014
comment
@Tobias О, понятно! Хорошо, пора пройти тест. Отчитаюсь с результатами :)   -  person Clonkex    schedule 14.06.2014
comment
@Tobias Это работает !! Большое спасибо!! : D Если хотите, опубликуйте полный ответ, и я выберу его как ответ на вопрос, чтобы дать вам очки репутации, поскольку вы действительно решили мою проблему :)   -  person Clonkex    schedule 15.06.2014


Ответы (2)


Во-первых, я хотел бы сказать, что я решил свою проблему полностью благодаря усилиям @ Tobias. Огромное спасибо! Все это время я подходил к проблеме не с той стороны. Я предположил, что мне нужно использовать AddTorque определенным образом (с углами Эйлера), и работал оттуда, но @Tobias (и @JarkkoL чуть позже) указал, что мне нужно использовать AddTorque по-другому.

Вот что я сделал в UnityScript (по сути, JavaScript):

var quat0:Quaternion;
var quat1:Quaternion;
var quat10:Quaternion;
quat0=transform.rotation;
quat1=target.transform.rotation;
quat10=quat1*Quaternion.Inverse(quat0);
rigidbody.AddTorque(quat10.x,quat10.y,quat10.z,ForceMode.Force);

И, вопреки всем ожиданиям, это РАБОТАЕТ !! Просто ... работает! Конечно, кубу с твердым телом требуется много времени, чтобы успокоиться, но это потому, что мне нужен ПИД-регулятор. Или, может быть, quat10 нужна нормализация, не уверен. Я разберусь :)

Я понятия не имел, что вы действительно можете использовать эту часть четверостиший отдельно.

person Clonkex    schedule 15.06.2014
comment
Да, если вы посмотрите литературу о единичных кватернионах для представления трехмерных вращений, вы обнаружите, что q = [v * sin (angle / 2), cos (angle / 2)], где v = трехмерная ось вращения (unit вектор) и angle = угол поворота вокруг оси. - person JarkkoL; 15.06.2014
comment
@JarkkoL Итак ... то, что я никогда не понимал о кватернионах, - это почему они лучше, чем просто старое представление осевого угла (которое, похоже, не вызывает у меня проблем)? Они просто лучше для расчетов что ли? - person Clonkex; 15.06.2014
comment
Да, к кватернионам можно применить целый класс математических операций. Например, если вам нужно объединить повороты (например, для выполнения иерархических преобразований), вы просто умножаете два кватерниона, как в случае с матрицами. - person JarkkoL; 15.06.2014
comment
В документации написано, что тело начнет вращаться вокруг глобальной оси, пока на YouTube говорят, что крутящий момент применяется к локальная ось. Версия для YouTube означает, что вам нужно преобразовать вектор крутящего момента в локальные координаты. Подробнее об этом в следующем комментарии. Обе версии согласны с гниением вокруг одной оси вращения. Они различаются для составных частей по нескольким осям. - person Tobias; 15.06.2014
comment
q0 - это ориентация рамы в момент времени, когда вы хотите приложить крутящий момент. Чтобы преобразовать вектор крутящего момента q10 в координаты относительно q0 вы можете умножить Inverse (q0) * q10 * q0. Предыстория: представьте себе представление q10 w.r.t. q0 как поворот q10 назад с помощью Inverse (q0), который просто дает Inverse (q0) * q1 * Inverse (q0) * q0 = Inverse (q0) * q1. (Кватернионы как вращения и однородные координаты) - person Tobias; 15.06.2014
comment
Попробуйте модифицированную версию quat10=Quaternion.Inverse(quat0)*quat1; с поворотами на несколько осей. Если это сработает, вы можете отметить свой ответ как решение. После этого вопрос появится в списке вопросов с ответом. - person Tobias; 15.06.2014
comment
@Tobias с этой модифицированной версией тестовый куб сначала вращается под правильным углом, но сразу после того, как он, кажется, оседает, он быстро становится нестабильным и начинает дико вращаться, не останавливаясь. quat10=quat1*Quaternion.Inverse(quat0); действительно работает лучше. Также имейте в виду, что существует две версии функции AddTorque - AddTorque и AddRelativeTorque. Вы могли смотреть не на ту; Я использую AddTorque без преобразования quat10 в любую другую систему отсчета. - person Clonkex; 15.06.2014
comment
Интересно, потому что они также используют AddTorque в видео на YouTube. Но у меня нет опыта работы с Unity. Так что это была всего лишь догадка. В любом случае спасибо за тестирование. arcsin скалярного компонента quat10 должен дать вам угол, на который вам нужно повернуться. Если вы зададите это как шаг угловой скорости и примените противоположный шаг угловой скорости через единицу времени (без сопротивления), вы должны сразу приземлиться на quat1. Удачи. - person Tobias; 15.06.2014
comment
@Tobias Спасибо! У меня настроена система ПИД-регулятора, и в настоящее время я настраиваю значения, чтобы она работала оптимально :) - person Clonkex; 15.06.2014

Во-первых, я думаю, вам больше повезет на форумах Unity для конкретных вопросов Unity (: Тем не менее, я думаю, что вы неправильно интерпретируете интерфейс AddTorque (), если это то, что вы используете: http://docs.unity3d.com/ScriptReference/Rigidbody.AddTorque.html

Вместо того, чтобы передавать углы Эйлера, вы передаете вектор функции, являющейся осью вращения. Я не знаком с Unity, но считаю, что длина вектора определяет, какой крутящий момент нужно добавить. Углы Эйлера по своей сути являются плохим представлением вращений, поэтому вы всегда должны предполагать (если иное не задокументировано), что хорошо зарекомендовавшие себя API работают с кватернионами, парами осей / углов или матрицами, когда дело доходит до вращений. Углы Эйлера более удобны для конечных пользователей.

person JarkkoL    schedule 14.06.2014
comment
На самом деле я не верю, что мне повезет больше с Unity Answers - там культура даже близко не приближается к SO, и, похоже, очень мало экспертов. По функции AddTorque(): вы правы. Функция действительно работает с вектором. Проблема заключалась в том, как определить, что это был за вектор. Я собираюсь ответить на свой вопрос, так что вы увидите, что я в итоге сделал :) - person Clonkex; 15.06.2014