PaazhilayaZhaba
PaazhilayaZhaba

Reputation: 28

Getting a signed angle value

I'm having an issue with finding an angle between two vectors. I have this code (pic below) in blueprints, which uses dot product in order to find cos of the angle between two vectors.

enter image description here

However, it seems that this method does not give me full information - I still cannot determine if the object, which position I am tracking, is left or right from me. I believe it is because cos is even function and does not provide information about angle's sign.

Is there any way to determine angle's signed value? May be some C++ magic? I would really appreciate some help in this case.

Upvotes: 1

Views: 2161

Answers (2)

Ruzihm
Ruzihm

Reputation: 20269

The other answer has a good solution for your specific use case since you can use the rotator to find the actor's local right direction quickly. More generally (such as if a rotator is not involved), if you need to get the angle and its relative direction from the perspective of some arbitrary up axis you can use this function:

// Header
UFUNCTION(BlueprintPure)
static void AngleAndDirection(const struct FVector& FromNormalized, 
        const struct FVector& ToNormalized, 
        const struct FVector& UpAxisNormalized, 
        float& OutAngle, float& OutDirection);

// Source
void UClassName::AngleAndDirection(const FVector& FromNormalized, 
        const FVector& ToNormalized, const FVector& UpAxisNormalized, 
        float& OutAngle, float& OutDirection)
{
    OutAngle = UKismetMathLibrary::Acos(
            FVector::DotProduct(FromNormalized, ToNormalized));
    FVector Right = FVector::CrossProduct(UpAxisNormalized, FromNormalized);
    float Dot = FVector::DotProduct(UpAxisNormalized, Right);
    OutDirection = UKismetMathLibrary::SignOfFloat(Dot);
}

Where:

  • FromNormalized and ToNormalized, and UpAxisNormalized are (of course) normalized

  • OutDirection is positive if ToNormalized is on the relative rightwards, negative if leftwards, or zero if neither (could be in front, above, below, or directly behind)

  • OutAngle is measured in radians.

If you need degrees, you can use DegACos instead of Acos.

This function could be put into a Blueprint Function Library if you are using one, so you could use it with your blueprints.

Upvotes: 0

user10316640
user10316640

Reputation:

Dot product will only give you the cosine of the angle formed by the two vectors. It is positive of they are facing the same direction, negative for opposite directions and 0 if they are perpendicular.

Simply check the "RightDirection" to get the sign that corresponds to the original dot product.

By doing this, you will exclude the zeros given by the cardinal directions, so substitute the opposite axis when zero.

Here is the Blueprint pseudocode:

   Vector TargetDirection = Normalize(Player.GetActorLocation - Object.GetActorLocation);
   float LR = dot(TargetDirection, Player.GetActorRotation.GetRightVector);
   float SignLR = Sign(LR); // returns -1,0,1
   float Angle = dot(TargetDirection,Player.GetActorRotation.GetForwardVector);

// catch the dot product zeros at(0,90,180,270...) 
// if is a float comparison object with the bool output passed to a branch

   if(Angle == 0) Angle = LR; // pick a direction (90 degrees left or right)
   if(SignLR == 0) SignLR = Angle; //pick a direction


   float Signed Angle = SignLR * Angle;

Note: The variables are not needed, when implementing this code, the output pin is wired directly to the multiple inputs.

Upvotes: 2

Related Questions