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 Align up direction with normal while retaining look direction

Discussion in 'Scripting' started by FreezedIce, Aug 19, 2021.

  1. FreezedIce

    FreezedIce

    Joined:
    Jun 12, 2018
    Posts:
    6
    I'm testing a small prototype where player (first person controller) can stick itself to different surfaces (similar to manifold garden / outer wilds gravity crystalls). After a quick google search, I decided to use Quaternion.FromToRotation(transform.up, normal) * transform.rotation with Quaterion.Slerp to smooth out the rotation. But it seems like FromToRotation can sometimes flip the player depending on the normal direction. What is the right way to compute this kind of rotation?
    I've also attached a picture showing the issue.
     

    Attached Files:

  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,722
    I think your quaternion composition may be backwards?

    I think it should be:
    Code (CSharp):
    1. Quaternion targetRotation = transform.rotation * Quaternion.FromToRotation(transform.up, normal);
    Because you're starting at the object's current rotation and adding the rotation that it takes to go from the current up direction to the surface normal direction.
     
  3. FreezedIce

    FreezedIce

    Joined:
    Jun 12, 2018
    Posts:
    6
    Hmm, it works better now, but it still creates some weird rotations when you are not looking directly at the wall. I guess I should be using transform.forward somewhere as transform.up doesn't provide enough info for Quaternion.FromToRotation, because I need to align both transform.up and transform.right/forward with the wall orientation.
     
  4. steego

    steego

    Joined:
    Jul 15, 2010
    Posts:
    968
    What do you expect the new forward direction to be? Probably you can project the current forward direction on the wall to keep somewhat the same looking direction

    Code (csharp):
    1.  
    2. // We need to check this cause we can't project a zero vector, that is when we're looking straight at the wall
    3. bool areParallel = Mathf.Approximately(Mathf.Abs(Vector3.Dot(transform.forward, wallNormal)), 1f);
    4. // If they are parallel we need to specify some arbitrary forward vector
    5. Vector3 newForward = areParallel ? Vector3.up : Vector3.ProjectOnPlane(transform.forward, wallNormal).normalized;
    6. Quaternion newRotation = Quaternion.LookRotation(newForward, wallNormal);
    7.  
     
    FreezedIce and PraetorBlue like this.
  5. FreezedIce

    FreezedIce

    Joined:
    Jun 12, 2018
    Posts:
    6
    Thank you! It works great now. I had to set a lower threshold for parallelism check (about 0.95), as Mathf.Approximately was still giving false for really close numbers and also replaced Vector3.up with transform.up as player could be hanging upside down (while still looking directly at the wall). If you are curious, here is how it works now
     
    steego likes this.