RevoluteJoints and Limits for Ragdoll

Discuss any questions about BEPUphysics or problems encountered.
Post Reply
reeda1283
Posts: 20
Joined: Fri Dec 16, 2011 10:12 am

RevoluteJoints and Limits for Ragdoll

Post by reeda1283 »

Hi again,
I am now trying to improve my skeleton so that it behaves more like a real human skeleton, and one of my first steps is trying to use revolute joints for the elbows and knees.

I have managed to get knee joints working with the joint rotating around the proper axis, however I have not been able to figure out how to get the rotation limits to work. No matter what values I use for MaximumAngle and MinimumAngle I am consistently seeing backward rotation on the knee from the starting angle.

So my questions are:
1. The ragdoll begins in bindpose, with the thigh and shin bones lined up and on top of each other. Since this how the ragdoll is setup when its joints are attached, does this orientation represent a 0 degree angle?
2. Am I doing something inherently wrong when I am creating the joint and setting up the limits?

Code: Select all

//Connect the upper leg to the lower leg
            revJoint = new RevoluteJoint(upperLimb, lowerLimb, upperLimb.Position +
                new Vector3(0, -1f, 0), new Vector3(1, 0, 0));
            revJoint.Motor.IsActive = false;
            revJoint.Limit.MaxCorrectiveVelocity = .5f;
            revJoint.Limit.MaximumAngle = 0;
            revJoint.Limit.MinimumAngle = (float) Math.PI/2;
            Add(revJoint);
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: RevoluteJoints and Limits for Ragdoll

Post by Norbo »

1. The ragdoll begins in bindpose, with the thigh and shin bones lined up and on top of each other. Since this how the ragdoll is setup when its joints are attached, does this orientation represent a 0 degree angle?
Generally, yes. This isn't always true of constraints, though. They can be configured such that '0' is any desired state. Limits all of some kind of measurement basis attached to one entity (connection A by convention) and the thing which is measured attached to the other entity (connection B by convention). By changing the measurement basis or measurement target, the meaning of the angles can be changed.

The RevoluteJoint is a group of constraints whose constructor makes some assumptions on construction. It configures the limit with some reasonable defaults based on the initial relative state of the involved entities, though these guesses aren't always what is wanted.
2. Am I doing something inherently wrong when I am creating the joint and setting up the limits?
In a RevoluteJoint, the BallSocketJoint and RevoluteAngularJoint are active by default while the RevoluteMotor and RevoluteLimit are inactive by default. So, the limit must be explicitly activated (and the motor does not need to be explicitly deactivated). The MaxCorrectiveVelocity should probably be left at the default value, too, unless there's a reason to change it.

The MinimumAngle is larger than the MaximumAngle, so the allowed range wraps from Pi/2 all the way back around to the maximum angle (0 is equivalent to 2pi). That's 270 degrees and probably not what you are looking for in a knee joint.

If you wanted to change the meaning of the angles (i.e. make 90 degrees a different relative state than the default initialization's interpretation), you can change the measurement basis by changing the revoluteJoint.Limit.Basis and the measurement target by changing the revoluteJoint.Limit.TestAxis. The basis is attached to connection A and the test axis is attached to connection B.

The basis has two axes. The primary axis should be aligned with the RevoluteAngularJoint's axis of rotation. This primary axis is the normal of a plane. On that plane lies the basis's X axis; the X axis defines what 0 is. That is, if the test axis from connection B projects onto that measurement plane and the result is aligned with the X axis, the angle is 0. Negating the basis's primary axis negates the measured relative angle.

So, for example, here's a slightly modified version of the code you posted:

Code: Select all

            var thigh = new Cylinder(new Vector3(0, 5, 5), 2, 0.8f, 5);
            var shin = new Cylinder(new Vector3(0, 3, 5), 2, 0.8f, 5);
            CollisionRules.AddRule(thigh, shin, CollisionRule.NoBroadPhase);
            Space.Add(thigh);
            Space.Add(shin);

            var revoluteJoint = new RevoluteJoint(thigh, shin, thigh.Position + new Vector3(0, -1f, 0), new Vector3(1, 0, 0));
            revoluteJoint.Limit.IsActive = true;
            revoluteJoint.Limit.MaximumAngle = (float)Math.PI / 2;
            revoluteJoint.Limit.MinimumAngle = 0;
            revoluteJoint.Limit.Basis.SetWorldAxes(new Vector3(1, 0, 0), new Vector3(0, 0, 1));
            revoluteJoint.Limit.TestAxis = new Vector3(0, 0, 1);

            Space.Add(revoluteJoint);
By default, the constructor set (0,-1,0) to represent 0 on the measurement plane and set the test axis accordingly. That default is overridden in the above by setting the basis and test axis. I chose (0,0,1) to represent 0 on the measurement plane. The test axis is changed to (0,0,1) as well so that the limit is at 0 relative angle at initialization.

On the revoluteJoint.Limit.Basis.SetWorldAxes line, if I change the first parameter (the primary axis) to (-1,0,0) instead of (1,0,0),the limit flips and the knee can bend the opposite way.

I'd recommend playing around with it in the demos so you can get quickly isolate and visualize the behaviors.
reeda1283
Posts: 20
Joined: Fri Dec 16, 2011 10:12 am

Re: RevoluteJoints and Limits for Ragdoll

Post by reeda1283 »

Ahh thanks Norbo. I thought I had read that both the motor and limit were ACTIVE by default and never thought twice about it.

That code was copy-pasted during a session of endless tweaking of the numbers to see if I could get anything to work. Setting the limit to active resolved pretty much everything, and thanks for the tip about making sure connected joints don't have collisions, as that definitely helps curb some odd behavior.

Someday I will actually get my model to properly follow my now near-perfect ragdoll and all will be good!
Post Reply