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

Question Impossible rotation? (Follow a vector) [SOLVED]

Discussion in 'Scripting' started by Svintaj, Sep 1, 2021.

  1. Svintaj

    Svintaj

    Joined:
    Apr 27, 2018
    Posts:
    7
    Hello!

    I'm trying to rotate an object so it always stays parallel with a direction-vector, it works fine besides when the vector points down ~170 degrees, then the object spins randomly around the Y-axis.

    The object has no parent and its rotation and position is set to zero. It looks just like gimbal-lock but still I do the rotation with only one Quaternion. I have now tried many different ways to do this but they all end up having the exact same problem!?

    I could compensate the local Y orientation with an Quaternion in the next step, but how can I read it’s current local Y and only the Y as an Quaternion? I need to read it to reset it to zero. (The local Euler value can’t be used here, it just brings more rotation chaos.)

    This must be a well known problem, so is there any known solution?
    (How to stop the random spinning..?)


    Code (CSharp):
    1. // The direction-vector pointing at the target:
    2. Vector3 vectorToTarget = Target.transform.position.normalized;
    3.  
    4. // First try: using -> FromToRotation()
    5. this.transform.rotation = Quaternion.identity; // Start with no rotation
    6. this.transform.rotation = Quaternion.FromToRotation(this.transform.up, vectorToTarget)*this.transform.rotation;

    I have also tried with:
    Code (CSharp):
    1. // Second try: using ->  AngleAxis()
    2.  
    3. // Get the angle between the up-vector and vectorToTarget
    4. float angle = Vector3.Angle(Vector3.up, vectorToTarget);
    5.  
    6. this.transform.rotation = Quaternion.identity; // Start with no rotation
    7. this.transform.rotation = Quaternion.AngleAxis( angle, Vector3.Cross(Vector3.up, vectorToTarget).normalized ) * this.transform.rotation;

    And also:
    Code (CSharp):
    1. // Third try: using -> RotateAround()
    2.  
    3. // Get the angle between the up-vector and vectorToTarget
    4. float angle = Vector3.Angle(Vector3.up, vectorToTarget);
    5.  
    6. this.transform.rotation = Quaternion.identity; // Start with no rotation
    7. this.transform.RotateAround(Vector3.zero, Vector3.Cross(Vector3.up, vectorToTarget).normalized, angle)

    Thanks in advance! :)
     
  2. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,833
    "Reading (or changing) only the Y rotation" isn't a well-defined mathematical operation because Euler angles are not linearly independent. For instance, the rotations (180, 0, 0) and (0, 180, 180) are equivalent, even though none of their components are equal.


    "Look in this direction" doesn't fully define a rotation; it gives you pitch and yaw, but not roll. You could be (for example) upside down while still looking in that direction.

    That's why Unity's LookRotation function has a second parameter, to indicate which direction to treat as "up". Usually you just use +Y as that second parameter (and that's the default), which mostly does what you'd intuitively expect, but if the direction you're looking is already straight up or down, then this is ambiguous, and you need to choose a different direction to act like "up".

    If you want to always have the same roll when looking up/down, then one option would be to check if you're looking up/down (or maybe "approximately" up/down), and if so, supply a different second argument to LookRotation to act as "up". Or, heck, even just have two constants defined in your code for what rotations to use for "up" and "down".
     
    Bunny83 likes this.
  3. Svintaj

    Svintaj

    Joined:
    Apr 27, 2018
    Posts:
    7
    Thanks, got it working now! :)

    I was trying to use a local-up-vector right after I had reset the rotations to zero, resulting in an local-up-vector that was always world-up. So I just removed that line and it now works perfect and is stable! :cool:

    Here is the latest working version:

    Code (CSharp):
    1. Vector3 vectorToTarget = Target.transform.position;
    2. this.transform.rotation = Quaternion.FromToRotation(this.transform.up, vectorToTarget) * this.transform.rotation;