Better version of FindLookAtRotation

FindLookAt Rotation under the hood is MakeRotFromX(Target - Start) and always returns a roll of zero. What I want is a better version of this equation that avoids a yaw flip from 180 to -180 at pitch -90 and 90. If anyone has strong math and could make a version that uses quaternions under the hood to avoid this problem It would be greatly appreciated.

Here is another post another description of the issue.

My guess is its something to do with gimbal lock and could be avoided with quaternions.

I have found somewhat of a fix to the problem here, by changing the order of the calulation, pitch works now, but then it flips on another axis.

Any links to better understand this issue would be appreciated.

I have sense found the solution to the problem. It is impossible to set roll and fix this issues if the input to the algorithms is just two positions. You must pass in two positions and a forward vector. I would strongly recommend to use this anytime over the built in FindLookAtRotation, as its just better.

The solution i found here c++ - How can I create the equivalent of Unity LookAt in Unreal blueprint? - Stack Overflow

I will repost the solution incase the link dies

    FRotator MyLookRotation(FVector lookAt, FVector upDirection)
    {
    FVector forward = lookAt - GetActorLocation();
    FVector up = upDirection;


    forward = forward.GetSafeNormal();
    up = up - (forward * FVector::DotProduct(up, forward));
    up = up.GetSafeNormal();

   ///////////////////////


   FVector vector = forward.GetSafeNormal();
   FVector vector2 = FVector::CrossProduct(up, vector);
   FVector vector3 = FVector::CrossProduct(vector, vector2);
   float m00 = vector.X;
   float m01 = vector.Y;
   float m02 = vector.Z;
   float m10 = vector2.X;
   float m11 = vector2.Y;
   float m12 = vector2.Z;
   float m20 = vector3.X;
   float m21 = vector3.Y;
   float m22 = vector3.Z;

   float num8 = (m00 + m11) + m22;
   FQuat quaternion = FQuat();

   if (num8 > 0.0f)
   {
     float num = (float)FMath::Sqrt(num8 + 1.0f);
     quaternion.W = num * 0.5f;
     num = 0.5f / num;
     quaternion.X = (m12 - m21) * num;
     quaternion.Y = (m20 - m02) * num;
     quaternion.Z = (m01 - m10) * num;
     return FRotator(quaternion);
   }

   if ((m00 >= m11) && (m00 >= m22))
   {
     float num7 = (float)FMath::Sqrt(((1.0f + m00) - m11) - m22);
     float num4 = 0.5f / num7;
     quaternion.X = 0.5f * num7;
     quaternion.Y = (m01 + m10) * num4;
     quaternion.Z = (m02 + m20) * num4;
     quaternion.W = (m12 - m21) * num4;
     return FRotator(quaternion);
   }

   if (m11 > m22)
   {
     float num6 = (float)FMath::Sqrt(((1.0f + m11) - m00) - m22);
     float num3 = 0.5f / num6;
     quaternion.X = (m10 + m01) * num3;
     quaternion.Y = 0.5f * num6;
     quaternion.Z = (m21 + m12) * num3;
     quaternion.W = (m20 - m02) * num3;
     return FRotator(quaternion);
   }

   float num5 = (float)FMath::Sqrt(((1.0f + m22) - m00) - m11);
   float num2 = 0.5f / num5;
   quaternion.X = (m20 + m02) * num2;
   quaternion.Y = (m21 + m12) * num2;
   quaternion.Z = 0.5f * num5;
   quaternion.W = (m01 - m10) * num2;


   return FRotator(quaternion);
}

1 Like

Here is what I did

inline FQuat MyLookAt(const FVector& lookAt, const FVector& upDirection)
{
     return FRotationMatrix::MakeFromXZ(lookAt, upDirection).ToQuat();
}
1 Like

cleaner than doing the math by hand, good find!

This does not work for me, still snaps between 180 and -180

Same. Still causes the same issue. I’m in a 2D space and anytime the player goes over the enemy the model “flips” or starts rotating the other direction, depending upon whether you split the struct or utilize all axes. For some reason Unreal is just not 2D friendly. It’s kind of a nightmare and I’m just about to take the sunken cost and go back to Unity. lol