Search Unity

[SOLVED] How Can I Make Ik Work With Configurablejoints On A Humanoid Rig?

Discussion in 'Physics' started by Nyanpas, Apr 15, 2019.

  1. Nyanpas

    Nyanpas

    Joined:
    Dec 29, 2016
    Posts:
    406
    Greetings,
    I have observed the following URLs prior to asking this question:
    https://gist.github.com/mstevenson/4958837
    https://forum.unity.com/threads/quaternion-wizardry-for-configurablejoint.8919/
    https://answers.unity.com/questions/278147/how-to-use-target-rotation-on-a-configurable-joint.html

    However, this does not seem to work when the target rotation is of the CCDIK-kind. This is what I have tried so far for a chain that consists of ConfigurableJoints from the hand as the effector, the forearm, upper arm, and to the shoulder as the base where the different joints are not hierarchical but on the same level (but I have also tried hierarchical):

    Code (CSharp):
    1. for(int c = 1; c < Segments.Count; c++)
    2.             {
    3.                 Quaternion targetOrientation = Quaternion.FromToRotation(Segments[0].transform.position - Segments[c].transform.position, Target.position - Segments[c].transform.position)
    4.                 //* Segments[c].transform.rotation
    5.                 ;
    6.  
    7.                 //Segments[c].transform.rotation = targetOrientation;
    8.                 //Segments[c].TheJoint.targetRotation = Quaternion.Inverse(targetOrientation);
    9.                 Segments[c].TheJoint.SetTargetRotation(targetOrientation * Segments[c].transform.rotation, Segments[c].StartLocalRotation);
    10.                 //Segments[c].TheJoint.SetTargetRotation(Quaternion.FromToRotation(Segments[0].transform.position - Segments[c].transform.position, Target.position - Segments[c].transform.position), Segments[c].StartRotation);
    11.                 //Segments[c].TheJoint.SetTargetRotationLocal(Quaternion.FromToRotation(Segments[0].transform.position - Segments[c].transform.position, Target.position - Segments[c].transform.position), Segments[c].StartLocalRotation);
    12.                 //Segments[c].TheJoint.targetRotation =
    13.                 //Segments[c].transform.rotation *
    14.                 //Quaternion.Inverse(Quaternion.FromToRotation(Segments[0].transform.position - Segments[c].transform.position, Target.position - Segments[c].transform.position))
    15.                 //(Quaternion.FromToRotation(Segments[0].transform.position - Segments[c].transform.position, Target.position - Segments[c].transform.position))
    16.                 // * Segments[c].transform.localRotation
    17.                 //* Segments[c].transform.rotation
    18.                 //* Quaternion.Inverse(Segments[0].transform.localRotation)
    19.                 ;
    20.             }
    I can almost get it to work, but some angles will always be off, especially for the upper arm (and there are jitters, of course):

    targiter.gif

    I am terrible at maths and rotations and I have tried a few things as you can see, but nothing seems to work to make the segments behave as an IK-chain. However, it does work when I simply set the transform's rotation to (targetOrientation * transform.rotation) without using ConfigurableJoints, but then I am back to start again;

    Please help if you can. It is much appreciated. ;w;

    In case you want to see how the ragdoll works (without the IK), you can see it here compared to the Unity's ragdoll wizard (on the right in a spooky outline):

    doller.gif
     
    Last edited: Apr 15, 2019
  2. Nyanpas

    Nyanpas

    Joined:
    Dec 29, 2016
    Posts:
    406
    I can't really afford to wait 3 years for an answer to this (which seems to be the average answering time for questions like these that not many people go in-depth with using), so I have tried for a few more days now to get it to work, and I have made progress with removing the jittering and other issues with instability, but the targeting still isn't going as it should.

    Why is targetRotation not based on the rotation of the GameObject it is on? Why does it have to be its own orientation system? This problem could have been solved if it was as simple as using it like you would for a transform.rotation or even transform.localRotation... I see that the other people who have worked with this also have tremendous issues working around it, and it all seems rather hacky and in the best case inelegant.
     
  3. Partel-Lang

    Partel-Lang

    Joined:
    Jan 2, 2013
    Posts:
    2,554
    Code (CSharp):
    1. Quaternion targetOrientation = Quaternion.FromToRotation(Segments[Segments.Length - 1].transform.position - Segments[c].transform.position, Target.position - Segments[c].transform.position)
     
  4. Nyanpas

    Nyanpas

    Joined:
    Dec 29, 2016
    Posts:
    406
    I am sorry, but that didn't work. The arm points back and remains there. (I had to switch from .Length to .Count as this uses a list.)

    If I try it with:
    Code (CSharp):
    1. _segment.transform.localRotation = targetOrientation * _segment.transform.localRotation;
    It wiggles uncontrollably. According to CCDIK-specification it should be the effector's position, not the base (maybe FABRIK or some other method does that, I am not sure), and this method works when I do:
    Code (CSharp):
    1.  Quaternion targetOrientation = Quaternion.FromToRotation(Segments[0].transform.position - _segment.transform.position, Target.position - _segment.transform.position)
     
  5. Nyanpas

    Nyanpas

    Joined:
    Dec 29, 2016
    Posts:
    406
    [An update]

    I have almost managed to get this to work now using:

    Code (CSharp):
    1. _segment.TheJoint.targetRotation = _segment.LocalToJointSpace * Quaternion.Inverse(targetOrientation * _segment.transform.localRotation) * _segment.StartLocalRotation;
    or
    Code (CSharp):
    1. _segment.TheJoint.targetRotation = _segment.LocalToJointSpace * Quaternion.Inverse(targetOrientation * _segment.transform.rotation) * _segment.StartLocalRotation;
    armyr.gif
    The ghostly shader represents standalone transforms, and the toon shader represents nested transforms for the arm.

    As you can see, it works a little bit in certain areas and ranges but then it gets all weird and unpredictable.

    I don't want to use a second rig that this copies the poses from, as I want to be able to do it with just one rig. Currently it is only using one rig per skinned mesh.
     
  6. Nyanpas

    Nyanpas

    Joined:
    Dec 29, 2016
    Posts:
    406