Configurable Joints – Part 2

In the last tutorial, we learned about configurable joints, anchors, XYZ Motion, Angular XYZ Motion, Angular XYZ Limits, Target Rotation and Angular Velocity, as well as, Angular XYZ Drives.

In this lesson, we are going to learn how it works when connected to one or more other configurable joints to start to create a body. The final tutorial will go over configuring a rigged character and making it stand and balance. So let’s get started.

Rename our Cube to Forearm. Press Ctrl+D or right click and click duplicate. Rename this to Upper Arm and drag the green arrow directly up to look below. Leave a little space so we can see the rotations a bit better. If we just press play, the joints act like the aren’t connected and will both swing like how we set up our forearm.

Next we are going to reset the configurable joint to our elbow. Right click the upper arm and click reset. First we want to lock the XY and Z motions as we don’t want it to move laterally. Next we want to look closer at the connected body. If we drag the ForeArm rigidbody to the Upper Arm we get the below. Not what we are going for. In this case it looks like the top of the forearm is connected to the top of the upperarm by an imaginary line. So they rotate around themselves. (for the purpose of this gif, i locked the Y and Z axis on the upperarm).

The basic idea is we want to attach the upper portion to the lower. So click on the fore arm and drag the upper arm to the connected body. If you press play they will appear to cooperate closer to a working arm. Let’s get the angle to make it seem more like an upper arm. For some reason the X axis is the only one in which we can define both a high an low limit. All other axes are mirrored. So if you say 30 degrees, that is plus and minus 30. That means you have to be careful about setting a limited angle if the backwards angle doesn’t make sense. (I do believe there is a way around by creating another rigidbody in between, but I think we can solve this problem by just being more restrictive). Also in Unity’s how to, it states “Avoid small Joint angles of Angular Y Limit and Angular Z Limit. Depending on your setup, the minimum angles should be around 5 to 15 degrees in order to be stable. Instead of using a small angle, try setting the angle to zero. This locks the axis and provide a stable simulation.”

So the shoulder is a ball and socket joint instead of a hinge. This means it has a bit more flexibility in motion. So if you hang your arm down, you can move it backwards, maybe 30 degrees and you can reach straight up. This means we should set the Angular X Motion to Limited. Set the Low Angular Limit to -30 and the High Angular Limit to 175. Straight up should be 180, but remember last lesson the quaternions approach infinity, and so unity won’t let us put anything higher than 177. Let’s use 175 to be safe. I am going to Lock the Y and Z angular motions, but we will come back to it shortly.

Wow, that already looks like an arm. So next let’s think about the Z axis. The Z axis would be raising your arm laterally to your side. If we set it to 90 degrees, our arms will also be able to flail across our chest in the other direction (which is possible, but not desired). I found a workaround using the physics IgnoreCollision call. What this will do is make the leftArm not be able to move through the leftUpperLeg. At least I think it will. We may test this later (but add this to the Awake() or Start() functions. So let’s set the Angular Z motion to limited and the Angular Z limit to 90.

Physics.IgnoreCollision(leftArm.GetComponent<Collider>(), leftUpperLeg.GetComponent<Collider>(), true); 

It works great, but the issue we run into is a nearly endless pendulum. The lower limbs keeps adding swing power to the upper joint. As we messed with last lesson the springs should help. Now you might make the mistake I made initially an try and fix the angular XYZ limit springs. Those affect the springiness when the arm reaches the limits. So a spring when you reach up might bounce and spring back. What we want is the Angular XYZ Drive Position Springs. We want to set both the Angular X Drive Position Spring and the Angular YZ Drive Postion Springs. I recommend /100. The lower value on the X axis because we normally swing our arms that way. But you can mess around with this as you deem fit. We aren’t going for 100% accuracy, but close enough to prep movement.

This looks pretty good so far. But notice at the end how the forearm keeps twisting more than we would like? Let’s go back to the forearm and set the YZ position spring to 50.

Wow much better! So now that we have a good working arm, let’s see if we can make it do something. So let’s create a C# script. First we will start with defining our variables. We want to create a gameobject for our upper arm which we will move. Then in our start function we want to get the starting rotation information and store it for later. Basically to use it to reset our position to normal.

    public GameObject upperArm;
    private Quaternion startingUpperArmRotation;

    void Start()
    {
        startingUpperArmRotation = upperArm.GetComponent<ConfigurableJoint>().targetRotation;
    }

After that we want to create an input manager. The idea is when we press a button it does something. In this case we will call the function within the Update() function. Then if we see that the Up button is pressed, we want to call the MoveArmUp() function. If the down button is press, we want to call the MoveArmDown() function.

    // Update is called once per frame
    void Update()
    {
        InputCheck();
    }

    void InputCheck()
    {
        if(Input.GetKeyDown(KeyCode.UpArrow))
        {
            MoveArmUp();
        }
        if(Input.GetKeyDown(KeyCode.DownArrow))
        {
            MoveArmDown();
        }
    }

So now let’s actually define the MoveArmUp and MoveArmDown functions. As we did earlier, we messed with the Target Rotation Z number to help rotate and push the block to rotate towards that particular angle. In this case we want to set it Target Rotation to (0,0,-1,1). NOTE: My unity crashed and I didn’t save mid writing this, so play with the z being -1 or 1 depending upon what you are trying to do. This can be done using the Quaternion Lerp function. This calculates smoothly how to go from one rotation to another. Since we have to deal with Quaternions, and we have a fading familiary with them, best we stick with that. However I think there might be a way to convert it all to euler angles and might do that later.

    void MoveArmUp()
    {
        //Set Target Rotation of Upper Arm to 90 degrees parallel
        //Lerp is from rotation, to rotation, speed)
        upperArm.GetComponent<ConfigurableJoint>().targetRotation = Quaternion.Lerp(upperArm.GetComponent<ConfigurableJoint>().targetRotation, new Quaternion(0,0,-1,1), 6);
    }

    void MoveArmDown()
    {
        upperArm.GetComponent<ConfigurableJoint>().targetRotation = Quaternion.Lerp(upperArm.GetComponent<ConfigurableJoint>().targetRotation, startUpperArmPos, 6);
    }

So On MoveArm() we set the Target Rotation of the Configurable joint component of the Upper Arm to a Lerp of the current rotation, to a new Quaternion that we believe will be the arm up, and a speed of 6. If we changed the input manager to be while pressed, we should add *Time.fixedDeltaTime next to the 6. The 6 by the way is the speed. I just picked it, play around and see how it changes the speed of movement.

Next up we drag this script to the upper arm. Provided here in case you run into errors. Then we drag the upper arm gameobject to the public UpperArm variable within the script.

So there we go, we have a working configurable joint and able to move it on command.

Making a Body

So next we want to create a body, head and the other arm. Duplicate the Arms and rename them. Move them Over. Create a 3D cube and keep it 1,1,1 scale and put in inbetween both arms. Create a head and make it .5,.5,.5 scale. Position it so everything is lined up. Then Add a configurable joint component to the head and body. Next add the Body to the Connected Body for both upper arms and the head. Next lock the XY and Z Motions for the head and body. We should have something like below.

Notice the head looks a little odd. Let’s change the anchor’s Y value from .5 to 0. This stabilizes the head a bit more. While we are talking the head, move your head around. Turn it left and right, you can do about a 90 degree turn both ways around the Y. Tilt your ears to your shoulders, thats maybe a 45, but maybe you can go more and that is the Z axis. now tilt your head forward and back around the X axis. I’m thinking forward is maybe 80 and back is -45. Let’s try those out., dont’ forget to set the Angular XYZ to limited, or it won’t even read the limits we put in. I am going to add some quick eyes using capsules, so we know which way is the face.

I think that looks half way decent. It moves a bit too freely, let’s add some stiffness to the neck. Change the Angular X Drive to 10 and the Angular YZ drive also to 10. Now we can see it’s stiffness is confirmed.

So we can also go in and change our script to handle both arms. Simply add another gameobject as a variable, duplicate the lines but make it so one is left and one is right. Then the major difference is below for the Quaternion. Instead of -1 which is 90 degrees to the characters right, the arm should be 1 which is 90 degrees to the characters left. See below.

upperArmRight.GetComponent<ConfigurableJoint().targetRotation = 
Quaternion.Lerp(upperArmRight.GetComponent<ConfigurableJoint().targetRotation, 
new Quaternion(0,0,-1,1), 6);       
upperArmLeft.GetComponent<ConfigurableJoint().targetRotation = 
Quaternion.Lerp(upperArmLeft.GetComponent<ConfigurableJoint().targetRotation, 
new Quaternion(0,0,1,1), 6);

A few things before we depart. You likely want to create a parent Object for the Character and attach the script to it. We didn’t mess with the chest, but we will next lessons. Unity rigging uses the hips as the stability point. So we will want the upper body, which will represent twisting the spine. We will also add legs and feet. We also didn’t change any mass, as everything is 1. That isn’t quite normal and so will check what unity does with their ragdoll wizard and also check academic literature. See you next lesson.


9,670 Comments

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.