Ragdoll Joint Help

Discuss any questions about BEPUphysics or problems encountered.
Post Reply
Ardo
Posts: 2
Joined: Thu Dec 15, 2016 11:36 pm

Ragdoll Joint Help

Post by Ardo »

Hi I am new to physics in general and to Bepu, I've got this working so far for my ragdoll:

Image

Note: I render boxes for each of the joints, so you can see them in the gif. But they don't move which is intentional as I don't move the render boxes. They are just to show the starting location. Also the white spheres are lights.

I'm been looking at the Ragdoll sample but the joints code confuses me. Also In my code I only have a parent bone and child bone each time, so I can't distinguish between hip to leg or arm to forearm etc. So I was hoping there was some universal joint I could use?

My code as it generally is executed at the moment:

Code: Select all

    var parallelLooper = new ParallelLooper();
    
    //This section lets the engine know that it can make use of multithreaded systems
    //by adding threads to its thread pool.

    if (Environment.ProcessorCount > 1)
    {
        for (int i = 0; i < Environment.ProcessorCount; i++)
        {
            parallelLooper.AddThread();
        }
    }
    
    World = new Space(parallelLooper);

Code: Select all

World.ForceUpdater.Gravity = new Vector3(0, -9.81f, 0);

Code: Select all

        public void AddGround()
        {
            float width = 10000;
            float height = 20;
            float depth = 10000;

            ground = new Box(Vector3.Zero, width, height, depth);
            World.Add(ground);
        }

Code: Select all

        private void DxSurface_Update(object sender, UpdateEventArgs e)
        {
            World.Update(Atom.ElapsedSecs*10);
        }

Code: Select all

            for (int i = 0; i < rigidBodies.Length; i++)
            {
            var boxInfo = RagdollType.Info.RigidBodies[i];

                var physicsBody = new Box(
                                RagdollType.boneCenters[i], 
                                boxInfo.Depth / 2, 
                                boxInfo.Height, 
                                boxInfo.Width / 2, 
                                boxInfo.Height*boxInfo.Width*boxInfo.Depth);

                World.Add(physicsBody);            
            }
Current joint code, bit messy as just trying things out:

Code: Select all

for (int i = 0; i < RagdollType.rigidbodyJointDefaultWorlds.Length; i++)
{
    var parentBody = ...;
    var childBody = ...;
    var pos = childBone.head;
                
    var torsoTopToLeftArmBallSocketJoint = new BallSocketJoint(parentBody, childBody, pos);
    
    var torsoTopToLeftArmEllipseLimit = new EllipseSwingLimit(parentBody, childBody, Vector3.Left, 
    	MathHelper.Pi * .75f, MathHelper.PiOver2);
    	
    var torsoTopToLeftArmTwistLimit = new TwistLimit(parentBody, childBody, Vector3.Left, Vector3.Left, 
    	-MathHelper.PiOver2, MathHelper.PiOver2);
    	
    var torsoTopToLeftArmMotor = new AngularMotor(parentBody, childBody);
    torsoTopToLeftArmMotor.Settings.VelocityMotor.Softness = .2f;

    World.Add(torsoTopToLeftArmBallSocketJoint);
    World.Add(torsoTopToLeftArmEllipseLimit);
    World.Add(torsoTopToLeftArmTwistLimit);
    World.Add(torsoTopToLeftArmMotor);

    var leftUpperArmToLeftForearmSwivelHingeJoint = new SwivelHingeJoint(parentBody, childBody, pos, Vector3.Up);
    leftUpperArmToLeftForearmSwivelHingeJoint.HingeLimit.IsActive = true;
    leftUpperArmToLeftForearmSwivelHingeJoint.TwistLimit.IsActive = true;
    leftUpperArmToLeftForearmSwivelHingeJoint.TwistLimit.MinimumAngle = -MathHelper.Pi / 8;
    leftUpperArmToLeftForearmSwivelHingeJoint.TwistLimit.MaximumAngle = MathHelper.Pi / 8;
    leftUpperArmToLeftForearmSwivelHingeJoint.HingeLimit.MinimumAngle = -MathHelper.Pi * .8f;
    leftUpperArmToLeftForearmSwivelHingeJoint.HingeLimit.MaximumAngle = 0;

    //The SwivelHingeJoint has motors, but they are separately defined for twist/bending.
    //The AngularMotor covers all degrees of freedom.
    
    var leftUpperArmToLeftForearmMotor = new AngularMotor(parentBody, childBody);
    leftUpperArmToLeftForearmMotor.Settings.VelocityMotor.Softness = .3f;

    World.Add(leftUpperArmToLeftForearmSwivelHingeJoint);
    World.Add(leftUpperArmToLeftForearmMotor);
}

Code: Select all

public void ToggleIsActive()
{
    for (int i = 0; i < rigidBodies.Length; i++)
        rigidBodies[i].ActivityInformation.Activate();
}
My main problems seem to be:
  1. The arms bounce around and actually elongate. I really want them to not elongate at all. Docs say use ball socket joint for that but mine doesn't seem to work?
  2. I update at 60 fps, but found I need to pass Elapsed*10 into Update() to get good results, otherwise things move really slowly. Am I doing this right?
  3. I calc mass as box width*height*depth. Is this a good way to do it?
  4. I don't really need a perfect ragdoll, just something that looks right, where the joints stay together and don't intersect other parts of the body. At the moment it kinda becomes a heap on the floor (I think because there is no limit on joint rotation).
  5. I like what Blender has which is a joint where you can specify the min and max angles for XYZ axis. Is it possible to have something like that in Bepu? Then I can add a config option to set the angle limits so can have some variation for different bones.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Ragdoll Joint Help

Post by Norbo »

The arms bounce around and actually elongate. I really want them to not elongate at all. Docs say use ball socket joint for that but mine doesn't seem to work?
All constraints are actually springs in BEPUphysics. By default, they are very rigid, but not infinitely rigid. That kind of elongation could happen if the involved entities are extremely heavy. The default stiffnesses are tuned for objects with masses in the range 0.1 to 100. Note that you can change the spring settings on any constraint.
I update at 60 fps, but found I need to pass Elapsed*10 into Update() to get good results, otherwise things move really slowly. Am I doing this right?
This type of thing usually implies some kind of misconfiguration. For example, a 200 unit tall humanlike character with gravity set to (0,-9.81,0) will feel like you're on an asteroid instead of earth because earthlike gravity is 9.81 meters per second squared, while the 200 unit tall humanlike character is in terms of centimeters. So, the apparent 'speed' of falling will appear to be a factor of 100 off.

To fix it, first ensure that all your units are consistent across gravity, sizes, and velocities. I would recommend sizes around what the demos use- if you have something much larger or much smaller, you'll want to use something like the BEPUphysicsDemos ConfigurationHelper.ApplyScale to update the engine's tuning variables for the different scale. For example, if you want to use a scale 30x larger than the demos, call ApplyScale(30).

Also, modifying the time passed into Space.Update(dt) is not a great way to change the speed of the simulation. Unlike Space.Update() which simulates a single time step, Space.Update(dt) will simulate as many timesteps as it can to reach the accumulated time. Every timestep has a duration equal to Space.TimeStepSettings.TimeStepDuration. So, if you pass in a value 10x larger, it's basically asking the engine to simulate 10x as many timesteps- that'll slow things down a lot. (Note that the Space.TimeStepSettings.MaximumTimeStepsPerFrame limits this internal loop to 3 iterations per Space.Update(dt) call by default.)
I calc mass as box width*height*depth. Is this a good way to do it?
In the sense that an object with uniform density has a mass proportional to volume, yes, it's a decent approach. However, this can get you in some trouble. First, as you are probably already encountering, a large shape will have an absolutely huge mass relative to the ones seen in the demos. That can overwhelm the default constraint stiffness.

There is also a risk of causing mass ratio problems. Realistic masses aren't always a good choice in speed-oriented game physics solvers. For example, if a very heavy tank rolls over a very light box, the light box will not retain its rigidity- it'll get squeezed around and possibly out of the map, possibly introducing some weird boingy behavior to the tank as it does so. Similarly, a big heavy wrecking ball on the end of a series of light chain links will give the solver a very hard time and the chain links will tend to separate nonphysically. Keeping mass ratios closer to 1:1 helps this a lot.

(There do exist real time solvers that handle mass ratios better with some other tradeoffs, but I haven't implemented any in BEPUphysics. Maybe something for later :P)
So I was hoping there was some universal joint I could use?...
I like what Blender has which is a joint where you can specify the min and max angles for XYZ axis. Is it possible to have something like that in Bepu? Then I can add a config option to set the angle limits so can have some variation for different bones.
BEPUphysics doesn't have a single combined constraint that does that, but you can accomplish the same thing with a combination of constraints. If you haven't already seen it, check out the descriptions of different constraints in the documentation: https://bepuphysics.codeplex.com/wikipa ... umentation
(Notably, even if there were a single combined constraint, some kind of content processing would still be necessary to get it from blender's conventions to BEPUphysics's conventions unless I matched it perfectly.)
Ardo
Posts: 2
Joined: Thu Dec 15, 2016 11:36 pm

Re: Ragdoll Joint Help

Post by Ardo »

Hi Norbo thanks for your blazing fast response! I tweaked the gravity and mass as you said and the simulation started working as expected. With that, I could play around with the constraints and have now got something that looks good enough. Excellent stuff, didn't think I would be able to get a ragdoll setup in a day. You should be commended for creating such a brilliant piece of tech!
Post Reply