How do I get a float value on whether 2 objects are facing the same direction?

Hello,
I have a question. I want to write a function where I have a car, and a bunch of way points. I only want the car to pick way points that are NOT ONLY in front of the car, but ALSO IF the way points are pointing in a certain range of direction similar to the direction of where the car is pointing.

In my function, I want it to return anywhere from +1.0f (IF the blue arrow in my editor from the waypoint is pointing in the EXACT SAME direction of where the blue arrow is pointing from the car AND, if the way point is in front of my car), and a -1.0f (IF the waypoint is EITHER behind the car OR in front of the car BUT the blue arrow in my editor is pointing in the wrong direction). How would I achieve this? Thank you.

I think Vector3.Angle will be your friend here.

If the angle between your car’s forward direction (transform.forward) and the position of the waypoint relative to your car’s position (waypoint.position - transform.position) is less than 90, it is in front. More than 90, it is behind.

Then you only need to map the angle to a -1,1 float range.

I’ll come up with an example and post back here.

Nope. Dot product if your friend in this scenario, it is already -1 to 1 range 1 facing the same direction and -1 facing the opposite direction.
https://docs.unity3d.com/ScriptReference/Vector3.Dot.html

Edit: Dot is faster than angle too, angle requires a few more steps.

1 Like

Yep that is exactly what @mikelowefedex is looking for, even has the code example.

My method worked great, but Vector3.Dot is easily a better and less manual option.

Yes and no. :slight_smile:
First of all the Dot product only returns a value between -1 and 1 if both vectors are normalized, otherwise it doesn’t. Also while it is true that they return a value of 1 if they point exactly in the same direction and -1 if they face exactly in opposite directions, it’s not a linear relationship in between. It’s actually the cosine of the angle between the two vectors. Yes, it’s the cheapest solution and if you’re only interested if something faces “roughly” in the same direction or roughly in the opposite direction, the dot product is the way to go. However when you need an actual smooth gradient, using Vector3.Angle and remap is the better solution.

Note that in most cases it’s very unlikely to actually get a value of 1 or -1 from the dot product (when using two normalized vectors). Likewise an exact angle of 0° or 180° is also quite unlikely, so always work with ranges.

I guess you need that value to actually rotate a “hint arrow” for a driving game? Since you talked about the forward axis of your waypoint, I guess you rotated the waypoints so their forward axis points in the direction where you need to go fro here. So you usually would calculate two values. The first would tell you if you’re heading towards the waypoint or away from it. The second value would tell you if you have the same alignment as the waypoint. You just have to mix the two values based on how far you are from the waypoint. If you are far away from your next waypoint, you usually only care about the direction towards the waypoint and not the direction where to go from that waypoint. The closer you get to the waypoint, the more important the forward direction of the waypoint gets. When you are really close, that forward direction is the only relevant direction. Likewise you could also incoperate the last waypoints forward direction and use that if you are still closer to the last waypoint and slowly move over to use the next way point. So just a bunch of slerps depending on the relative distances.

Note if that hint arrow is your actual goal, using an angle directly would probably make more sense. Though I would use a SignedAngle instead so you also know the direction (left or right).

Of course so far as the OP is concerned they would query each waypoint and check which one is the closest to one and in front. Nothing is exact with floating point calculations, we should all know the caveats of them as programmers.

Now what we haven’t answered is how to tell if the waypoint is in front of the car, which is basically transform.InverseTransformPoint and if z is greater than 0 it’s in front.

Oh and direction like tranform.forward is already normalized so that point is moot. Vector3.Angle/SignedAngle probably normalizes both vectors anyways, even though it isn’t really needed. (The Unity API does do some redundant things to make up for newbs.) Yeah I know that’s an assumption and I could be wrong, I have been before and will be again.

1 Like

I think I developed my own formula. The obj variable is the waypoint, and the ‘this’ variable refers to the car. CalculateValidWaypointAngle returns between 0 and 1 depending on IF the waypoint should be considered (depending on where the waypoint is facing). getFacingValue returns between 0 and 1 if the car is facing toward or away from the waypoint…

    public float getFacingValue(GameObject obj) {
        float dot = (1 + Vector3.Dot(transform.forward, ((obj.transform.position + new Vector3(0, 0.5f, 0)) - transform.position).normalized)) * 1.0f / 2;
        return dot;
    }

    public float CalculateValidWaypointAngle(GameObject obj)
    {
        float angle = (obj.transform.eulerAngles-transform.eulerAngles).y;
      
        float angle2 = getFacingValue(obj);

        if(angle > 180){angle -= 360f;}
        if(angle < -180){angle += 360f;}
      
        if(angle2 > 180){angle2 -= 360f;}
        if(angle2 < -180){angle2 += 360f;}
       
        float finalAngle = Mathf.Lerp(0, (1 - (Mathf.Abs(0.5f - ((1 + (angle * 1.0f / 180)) * 1.0f / 2)) * 2)), angle2);
      
        return finalAngle;
    }

Sounds like you’ve come to a solution which is great.

Just one tiny little tip I’d like to share, you’re using a couple of divisions in your code

Mathf.Abs(0.5f - ((1 + (angle * 1.0f / 180)) * 1.0f / 2))

If angle was to equal 0, this line might throw a ‘Cannot devide by zero’ error.
I prefer to avoid divisions as much as possible, and instead multiply by a float.

/ 2 is equavalant to * 0.5f
/ 180 is equavalnt to * 0.0055f

When you do this you guarantee that the calulation is safe against division by zero errors if the varible you’re halving ever happens to equal zero. Although you may loose some precision due to any rounding errors. (1 / 180 is actually 0.00555555…)

0 / 1 = 0, 1 / 0 = error. The advice to multiply is good though, division is more expensive than multiplication. It’s a micro optimization though, so no need to change it if it isn’t necessary.

1 Like