• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
2
Question by SharkFace · Jan 15, 2014 at 01:40 AM · directionvector

Calculate the General Direction of a Vector

Hi All,

Given a point of origin and a Vector3 extending therefrom, I'm trying to work how to calculate the 'general direction' of that Vector. By 'general direction' I mean whether the Vector is mostly point forwards, backwards, left, right, up or down.

It's probably easier to explain what I'm after using the 2D example below :

alt text

As displayed, the point of origin (x) is in the centre of the circle. The circle is split into four 90 degree quadrants. The position of each quadrant (relative to a notional direction of which way is forwards) determines whether it represents forward, back, left or right. In the above, the green arrow represents a Vector2 that is facing forwards. The yellow arrow a Vector facing to the left.

I can calculate the 'general direction' in the 2D examples above using a bit of trig, but what I'm really struggling with is the math to apply this in 3D. Consider the circle below is actually a sphere that, as well as outlining forward, back, left and right, also has Up and Down based on the vertical (or y) aspect of the Vector.

I could probably hash something together by checking the Vector3's x, y and z angle (relative to the origin's x,y and z planes) individually and then place the vector in the relevant quadrant with piles of switch statements or nested if's but that approach has so many variables to account for and just doesn't feel right. I'm hoping there's a math boffin out there that could provide a smarter and slicker approach?

Many thanks in advance for any suggestions!

example.jpg (116.5 kB)
Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

3 Replies

· Add your reply
  • Sort: 
avatar image
8
Best Answer

Answer by robertbu · Jan 15, 2014 at 02:00 AM

I don't consider myself a "math boffin', but the Dot product might help here. If you take the Dot products between the direction vectors and the unknown vector, the highest value will indicate which vector it is closest to in direction. Here is a bit of untested code:

 #pragma strict
 
 var compass = [Vector3.left, Vector3.right, Vector3.forward, Vector3.back, Vector3.up, Vector3.down];
 
 function ClosestDirection(v : Vector3) : Vector3{
 
     var maxDot = -Mathf.Infinity;
     var ret = Vector3.zero;
     
     for( var dir : Vector3 in compass) { 
         var t = Vector3.Dot(v, dir);
         if (t > maxDot) {
             ret = dir;
             maxDot = t;
         }
     }
 
     return ret;
 }

Note this code returns the vector. You could change to an indexed 'for' loop and return the index or even an enumeration for the direction.

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image SharkFace · Jan 16, 2014 at 01:12 AM 0
Share

Thanks robertbu, perfect!

avatar image SharkFace · Jan 16, 2014 at 01:54 AM 0
Share

Just to add, I've tested this approach versus my own 'distance-based' approach below. Nothing fancy, just perfor$$anonymous$$g a few thousand of each every frame and eyeballing the framerate and I'd say this solution is between 70% - 80% more efficient, i.e. 70/80% more frames per second! Happy days.

avatar image
1

Answer by SharkFace · Jan 16, 2014 at 01:13 AM

Thanks Chaps, both very helpful suggestions.

Robertbu - I still haven't quite got my around exactly how the dot function works - I just need to meditate on it for a while longer, but I do see how the results can translate into what I'm after - returning a custom enum will be the way forward for me.

Gfoot - I appreciate the alternative. My current project requires the precision of robertbu's solution and is based on equal weightings between each direction but it's a good call on being able to adjust the thresholds to apply bias'.

For what it's worth, I came up with another alternative myself. It's no more effective that robertbu's solution but I thought I'd mention it for the benefit of any future readers.

The idea is that you define a point infront, behind, above, below, to the left and to the right of the point of origin directly along each axis. It does matter how far they are from the point of origin, as long as they are all the same distance. Then, you just check the distance between point at the end of the vector you're testing and each of the six points previously defined. The general direction can be defined from which ever of those six points is closest to the point at the end of you vector.

Something like this ...

 public enum GeneralDirection {
     None,
     Forwards,
     Back,
     Left,
     Right,
     Up,
     Down
 }
 
     public GeneralDirection GetDirection (Vector3 pointOfOrigin, Vector3 vectorToTest) {
         
         GeneralDirection result = GeneralDirection.None;
         float shortestDistance = Mathf.Infinity;
         float distance = 0;
         
         Vector3 vectorPosition = pointOfOrigin + vectorToTest;
 
         distance = Mathf.Abs (((pointOfOrigin + Vector3.forward) - vectorToTest).magnitude);
         if (distance < shortestDistance)
         {
             shortestDistance = distance;
             result = GeneralDirection.Forwards;
         }
         distance = Mathf.Abs (((pointOfOrigin  -Vector3.forward) - vectorToTest).magnitude);
             if (distance < shortestDistance)
         {
             shortestDistance = distance;
             result = GeneralDirection.Back;
         }
         distance = Mathf.Abs (((pointOfOrigin + Vector3.up) - vectorToTest).magnitude);
             if (distance < shortestDistance)
         {
             shortestDistance = distance;
             result = GeneralDirection.Up;
         }
         distance = Mathf.Abs (((pointOfOrigin + -Vector3.up) - vectorToTest).magnitude);
             if (distance < shortestDistance)
         {
             shortestDistance = distance;
             result = GeneralDirection.Down;
         }
         distance = Mathf.Abs (((pointOfOrigin + Vector3.left) - vectorToTest).magnitude);
             if (distance < shortestDistance)
         {
             shortestDistance = distance;
             result = GeneralDirection.Left;
         }
         distance = Mathf.Abs (((pointOfOrigin + Vector3.right) - vectorToTest).magnitude);
             if (distance < shortestDistance)
         {
             shortestDistance = distance;
             result = GeneralDirection.Right;
         }
 
         return result;
         
     }
     
     
     
     
 
 }



It's not quite as elegant as robertbu's solution but I reckon it gives the same degree of accuracy but uses 'Simpler Maths' - not that that's a tangible benefit I suppose ;)

It does, however, combine what I think are the strengths of both robertbu's and gfoot's solutions in that it should be just as precise as robertbu's but also you could easily apply a bias to any particular direction by defining the point in front/behind/etc closer or further away from the point of origin - e.g. defining the point above the point of origin closer would apply bias toward it and moving it further away would do the opposite. This solution would also work whether you normalize the vector or not.

Anyway, as I said, just a thought that may be a better for someone else's needs.

Thanks again Gents.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image sandeep_ika · Oct 10, 2017 at 01:32 PM 0
Share

It works perfectly, Thanks!!

avatar image
2

Answer by gfoot · Jan 15, 2014 at 02:21 AM

robertbu's solution is precise, it will tell you exactly which axis the vector is closest to pointing along. I thought I'd mention an alternative though which is simpler to implement and gives good intuitive results that are not quite so precise but usually good enough.

This is for a normalized vector - if yours is not normalized, then normalize a copy of it first.

 if (vector.z > thresholdZ)
     // pointing forwards
 elif (vector.z < -thresholdZ)
     // pointing backwards
 elif (vector.y > thresholdY)
     // pointing up
 elif (vector.y < -thresholdY)
     // pointing down
 elif (vector.x > 0)
     // pointing right
 else
     // pointing left

For the first threshold, use a value like 0.6-0.7 - the lower the value, the more keen the algorithm is to say you're pointing forwards or backwards. For the second threshold you might lean towards higher numbers like 0.7-0.8, to make the algorithm not so keen to say you're looking up or down (i.e. more likely to say you're looking left or right).

(Mathematically, thresholdZ is the cosine of the largest angle offset from straight forwards which you still consider to be looking forwards, and thresholdY is similar for up and down.)

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image SharkFace · Jan 16, 2014 at 01:13 AM 0
Share

Thanks gfoot, nice suggestion.

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

20 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

determine that the spinning motion is "CW" or "CCW" 0 Answers

How do you turn object to face a particular vector ? 1 Answer

the projectile reflects 1 time only when it hits something, pls help! 1 Answer

C# Raycast from Object direction (z-axis) + another Vector3 1 Answer

How do I rotate an object to face a direction. 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges