Search Unity

Quaternion.AngleAxis is a F***.

Discussion in 'Physics' started by koukido, May 13, 2019.

  1. koukido

    koukido

    Joined:
    Mar 11, 2019
    Posts:
    3
    so, i'm using hit.normal to make the player character's ''up'' direction perpendicular to whichever surface they're standing on, and if you jump, it retains the last ''up'' vector it measured, which is useful for me because the idea is to jump off any immediate surface

    when i'm not using quaternion.angleaxis, jumping off of a wall works perfectly


    when i am, as soon as the raycast is out of range it changes the transform.up to 0

    why is this

    why

    is there any way i can fix this, make it so it doesn't go to zero when using angleaxis or an alternative way of rotating the player with effectively the same results

    i'm stumped
     
  2. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    Post your code, otherwise its hard to help you
     
    SparrowGS and Antypodish like this.
  3. koukido

    koukido

    Joined:
    Mar 11, 2019
    Posts:
    3
    in the end, i fixed it in the most naïve and least sustainable way possible by just setting the rotation speed to 0
    i'm happy with this, even if it's suboptimal

    however, if you have a better solution, please show me the way

    Code (CSharp):
    1. {
    2.     Rigidbody rb;
    3.     bool airborne;
    4.     bool jumping;
    5.     float y_airspeed;
    6.     public float rayDistance;
    7.     public float spd;
    8.     float stickmagnitude;
    9.     float jump;
    10.     sbyte jumping_drag;
    11.     sbyte gravity;
    12.     float angle;
    13.     float ang = 40f;
    14.  
    15.     Quaternion targetrotation;
    16.    
    17.  
    18.  
    19.     // Use this for initialization
    20.  
    21.     void Start()
    22.  
    23.     {rb = GetComponent<Rigidbody>();}
    24.  
    25.     // Update is called once per frame
    26.     void FixedUpdate()
    27.     {  
    28.         float hor = Input.GetAxisRaw("Horizontal");
    29.         float ver = Input.GetAxisRaw("Vertical");
    30.         stickmagnitude = Mathf.Clamp01(new Vector2(hor, ver).magnitude);
    31.         if (hor != 0.0f || ver != 0.0f) { angle = Mathf.Atan2(hor, ver) * Mathf.Rad2Deg; }
    32.  
    33.         RaycastHit hit;
    34.         var theRay = transform.TransformDirection(Vector3.down);
    35.  
    36.         if (Physics.Raycast(transform.position, theRay, out hit, rayDistance))
    37.         {transform.rotation = Quaternion.FromToRotation(transform.up, hit.normal) * transform.rotation;}
    38.  
    39.  
    40.  
    41.         transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.AngleAxis(angle, transform.up), Time.deltaTime * ang);
    42.         transform.Translate(Vector3.forward * stickmagnitude * spd * Time.deltaTime, Space.Self);
    43.  
    44.  
    45.  
    46.         if (Input.GetButtonDown("Jump"))
    47.         {
    48.             jumping = true;
    49.             jump = 48;
    50.             airborne = true;
    51.         }
    52.  
    53.  
    54.  
    55.  
    56.         if (airborne == true)
    57.         {
    58.             gravity = 28;
    59.  
    60.             y_airspeed -= gravity * Time.deltaTime;
    61.  
    62.             if (jump <= 0) {jump = 0;}
    63.  
    64.             transform.Translate (Vector3.up * y_airspeed * Time.deltaTime, Space.World);
    65.             transform.Translate(Vector3.up * jump * Time.deltaTime, Space.Self);
    66.  
    67.             if (jumping == true)
    68.  
    69.             {
    70.                 jumping_drag = 2;
    71.                 jump -= jumping_drag * Time.deltaTime;
    72.             }
    73.         }
    74.     }
    75.  
    76.     void OnCollisionEnter(Collision col)
    77.     {
    78.         if (col.collider)
    79.         {
    80.             airborne = false;
    81.             jumping = false;
    82.             gravity = 0;
    83.             jumping_drag = 0;
    84.             y_airspeed = -7;
    85.             jump = 0;
    86.             ang = 5;
    87.         }
    88.     }
    89.  
    90.  
    91.     private void OnCollisionExit(Collision col)
    92.     {
    93.         if (col.collider)
    94.         {   airborne = true;
    95.             ang = 0;
    96.         }
    97.     }
    98.  
    99. }
     
  4. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    Few tips:
    1. Do not use Input polling in the FixedUpdate, as that is unreliable somewhat. Use Update for that purpose;
    2. You're not using Slerp correctly.
    https://chicounity3d.wordpress.com/2014/05/23/how-to-lerp-like-a-pro/

    Maybe you'd actually want Quaternion.RotateTowards instead.

    3. Double check if your math is correct.
    You can insert a few Debugs to check if the actual angle is not 0 (before changing transform's rotation).

    4. For each quaternion approach, there a vector one (Which may be faster and easier to read / maintain).
    If you can illustrate what are you trying to achieve we'll probably figure something out.

    5.
    Code (CSharp):
    1. var theRay = transform.TransformDirection(Vector3.down);
    This one is probably can be transform.down.

    6. Reorder multiplication order:
    Code (CSharp):
    1. Vector3.forward * stickmagnitude * spd * Time.deltaTime
    To:
    Code (CSharp):
    1. stickmagnitude * spd * Time.deltaTime * Vector3.forward
    So instead of doing Vector3 (x, y, z) * float (3), Vector3 * float (), Vector3 * float, it will compile to float * float, float * float, float * Vector3, which will run faster.

    7. Time.deltaTime can be stored in a float variable inside method. Like float delta = Time.deltaTime.
    Each time you do Time.deltaTime that is an external c++ call. Its small, but in the end everything counts towards FPS count.

    8. Use Vector3.sqrMagnitude > 0 to check if the inputs are pressed instead of float comparison. Float comparison can be imprecise.
    Or, use stickMagnitude, because you've already got it.

    9.
    Code (CSharp):
    1. void OnCollisionEnter(Collision col)
    2.     {
    3.         if (col.collider)
    4.         {
    5.             airborne = false;
    6.             jumping = false;
    7.             gravity = 0;
    8.             jumping_drag = 0;
    9.             y_airspeed = -7;
    10.             jump = 0;
    11.             ang = 5;
    12.         }
    13.     }
    14.  
    Collision.collider is always true in this case. Also, CollisionEnter could be called multiple times. Which will modify ang as well. Be aware of that.
     
    Last edited: May 14, 2019
    koukido likes this.
  5. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    @xVergilx actually using getAxis and getKey is fine there, the problem is with the down/up variants that triggers with corelation to the Update loop.
     
  6. koukido

    koukido

    Joined:
    Mar 11, 2019
    Posts:
    3
    thanks for replying, you really went above and beyond with giving me plenty of options and i've since had an opportunity to finally read through and put your suggestions into practice

    i have some questions i'd like to ask and comments too and i'll also supply my notes of what i'm planning to achieve

    1. quaternion.rotatetowards relies on a 2nd quaternion to rotate to from the first rotation, how do i go about modifying that 2nd quaternion to work like a quaternion.angleaxis? i.e: only rotate on a local pivot

    2. i know my code for moving the character is flaud, but i simply use it to move around so i can test how the player object handles slopes,

    3. the math is correct and the order of everything seems to be irrelevant; adding quaternion.angleaxis at any point in the code makes the transform.up revert back to 0 as soon as the raycast is out of range...i debugged this as you suggested, and when using angleaxis, the transform.up seems to always be set to 0, but the raycast normal negates that, until it becomes out of range

    4. while i heeded your advice about using vector3.sqrmagnitude and i'll leave it that way, as it is still good practice, i noticed no difference in precision, granularity or stability when i switched over from float comparison


    that's all the questions and comments i've got for now, i've included a tagged-on png of my design notes, although i forgot to mention that you go very, very fast, too
     

    Attached Files: