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

Rotation script freaks out for angles >45 degrees

Discussion in 'Scripting' started by m0nkeybl1tz, Mar 5, 2020.

  1. m0nkeybl1tz

    m0nkeybl1tz

    Joined:
    Feb 10, 2013
    Posts:
    27
    Hey all, this is a bit of an odd one.

    I wrote some simple code that allows users to rotate an object by grabbing a handle:

    Code (CSharp):
    1.  
    2.     void Update()
    3.     {
    4.        perpendicularDir = Vector3.Normalize(transform.position - pair.position);
    5.        Vector3 moveAxis = Vector3.Cross(transform.up, perpendicularDir).normalized;
    6.        alignedOffset = Vector3.Dot(totalOffset, moveAxis) * moveAxis;
    7.        ChangeTransform(alignedOffset);
    8.     }
    9.  
    10.     public override void ChangeTransform(Vector3 offset)
    11.     {
    12.         float sign = Mathf.Sign(Vector3.Dot(offset, Vector3.Cross(transform.up, perpendicularDir)));
    13.         controlledObject.rotation = startRot * Quaternion.AngleAxis(offset.magnitude * speed*sign, transform.up);
    14.     }
    15.  
    I know it's a lot of weird vector math, but here's what it looks like:



    The blue line is
    perpendicularDir
    which is the vector between the handle and its "pair" on the opposite side of the controlled object. The red line is the handle's `transform.up` and I do a cross product on these two to get the green line
    moveAxis


    I then pass
    moveAxis
    to the
    ChangeTransform
    function, and try rotating the controlled object around the handle's up axis based on how much the controller has moved.

    This all works up until about 45 degrees in either direction, but once I cross 45 degrees the controlled object starts freaking out, basically rotating infinitely quickly. Does anyone know why this would work up until 45 degrees but freak out after?
     
    Last edited: Mar 5, 2020
  2. kru

    kru

    Joined:
    Jan 19, 2013
    Posts:
    452
    Do you recalculate the values of the handles after moving them each frame?
     
  3. m0nkeybl1tz

    m0nkeybl1tz

    Joined:
    Feb 10, 2013
    Posts:
    27
    Sorry, you mean things like perpendicularDir and moveAxis? Yes I calculate those each frame. I updated my code to reflect that.
     
  4. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    So I'll mention there's a lot of variables/syntax in here that implies values could come from other places... so it makes unraveling your code hard.

    For example:
    totalOffset - what is this? Why are you dotting moveAxis onto it? Where is it set?
    startRot - I'm assuming this is the rotation the controllerObject started at based on name alone? But because we don't see where it comes from, that's just an assumption.
    speed - same as startRot

    Then you have variables that are class level, why?
    alignedOffset - why is this a class level field yet is set and sent as the parameter for ChangeTransform? This is peculiar...
    perpendicularDir - you set this in Update, but instead of passing it to ChangeTransform you keep it as a class level field. More so, the only thing ChangeTransform uses it for is to recalculate the cross of up and perpendicularDir, which is moveAxis in Update. Why not store moveAxis instead of redoing an cross product? I also notice you normalize it in Update, but don't in ChangeTransform, though we know that up is a unit vector and perpendicularDir is a unity vector, which means its cross is going to be a unit vector... so what's the point of the costly normalized?

    And of course the method ChangeTransform...
    This method is both public and overridden yet it relies on states that are set during Update. This screams big problems to me.

    First off ANYONE can call this method. It's public... is this intended to be called form multiple places other than just your Update method? If not... why is it public?

    Also it's overridden. This means whatever class you inherited from has the method defined. This implies that the parent class is either calling it or expects it to be publicly called at some point. When is it called? Does the parent class also call it in Update? Wait... your Update class here is not overriden though... that means you've wiped the parent Update class (since Unity reflects its messages out it makes private versions of messaging methods in inherited classes act in a not so obvious manner... basically it only calls the first one it found).

    Anyways, my point is that all of this syntax is implying that these methods may be called in more places than just the Update that you show here. And since the implementation of ChangeTransform relies on internal state that is modified by Update, that's a huge implication (the fact that it accesses perpendicularDir). It means that if perpendicularDir isn't properly set before calling ChangeTransform you can get unexpected behaviour. Is this the cause of your problem? Who knows... it could be! It might not be!

    ...

    TLDR;

    The code supplied lacks enough information to allow us to make an educated assessment of your problem with out making grave assumptions about your code.

    Furthermore a lot of the syntax are code smells that suggest a novice level of implementation. This compounds the previous unknown knowledge. Any assumptions we would have to make are now going to be coloured by that presumption of novice design. I can't trust that "startRot" is and only ever is the rotation of the object on start, who knows what you do with it. You may use it as a random cache variable in other methods for all I know. There's no way for me to assume how you use this code and if there is any rogue code out their calling it out of sync.

    Now of course I could just look at this in a pure mathematics manner... but there's not a lot of fun trying to break down your math when 3 of the variables are complete unknowns. As a math major my immediate reaction is "the problem is unsolvable due to undefines".
     
    Last edited: Mar 5, 2020