Reputation: 28
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.
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
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
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