Hello all,
I am currently working with a firm where I am developing a program that will convert their old assets to a new format, FBX. I am currently working on the skeletal meshes and I have a small bug that is taking me awhile to track down. For this model, there is a random bone rotation and one of the legs is misplaced. I am thinking that it has to do with my calculation of the Quat to Euler. I just need a second pair of eyes to take a look and check if I am converting the values correctly. Please let me know!
SWGMainObject::EulerAngles SWGMainObject::ConvertCombineCompressQuat(Geometry::Vector4 DecompressedQuaterion, Skeleton::Bone BoneReference, bool isStatic)
{
const double pi = 3.14159265358979323846;
double rotationFactor = 180.0 / pi;
Geometry::Vector4 Quat;
EulerAngles angles;
FbxQuaternion AnimationQuat = FbxQuaternion(DecompressedQuaterion.x, DecompressedQuaterion.y, DecompressedQuaterion.z, DecompressedQuaterion.a);
FbxQuaternion bind_rot_quat{ BoneReference.bind_pose_rotation.x, BoneReference.bind_pose_rotation.y, BoneReference.bind_pose_rotation.z, BoneReference.bind_pose_rotation.a };
FbxQuaternion pre_rot_quat{ BoneReference.pre_rot_quaternion.x, BoneReference.pre_rot_quaternion.y, BoneReference.pre_rot_quaternion.z, BoneReference.pre_rot_quaternion.a };
FbxQuaternion post_rot_quat{ BoneReference.post_rot_quaternion.x, BoneReference.post_rot_quaternion.y, BoneReference.post_rot_quaternion.z, BoneReference.post_rot_quaternion.a };
auto full_rot = post_rot_quat * (AnimationQuat * bind_rot_quat) * pre_rot_quat;
Quat = Geometry::Vector4(full_rot.mData[0], full_rot.mData[1], full_rot.mData[2], full_rot.mData[3]);
double test = Quat.x * Quat.z - Quat.y * Quat.a;
double sqx = Quat.x * Quat.x;
double sqy = Quat.y * Quat.y;
double sqz = Quat.z * Quat.z;
double sqa = Quat.a * Quat.a;
double unit = sqx + sqy + sqz + sqa;
// roll (x-axis rotation)
double sinr_cosp = 2.0 * (Quat.a * Quat.x + Quat.y * Quat.z);
double cosr_cosp = Quat.a * Quat.a - Quat.x * Quat.x - Quat.y * Quat.y + Quat.z * Quat.z;
angles.roll = std::atan2(sinr_cosp, cosr_cosp);
// pitch (y-axis rotation)
double sinp = 2.0 * (Quat.a * Quat.y - Quat.z * Quat.x);
if (std::abs(sinp) >= 1)
angles.pitch = std::copysign(pi / 2.0, sinp); // use 90 degrees if out of range
else
angles.pitch = std::asin(sinp);
// yaw (z-axis rotation)
double siny_cosp = 2.0 * (Quat.a * Quat.z + Quat.x * Quat.y);
double cosy_cosp = Quat.a * Quat.a + Quat.x * Quat.x - Quat.y * Quat.y - Quat.z * Quat.z;
angles.yaw = std::atan2(siny_cosp, cosy_cosp);
//angles.yaw = std::atan2(2.0 * (Quat.x * Quat.y + Quat.z * Quat.a), sqx - sqy - sqz + sqa); // heading
//angles.pitch = std::asin(-2.0 * test / unit); // attitude
//angles.roll = std::atan2(2.0 * (Quat.y * Quat.z + Quat.x * Quat.a), -sqx - sqy + sqz + sqa); // bank
/*double test = Quat.x * Quat.y + Quat.z * Quat.a;
if (test < 0.499)
{
angles.yaw = 2.0 * std::atan2(Quat.x, Quat.a);
angles.pitch = pi / 2.0;
angles.roll = 0;
}
else if (test < -0.499)
{
angles.yaw = -2.0 * std::atan2(Quat.x, Quat.a);
angles.pitch = -pi / 2.0;
angles.roll = 0;
}
else
{
double sqx = Quat.x * Quat.x;
double sqy = Quat.y * Quat.y;
double sqz = Quat.z * Quat.z;
angles.yaw = std::atan2(2.0 * Quat.y * Quat.a - 2.0 * Quat.x * Quat.z, 1.0 - 2.0 * sqy - 2.0 * sqz);
angles.pitch = std::asin(2.0 * test);
angles.roll = std::atan2(2.0 * Quat.x * Quat.a - 2.0 * Quat.y * Quat.z, 1.0 - 2.0 * sqx - 2.0 * sqz);
}*/
/*FbxVector4 zeroVector(0, 0, 0);
FbxQuaternion testQuat(Quat.x, Quat.y, Quat.z, Quat.a);
FbxMatrix testMatrix;
testMatrix.SetTQS(zeroVector, testQuat, zeroVector);
EulerAngles testAngles;
FbxVector4 returnVector = testMatrix.GetColumn(0);
testAngles.roll = returnVector[0] * rotationFactor;
testAngles.pitch = returnVector[1] * rotationFactor;
testAngles.yaw = returnVector[2] * rotationFactor;*/
angles.roll *= rotationFactor;
angles.pitch *= rotationFactor;
angles.yaw *= rotationFactor;
return angles;
}