Cheat the Cross Product on 'Look Towards' checks

A little optimization you can do when trying to get a signed magnitude of an angle without needing to use the cross product, if you have the necessary tools

Why do we care?

Dot Product is less expensive than Cross Product

The conventional way is to use both the Dot and Cross Product, however if you have the tools available, you can cut out the need for a Cross Product which will save some cycles since

Dot Product = O(n) Flops

Cross Product = O(nm) Flops

So in highly frequent code execution (like in an objects Tick) if we can remove the need for a Cross Product every tick, that's a small but IMO important win.

Scenario

A very realistic scenario you'll probably run into is a problem like this

Given a player and a target, derive the signed magnitude of the angle the player must turn to face the target.

Conventional way using Cross Product

1) find the unsigned angle θ between player and target using Dot Product
2) find a vector N which is orthonormal to the plane represented by player and target dir using Cross Product
3) compare N against player's UP vector 
    x > 0: clockwise
    x = 0: exactly parallel (choose either)
    x < 0: counter-clockwise
Cyan vector pointing Up or Down is the result of the Cross Product (notice it changing from UP to DOWN as we move it around)
void FaceTarget(const AActor* Player, const AActor* Target)
{
	FVector DirToTarget = Target->GetActorLocation() - Player->GetActorLocation();
	float AngleOfView = Player->GetActorForwardVector().GetSafeNormal().Dot(DirToTarget);
	
	FVector PlaneNormal = Player->GetActorForwardVector().Cross(DirToTarget);
	bool shouldTurnClockwise = PlaneNormal.Dot(Player->GetActorUpVector()) >= 0;
	
	// now we know which direction and how much to turn by...
}

This works because the resultant vector of the Cross Product will always have a signed magnitude which will tell us if the DirectionToTarget (Y in the picture below) is to the player's right or left

As a general guide X cross Y = Z

You can use this to know if going clockwise or counter clockwise will result in a positive or negative vector i.e. Unreal uses LEFT HAND RULE so going clockwise results in a "positive Z"

(left) Left Hand Rule, (right) Right Hand Rule

Cheaper way without using Cross Product

this only works if you have a perpendicular vector to the player's forward baked into the structure you're working with.

i.e. Unreal Actors all have a Forward, Up, and Right vector baked in

1) find the unsigned angle θ between player and target using Dot Product
2) compare player's RIGHT vector with target dir
    x > 0: clockwise
    x = 0: exactly parallel (choose either)
    x < 0: counter-clockwise

We can cut out the need the cost of the Cross Product by instead using the player's RIGHT and DirectionToTarget vector.

Remember the reason we couldn't just use PlayerForward.Dot(DirToTarget) to tell which direction to turn was because the result would always be an unsigned angle

ex: 45 degrees left or right always stays within [0,90] degrees (thus positive).

What we do here is by using the player's RIGHT, which just the player's forward rotated 90 degrees, when we're on the left the angle will be between [0,89] degrees (positive Dot) but when on the right the angle will be between [91,180] degrees (negative Dot)

void FaceTarget(const AActor* Player, const AActor* Target)
{
	FVector DirToTarget = Target->GetActorLocation() - Player->GetActorLocation();
	float AngleOfView = Player->GetActorForwardVector().GetSafeNormal().Dot(DirToTarget);
	bool shouldTurnClockwise = Player->GetActorRightVector().Dot(DirToTarget) >= 0;
	
	// now we know which direction and how much to turn by...
}

Last updated