Search Unity

Help! Limiting movement of bones in a simulator (Vector3 and Quaternion)

Discussion in 'Scripting' started by Berthil, Oct 17, 2015.

  1. Berthil

    Berthil

    Joined:
    Aug 26, 2013
    Posts:
    22
    Hi. This is my first post. Sorry if its on a wrong place.

    Im trying to limit an arm movement using different approaches but none worked to so far.

    I built a character on blender with 4 bones in the arm (2 for rotation and 2 for twist).

    1st approach:

    I have used Vector3 to angle the bones, but i need to limit the rotation on arround 90 degres so the arm dosnt pass its bend limits. In this case the shoulder rotates (bone1) and the forearm too (bone2).



    Code (CSharp):
    1.     public int RotSpeed;
    2.  
    3.  
    4.     void Update () {
    5.  
    6.  
    7.         if (Input.GetKey ("w"))
    8.         {
    9.             transform.Rotate( 0, RotSpeed * Time.deltaTime,  0  );
    10.         }
    11.  
    12.         if (Input.GetKey ("s"))
    13.         {
    14.             transform.Rotate( 0, -RotSpeed * Time.deltaTime, 0  );
    15.         }
    16.     }
    17. }
    I read in the forum that its impossible to limit the rotation of the Transform component using Vector3. Is there a way? Can i make the rotation stop when Y rotation value reaches 90 for example?

    2nd approach:

    So i read here in the forum that i need to use Quaternion to clamp the rotation. It worked, but while i make the rotation of one bone the other one doesnt rotate along as it does using Vector3:



    Code (CSharp):
    1.  
    2. public float speed = 10.0f;
    3. public float Rotate;
    4.  
    5.     void Update () {
    6.    
    7.         transform.rotation = Quaternion.Euler ( Mathf.Clamp(Rotate, -90, 90),0, 0);
    8.  
    9.         if (Input.GetKey ("w"))
    10.         {
    11.             Rotate -=speed * Time.deltaTime;
    12.         }
    13.  
    14.         if (Input.GetKey ("s"))
    15.         {
    16.             Rotate +=speed * Time.deltaTime;
    17.         }
    18.     }
    19. }
    20.  
    This project will be used on an rehabilitation exoskeleton development. So all it does is to move the arm to simulate its movement.

    I am new on scripting. Just start learning C# for unity.

    I appreciate any help on this.

    Thanks!
     
  2. ChrisSch

    ChrisSch

    Joined:
    Feb 15, 2013
    Posts:
    763
    I'm definitely not an expert on rotation, but I think you need to show some numbers, to do more than guessing. The bones can vary a lot from character to character. :)

    Like, whats the rotation value of the bone in its "straight" resting position, and whats the value when you move it inwards to the max you want. Get these numbers by first playing the scene (and pausing) then move the bones yourself. Why? Because while in editor Unity lets you rotate the object into negative values, but when you play it, that then becomes a positive value, because it can't be negative. For example if you set it to -30, that will become 330 when you play (360+(-30)).

    Yes you can definitely limit rotation with clamping, however I think it depends on the case as to how.
     
  3. Berthil

    Berthil

    Joined:
    Aug 26, 2013
    Posts:
    22
    Hi CrisSch. Thanks for your repply. I did what you sugested and i got a little confused. The numbers are odd.
    Z jumped to 270 in the middle of the movement. I need to study it to understand it better. X behaved normally adding 90 to its value. Can i use this value to stop the rotation, using it as a variable or something like this? I couldnt find it in the foruns. Everyone suggest quaternion, but i got this problem with quaternion i cant resolve.

    Using Vector3 while moving the arm bone, the forearm bone queeps its value, but using quaternion both values of the arm and forearm changes.

    Thanks
     
  4. ChrisSch

    ChrisSch

    Joined:
    Feb 15, 2013
    Posts:
    763
    Don't you just love rotations? :)

    As I see you're only rotating that bone around the Y axis (don't know about the silly other axis values). Where do you want the limits for the bones to be? Like on the screens? If so then you can try:


    Code (CSharp):
    1. //"thatBone" is the bone transform we're limiting. just reffering to it like that
    2.  
    3. Vector3 thatBoneEuler = thatBone.rotation.eulerAngles; //getting euler values of the quaternion
    4.  
    5. float clampedY = Mathf.Clamp(thatBoneEuler.y, 270, 360); //this will clamp the Y value between 270 and 360, and store it into clampedY float we just declared
    6.  
    7. Vector3 newRot = new Vector3(thatBoneEuler.x, clampedY, thatBoneEuler.z); //creating a new rotation with the new clamped value
    8.  
    9. thatBone.rotation = Quaternion.Euler(thatBoneEuler); // changing the rotation to a quaternion version of the new rotation
    10.  
    11. //add this after your rotating code and let me know what happens
    Still hoping someone with more experience comes along and helps you. I haven't dealt with limiting rotations much. I did just yesterday for the first time in a long time (for the Turret System asset in the sig), and it was a struggle. :D
     
  5. Berthil

    Berthil

    Joined:
    Aug 26, 2013
    Posts:
    22
    Hi CrisSch. Yeah i love rotations kkk

    Thanks for your attention once more!!!

    I got an erro using your code (probaly my fault) but i managed the problem with the rotation using transform.localRotation

    When i add "local" to it, the forearm bone start to act like it is independent from the arm bone.

    Ill leave the code here if someone have the same problem.

    Parent bone ( it doesnt need the "local"):

    Code (CSharp):
    1. public float speed = 10.0f;
    2.     public float Rotate;
    3.  
    4.     void Update () {
    5.  
    6.         transform.rotation = Quaternion.Euler ( Mathf.Clamp(Rotate, -90, 90),0, 0);
    7.  
    8.         if (Input.GetKey ("w"))
    9.         {
    10.             Rotate -=speed * Time.deltaTime;
    11.         }
    12.  
    13.         if (Input.GetKey ("s"))
    14.         {
    15.             Rotate +=speed * Time.deltaTime;
    16.         }
    17.  
    Child bone (Needs the "local" at transform.localRotation):

    Code (CSharp):
    1. public float speed = 100.0f;
    2.  
    3.     public float Rotate = 0.0f;
    4.  
    5.     void Update () {
    6.  
    7.         transform.localRotation = Quaternion.Euler ( Mathf.Clamp(Rotate, -90, 90),0, 0);
    8.  
    9.         if (Input.GetKey ("e"))
    10.         {
    11.             Rotate -=speed * Time.deltaTime;
    12.         }
    13.  
    14.         if (Input.GetKey ("d"))
    15.         {
    16.             Rotate +=speed * Time.deltaTime;
    17.         }
    18.     }
    19. }