Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

How to calculate (inexpensively) if your object is facing close to global down

Discussion in 'Scripting' started by The_Raz, May 22, 2014.

  1. The_Raz

    The_Raz

    Joined:
    Feb 8, 2014
    Posts:
    79
    I am trying to create a parabolic arc with a projectile that will not wrap around when it goes below the elevation that it was shot at. I don't know how to quickly calculate if the object is facing a threshold near global down. how do I check to see without other objects if the current object is CLOSE to facing global down?
     
  2. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,738
    Simplest (though probably not the fastest) would be something like (bullet.transform.forward.y < -0.9f)
     
  3. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
  4. The_Raz

    The_Raz

    Joined:
    Feb 8, 2014
    Posts:
    79
    ill look into that, If I can make an if statement like....

    ill be set

    Code (csharp):
    1.  
    2.  
    3. if(angle !< 10)
    4. {
    5. transform.Rotate((drop * Time.deltaTime),0,0); 
    6. }
    7.  
    8.  
     
  5. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,377
    Actually... that's probably about the quickest you can get. You have no calculations occurring, just a comparison is done.

    It's just not the best for representing proximity. If you wanted to allow for configuring the margin to allow in, say:

    ...y < margin - 1.0f

    where margin is in your example 0.1f

    That margin isn't linear, but instead trigonometric.

    It's also tethered directly to the 'down' vector, so if you wanted to allow for other directions, you'd require a completely different algorithm.

    So yeah, it's the fastest... just not the most dynamic.

    LeftyRighty has a more open answer that allows for any axis, but using Quaternions has a bunch of extra steps.

    You could in turn just use the dot product rule:

    dot product is defined as:
    A dot B = ||A|| * ||B|| * cos(theta)
    where theta is the angle between A and B

    note, ||A|| means magnitude of A

    if our vectors are unit vectors, well ||A|| and ||B|| both equal 1 so we could reduce this to:

    Au dot Bu = cos(theta)

    reorganize

    acos(Au dot Bu) = theta

    here we now have a formula for the angle between two unit vectors:

    Code (csharp):
    1.  
    2. var a = transform.forward; //get your forward vector, if this isn't it, get it however
    3. var b = Vector3.down; //the axis you're comparing against
    4.  
    5. var angle = Mathf.Acos(Vector3.Dot(a, b));
    6. if (angle < 0.1f)
    7. {
    8.     //do something
    9. }
    10.  
    note - acos returns in radians, not degrees. So 0.1 is about 5.7 degrees.



    Here's a reusable static function I use for finding angle's between. It uses magnitude though because it's not guaranteed the values passed in are actually unit vectors.

    Code (csharp):
    1.  
    2.  
    3.         public static float AngleBetween(Vector3 a, Vector3 b)
    4.         {
    5.             return (float)Mathf.Acos(Vector3.Dot(a, b) / (a.magnitude * b.magnitude));
    6.         }
    7.  
    8.  
     
    Last edited: May 22, 2014
  6. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,738
    The rest of your post is good, but I believe that's incorrect. transform.forward has to transform a direction vector by the rotation (it's a shortcut for "transform.rotation * Vector3.forward"). I can't think of a way to avoid that transformation, true, but that doesn't mean it's free or that someone smarter than I could figure out a faster way.

    Oh, and there is a Vector3.Angle function that is probably exactly the same as your custom static function ;) Except in degrees.

    LeftyRighty, your suggestion is wrong on two levels. First of all, that's not how Quaternion.Euler works - you want to use Quaternion.LookRotation if you're going to use Vector3.down. (Your code will give a rotation that is rotated 1 degree to the right) Second, you want to compare forward vectors, not rotations, in this case. For example, if I am facing the ground with the top of my head facing north, while you are facing the ground with the top of your head facing south, comparing quaternions will give us 180 degrees difference, even though our noses are pointing the same way and we want 0 degrees in that case. Hence, transform.forward.
     
  7. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,377
    I was mostly judging on the comparing the y value. Not how you got the forward. That's why I say in my example code "however you decide to get your forward".

    And yes, Vector3.Angle appears to do the same thing my static method does. Didn't know it existed... I ported my util classes over from other frameworks that didn't have a Vector3.Angle method.
     
  8. The_Raz

    The_Raz

    Joined:
    Feb 8, 2014
    Posts:
    79
    Thank you all for your help I will try these.
     
  9. The_Raz

    The_Raz

    Joined:
    Feb 8, 2014
    Posts:
    79
    It is not perfect, but it works and I am not complaining. I time the drop by the angle to reduce the chance of overshooting true down. Have not had a weapon that overshoots yet, but I would not be surprised if it happened. Glad to be past this problem lol.

    Code (csharp):
    1.        
    2. angle = Quaternion.Angle(Quaternion.Euler(transform.rotation * Vector3.forward), Quaternion.Euler(Vector3.down));
    3.  
    4.                 if(angle > anglecheck)
    5.                 {
    6.                     transform.Rotate(((drop * Time.deltaTime) * angle),0,0);   
    7.                 }
    8.  
    the way I have this code written, angle goes between 0 and 2. 0 means its looking down, 2 means its looking up. I keep anglecheck around 0.3f. I am shooting thousands of bullets at one time with no slowdown.
     
    Last edited: May 22, 2014
  10. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,377
    That test is not a good test.

    Quaternion.Euler creates a rotation from euler rotations (yaw, pitch, roll). Not a rotation in the direction of some vector.

    You should not be using that method.
     
  11. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,221
    Hmmm... I would think that Vector3.Dot would work better than any of that.

    Code (csharp):
    1.  
    2. if(Vector3.Dot(Vector3.down, transform.forward) > 0.9f) // We are facing almost down...
    3.