/// <summary> /// Return the FRotator orientation corresponding to the direction in which the vector points. /// Sets Yaw and Pitch to the proper numbers, and sets roll to zero because the roll can't be determined from a vector. /// </summary> /// <returns>FRotator from the Vector's direction.</returns> public FRotator ToOrientationRotator() { FRotator r; // Find yaw. r.Yaw = FMath.Atan2(Y, X) * (180.0f / FMath.PI); // Find pitch. r.Pitch = FMath.Atan2(Z, FMath.Sqrt(X * X + Y * Y)) * (180.0f / FMath.PI); // Find roll. r.Roll = 0; r.DiagnosticCheckNaN("FVector4::Rotation(): Rotator result " + r + " contains NaN! Input FVector4 = " + this); return(r); }
/// <summary> /// Get the FRotator representation of this Quaternion. /// </summary> public FRotator Rotator() { DiagnosticCheckNaN(); float singularityTest = Z * X - W * Y; float yawY = 2.0f * (W * Z + X * Y); float yawX = (1.0f - 2.0f * (FMath.Square(Y) + FMath.Square(Z))); // reference // http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/ // this value was found from experience, the above websites recommend different values // but that isn't the case for us, so I went through different testing, and finally found the case // where both of world lives happily. const float singularityThreshold = 0.4999995f; const float radToDeg = (180.0f) / FMath.PI; FRotator rotatorFromQuat; if (singularityTest < -singularityThreshold) { rotatorFromQuat.Pitch = -90.0f; rotatorFromQuat.Yaw = FMath.Atan2(yawY, yawX) * radToDeg; rotatorFromQuat.Roll = FRotator.NormalizeAxis(-rotatorFromQuat.Yaw - (2.0f * FMath.Atan2(X, W) * radToDeg)); } else if (singularityTest > singularityThreshold) { rotatorFromQuat.Pitch = 90.0f; rotatorFromQuat.Yaw = FMath.Atan2(yawY, yawX) * radToDeg; rotatorFromQuat.Roll = FRotator.NormalizeAxis(rotatorFromQuat.Yaw - (2.0f * FMath.Atan2(X, W) * radToDeg)); } else { rotatorFromQuat.Pitch = FMath.FastAsin(2.0f * (singularityTest)) * radToDeg; rotatorFromQuat.Yaw = FMath.Atan2(yawY, yawX) * radToDeg; rotatorFromQuat.Roll = FMath.Atan2(-2.0f * (W * X + Y * Z), (1.0f - 2.0f * (FMath.Square(X) + FMath.Square(Y)))) * radToDeg; } rotatorFromQuat.DiagnosticCheckNaN("FQuat::Rotator(): Rotator result " + rotatorFromQuat + " contains NaN! Quat = " + this.ToString() + ", YawY = " + yawY + ", YawX = " + yawX); return(rotatorFromQuat); }
/// <summary> /// Return the Quaternion orientation corresponding to the direction in which the vector points. /// </summary> /// <returns>Quaternion from the Vector's direction.</returns> public FQuat ToOrientationQuat() { // Essentially an optimized Vector->Rotator->Quat made possible by knowing Roll == 0, and avoiding radians->degrees->radians. // This is done to avoid adding any roll (which our API states as a constraint). float yawRad = FMath.Atan2(Y, X); float pitchRad = FMath.Atan2(Z, FMath.Sqrt(X * X + Y * Y)); float divideByTwo = 0.5f; float sp, sy; float cp, cy; FMath.SinCos(out sp, out cp, pitchRad * divideByTwo); FMath.SinCos(out sy, out cy, yawRad * divideByTwo); FQuat rotationQuat; rotationQuat.X = sp * sy; rotationQuat.Y = -sp * cy; rotationQuat.Z = cp * sy; rotationQuat.W = cp * cy; return(rotationQuat); }