Latest  | Search | Go
Edit this page   |   Attach file 

  Home | Tutorials | Technical Reference | Runtime | API Documentation | RagDolls  


Creating Ragdolls with Reality Builder

Author: Jeremy Stieglitz

ragdoll_RB.jpg


Creating your Ragdoll in Reality Builder

The first thing you'll want to do to for your RagDoll is create your skinned Model, as described in SkinnedCharacters. You should also be familiar with the ideas contained in the RigidActors tutorial before proceeding. Then create a new scene, enable the Sky so you've got some lighting (Alt-W and then set "Enable Sky" = true), and Insert a 'RigidActorAnimated' Actor. Set its 'ModelFileName' Property to your skinned Model, adjust the ModelFrame (Bone) display size via the slider on the toolbar, and then you'll have a scene like this:

ragdoll1.jpg

Next, you should add Capsule Rigid Bodies to the primary ModelFrames (Bones) in your character. To best do this, go into wireframe mode and select the box representing each pertinent ModelFrame, and click on the "Capsule" button to add to add a Capsule Rigid Body to each pertinent ModelFrame (you can also use the "Clone" Rigid Body button to speed up this process). You will then have a setup that looks something like this:

ragdoll2.jpg

Note that you can also set the Mass of a selected RigidBody in the "General Tab", and select from a list of all the ModelFrames in the RigidActor in the "Frames" tab (and see which ModelFrames have been Linked to a RigidBody):

ragdoll3.jpg

You're now ready to setup Joints to get these Rigid Bodies to connect these RigidBodies together. Return to Wireframe mode, Click on the Joints dropdown and add Revolute Joints to link between between your lower legs & upper legs, and between your lower arms and upper arms. Add Spherical Joints to link between the upper legs & torso, upper arms & torso, and head & torso. Use Physics Visualization to aid in setting the Joint Limits on your Revolute Joints and pertinent Spherical Joints, and add a bit of Spring Damping to make the ragdoll suitably stiff. You should then have a setup that looks like this (examine Alien_RagDoll.xml in the EvalKit\Models folder for an example of this):

ragdoll4.jpg

Finally, add a BBox Prefab to the scene (via the Models folder in the Prefabs Tab of the AssetBrowser), scale it to provide a floor for your RagDoll to fall on, save the work-in-progress scene, and goto "Build/Rebuild All Collision Meshes" to update the collisions on this newly scaled box. Then run the physics and test & tweak your RagDoll physics until they are satisfactory:

ragdoll5.jpg

Note, you must delete the the BBox Prefab before you save your final RagDoll scene for use in-Game. This is because we will be spawning the RagDoll procedurally via Actor Precaching in-Game, and Actor Precaching does not allow more than 1 Actor per Precached Actor XML. So when you're done testing your RagDoll falling onto the Floor, delete that Floor Prefab and save your RagDoll scene which is now ready for us in-Game. So let's examine how a RagDoll RigidActor is actually used for Player's Model in-Game.


Using your saved Ragdoll RigidActor in-Game via Actor Precaching

To use our RigidActor Ragdoll for a Player Model in-Game, we're going to Precache the Ragdoll from its saved XML file (which we can then Clone for each Player), and then have the Player co-employ that RigidActor's 'MyModel'. First, in our Player resource loading code (in the EvalKit, it's all contained in AlienModelLoader), we'll PrecacheActor the saved XML RigidActor Ragdoll:

    /// -----------------------------------------------
    /// PRECACHED MEDIA
    /// -----------------------------------------------
    private static string ClassName = "AlienModelLoader";
    private static bool HasCached = false;
    ///
    static public int StaticRigidActorPointer = MPrecacher.PrecacheActorPointer(ClassName, "Alien_RagDoll.xml");
    static public RigidActorAnimated StaticRigidActor;

Note that in addition to Precaching the pointer for the saved RigidActor ragdoll, we'll also store a static Object reference to it. Next, we'll init some desirable settings on this static Object reference in this class' Precache() function:

    /// <summary>
    /// does precaching of resources and statics initialization
    /// </summary>
    private static bool initStatics = false;
    public static void Precache()
    {
        // one-time init of particular vars & media
        if (!initStatics)
        {
            initStatics = true;

            HasCached = MPrecacher.Precache(ClassName, HasCached);

            StaticRigidActor = (RigidActorAnimated)MActor.GetFromPointer(StaticRigidActorPointer);
            StaticRigidActor.GhostObject = true;
            StaticRigidActor.CreateFramesList();
            StaticRigidActor.StopPhysicsControl();
...

CreateFramesList() effectively initializes this static RigidActor's ModelFrame linking, and StopPhysicsControl() ensures that no physics are actually run on this static RigidActor. Next, when a new Player is created, we'll want to make Clones of this static RigidActor to use by each Player instance, like so:

    public static void SetupPlayer(PlayerBase player)
    {
        player.MyRigidActor = (RigidActorAnimated)MActor.CloneFromPointer(player.MyWorld, StaticRigidActorPointer);
        player.MyRigidActor.StaticModelToUse = StaticRigidActor.MyModel;
        player.MyRigidActor.CreateFramesList();
        player.MyRigidActor.StopPhysicsControl();
        player.MyRigidActor.IsHidden = true;
        player.MyRigidActor.AutoUpdateModelTransformation = false;
        player.MyRigidActor.UpdateMyModelLighting = false;
        player.MyRigidActor.Parent = player;
        player.MyModel = player.MyRigidActor.MyModel;
    ...

As you can see, we create the a new Clone of the original static Precached RigidActor for each new Player. Then we set some values on the new Clone RigidActor. We set its "StaticModelToUse" to be equal to the MyModel on the original static Precached RigidActor -- this will ensure that the new Clone RigidActor doesn't try to Load the Model all over again (instead it will just call CreateNewInstance for a shallow copy). Additionally, we call the CreateFramesList() and StopPhysicsControl() functions just like we did for the static Precached RigidActor, which effectively initializes the ModelFrame linking but disables the physics (temporarily in this case).

Also, we need to set set the Cloned RigidActor to "IsHidden" (since the Player alone will handle drawing of the Model), and its "AutoUpdateModelTransformation" to false (since the Player will handle Updating of the Model), and set the RigidActor's Parent to the Player. Finally, the most important step, we use the RigidActor's MyModel also as the Player's MyModel! This allows the Player to treat the RigidActor's Model as the Player's own Model, with the Player having responsibility for Updating it (unless Physics are enabled on the RigidActor).

So that's all the setup we need to do to setup a Cloned RigidActor for a new Player. Now let's look at what the Player actually does to transition in and out of Ragdoll Physics. First, in the Player class we'll want to declare a variable to store the RigidActor instance that this Player is using:

    /// <summary>
    /// RigidActor used as the RagDoll and for this Player's MyModel
    /// </summary>
    public RigidActorAnimated MyRigidActor;

Next, let's create function to Start Physics on the Ragdoll when the Player has died and Stop Physics when the Player has respawned:

    protected void ActivateRagdoll()
    {
        if (MHelpers.IsDedicated())
            return;

        MyRigidActor.Location = Location;
        MyRigidActor.Rotation = newRot;
        MyRigidActor.StartPhysicsControl();
     }

    protected void DeactivateRagdoll()
    {
        if (MHelpers.IsDedicated())
            return;

        MyRigidActor.StopPhysicsControl();
    }

All we do is copy the Player's current Location and Rotation into the Player's RigidActor, and Start Physics!

Now let's look at cleaning up this Player's RigidActor in Player.DisposeResources()

    protected override void DisposeResources()
    {
        /// Normally we wouldn't nullify MyModel upon disposal, 
        /// but we know this MyModel is also owned by our RigidActor, 
        /// so we'll let the RigidActor dispose of it
        MyModel = null;
        if (MyRigidActor != null)
        {
            MyRigidActor.Destroy();
            MyRigidActor = null;
        }
     ...

Note that we set this Player's MyModel = null before Destroying this Player's RigidActor. That's because the Model is also owned by the MyRigidActor, and so when the MyRigidActor is Destroyed it will delete the Model. If we didn't set MyModel = null for the Player, the Model would get deleted twice (bad!).

A few more things to keep in mind: your Player class should have "AutoUpdateModelTransformation = false;", and manually cally MyModel.Update() when you want to update the Model's animation transformations. Never call MyModel.Update() when you're in ragdoll state, or you'll override the ragdoll transformations! Note what PlayerBase.cs does in the Player class:

Player ctor:
        AutoUpdateModelTransformation = false;

Player PreRender:
    public override void PreRender(MCamera camera)
    {
            // if not dead, update the model's transformation according to the Player's Rotation
            if (!IsDead())
            {
                ....
                // Finally update the Player's Model which will increment its animations 
                // and apply all the hierarchial transformations
                MyModel.Update();
            }
     }

This ensures that when the Player is not in a ragdoll state (not dead), we manually update the Model, and when he is dead we leave it to the RigidActor to update the Model with the ragdoll transformations.

Finally, when we Start physics on the RigidActor, we could also apply some impulses to the newly-activated ragdoll, like so:

    protected void ActivateRagdoll()
    {
        if (MHelpers.IsDedicated())
            return;

        // we should clear any custom bone influences before activating our ragdoll
        MyModel.SetFrameInfluence(spineBone, MHelpers.IdentityMatrix);
        MyRigidActor.Location = Location;
        MyRigidActor.Rotation = newRot;
        MyRigidActor.StartPhysicsControl();

        MVector velocity = Velocity;
        float totalMass = MyRigidActor.TotalMass;

        if(velocity.Length() < 7)
            MyRigidActor.ApplyImpulseToFrame("Bip01_Pelvis", velocity * totalMass, Location);

        if (deathImpulseAmount > 0)
            MyRigidActor.ApplyImpulseToClosestFrame(deathImpulseAmount / 42.0f * totalMass, deathImpactPoint);
    }

The two impulses ensure that:

  • The character's overall movement Velocity is applied to his central bone
  • The specific place that the character was shot to death is given an extra impulse, so that the character falls accordingly


Now you know how to create Ragdolls in Reality Builder, using RigidActorAnimated, and utilize them in-Game by Cloning them from your saved Actor XML and co-employing their Model as your Player Character's MyModel. This technique of setting up Actors in Reality Builder and then Precaching & Cloning them in-Game also has uses far beyond Ragdolls: visually-configured particle FX, Triggers, and arbritrary physics objects such as Vehicles can all be spawned in this way.

Attachment sort Action Size Date Who Comment
ragdoll_RB.jpg manage 147.1 K 14 May 2005 - 11:49 Main.guest  
ragdoll1.jpg manage 99.0 K 29 May 2005 - 20:04 Main.guest  
ragdoll2.jpg manage 111.8 K 30 May 2005 - 05:15 Main.guest  
ragdoll3.jpg manage 36.3 K 30 May 2005 - 05:15 Main.guest  
ragdoll4.jpg manage 212.6 K 30 May 2005 - 05:39 Main.guest  
ragdoll5.jpg manage 201.8 K 30 May 2005 - 06:07 Main.guest  
AttachingActor.jpg manage 46.9 K 31 May 2005 - 02:23 Main.guest  
SSM.jpg.JPG manage 121.7 K 06 Jun 2005 - 05:36 Main.guest  

RagDolls   Edit | Attach | Ref-By | Printable | Diffs | r1.6 | > | r1.5 | > | r1.4 | More