Повернуть корень анимации BVH вокруг оси Y на угол
Даже если вы не знакомы с форматом файлов BVH, возможно, вы могли бы помочь мне в том, как объединить два поворота.
Я просто беру поворот корня (копируя значения x,y,z) из файла BVH, чтобы каналы корня были установлены следующим образом:
CHANNELS 6 Xposition Yposition Zposition Zrotation Xrotation Yrotation
И я хочу, чтобы поворот корня на несколько градусов мог быть от 0 до 360, вокруг оси y (0,1,0). Это вращение работает в некоторых кадрах. Тем не менее, на большинстве кадров рут странно вращается (это похоже на то, что произошла блокировка карданного подвеса).
Это код, который я использую. C# в Unity. Я просто хочу правильно применить вращение корня вокруг оси Y.
Я могу подтвердить, что код работает нормально (корректная анимация BVH) при добавлении вращения на 0 градусов вокруг оси y. Таким образом, ошибка должна заключаться в комбинации этих двух поворотов (qBefore и YawRotationQuaternion).
private Vector3 getFinalRootRotation(Vector3 rotationFromBvh, float angle)
{
// [INITIALIZE]: Convert Euler to Quaternion for each axis.
Quaternion qX = Quaternion.AngleAxis(rotationFromBvh.x, Vector3.right);
Quaternion qY = Quaternion.AngleAxis(rotationFromBvh.y, Vector3.up);
Quaternion qZ = Quaternion.AngleAxis(rotationFromBvh.z, Vector3.forward);
Quaternion qBefore = qY * qX * qZ; // Multiply them in the correct order.
// Order in BVH file is ZXY.
qY*qX*qZ
имеет те же результаты, что и эйлер x,y,z Quaternion.Euler(rotationFromBvh)
// [CREATE ROTATION AROUND Y]: Get the quaternion of rotating around y axis.
Quaternion YawRotationQuaternion = Quaternion.AngleAxis(angle, Vector3.up);
// [APPLY ROTATION AROUND Y]
Quaternion qAfter = qBefore * YawRotationQuaternion;
// [RETURN IN XYZ FORM]
return qAfter.eulerAngles;
}
Моя цель - создать новый BVH с новым поворотом корня. Это часть кода, где я пишу новый поворот в файле. Этот код протестирован и создает файл BVH нормально.
private string CreateMLine(Vector3 rootPosition, Vector3 rootRotation, List<Vector3> rotations)
{
StringBuilder s = new StringBuilder();
// Apply root's translation and rotation.
s.Append(rootPosition.x + " " + rootPosition.y + " " + rootPosition.z + " ");
s.Append(rootRotation.z + " " + rootRotation.x + " " + rootRotation.y + " ");
for(int i=1; i<rotations.Count; i++) // start at 1 ==> skip rotation of the root.
{
s.Append(rotations[i].z + " " + rotations[i].x + " " + rotations[i].y + " ");
}
s.Append("\n");
return s.ToString();
}
2 ответа
Я бы сказал, что вы получаете значения BVH в порядке Zrotation Xrotation Yrotation
по уважительной причине.
Вращение, которое вращает euler.z градусов вокруг оси z, euler.x градусов вокруг оси x и euler.y градусов вокруг оси y (в этом порядке).
Так что я думаю, что ошибка заключается в
Quaternion qBefore = qY * qX * qZ;
который использует неправильный порядок.
скорее должно быть
Quaternion qBefore = qZ * qX * qY;
Я бы предложил вместо этого использовать Quaternion.Euler
Возвращает вращение, которое вращает z градусов вокруг оси z, x градусов вокруг оси x и y градусов вокруг оси y.
Quaternion qBefore = Quaternion.Euler(rotationFromBvh.x, rotationFromBvh.y, rotationFromBvh.z);
Физически умножение кватернионов означает применение поворота справа налево.
q1 * q2 означает поворот на q2, а затем на q1
Поэтому, если вы хотите применить вращение после другого, поместите его с левой стороны.
В вашем случае это должно быть:
Quaternion qAfter = YawRotationQuaternion * qBefore;