Non humanoid ragdoll

How to add a ragdoll for a quadruped animal like a dog or, in my case, a leopard? I tried with the ragdoll wizard
even if it’s used humanoid ragdolls, but I considered the front legs the arms and the back legs the legs, but the result isn’t very realistic:
bafs8r

And the tail is floating and glitching trough ground because I can’t add a rigidbody because none of the primitive colliders is aligned with the tail, the collider is perpendicular on the tail. Plus, If I want extra realistic-ness the tail should bend

I have this cool death animation that model’s author provided:
ynip16

But It clips trough terrain when it isn’t flat, plus I don’t like the fact that animals die in the same way…

You could use that animation if you added some kind of IK system. I am willing to bet you have it on a generic rig, instead of humanoid right now. If that is the case then you yourself need to set up the physics/behavior of the IK using script.

I am a bit of a noob, but am doing something similar atm by setting up a humanoid rig with allot of extra bones (I am extending the IK to the extra bones while letting unity do the heavy lifting.)

Now that won’t work for you. Unity’s humanoid IK system is terrible for quadrupeds. As you seem to have discovered. Good news is though. I have discovered a bunch about directly manipulating bones through script and am willing to help you set up a “VERY” basic IK for that 1 specific death animation if you are interested. (Essentially just getting the body to match the ground, prolly use a few different rays and position/rotate the bones accordingly to match the .Normal of the surfaces under the different sections of your model (Front, mid, and back)).

(I would offer to assist in setting up an actual “Generic” ragdoll… But good lord is that an entirely different beast to tackle. It is doable. I could try to help. But as far as a full ragdoll, I can make no promises.)

Would be great some help, but the model that I have I bought from unity asset store and I think it is illegal to share paid models online, but maybe you can assist me with the creation of the generic ik

Oh no, I am not gonna do the work for you. Lol. No need to share anything. (I make all my own models anyway.)
Just describe what you are dealing with.

First things first, You need to identify the bones in your model. Their is a couple different ways to do this but the easiest is probably just opening it up in unity, dropping the model into a scene and expanding it in the inspector. Should get something like this.

Since you didn’t make the model that list will be of great help when it comes to referencing bones in your script.

How much experience do you have when it comes to working with models? Do you understand the parenting system, where as each bone should be essentially a child or grandchild of a single root bone?

I animated rigged characters and I rigged some humanoid arms in blender so I guess I can deal with the skeleton hierarchy. I think I understand the parenting system. I don’t make my own models because I can’t make hyper-realistic high-poly models, just simple models with few polygons. And my game aims to have realistic aesthetics:

1 Like

That should be plenty of experience. I don’t think this will be too hard for you in this case.

At the moment I am setting up a sterile scene with an unfinished big cat model I happened to have laying around. I also mocked up a very simple “Fall over and die” animation for it. That way we are both on the same page.
Once I figure out the best way to reference all the bones at once in a single script I will get back to you.

6635125--756808--MowCatDies.gif

Wait, are these IK? Because the death animation I have already

Nope, What we are gonna do is figure out how to call up a bone in a script and then change the rotation of that bone in relation to the ground and other bones.
Like I said before, What I am working on is not exactly like yours. So I made a simple test scene that is allot closer to what you have.
That way, anything I do on my end, you should be able to recreate on your end. The names of the bones and stuff will be different, BUT the technique will be the same.
Sorry if I am not explaining well. I am a bit of a noob when it comes to unity specifically, so I am still learning these systems myself. If you have any ideas or input on anything feel free to speak up.

I’m using terrains in my actual project so the y of each part is the Terrain.sampleheight of x and z of the part

Here is what I got together so far.

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class Controler : MonoBehaviour
{
    public GameObject RootBone;

    public Transform[] Bones;

    private Animator Anim;

    public Vector3 RotationByHand;



    private void Awake()
    {
        Anim = GetComponent<Animator>();
        List<Transform> childs = new List<Transform>();

        Utilities.GetAllChildren(RootBone.transform, ref childs);

        foreach (Transform t in childs)
        {

            Debug.Log(t.transform);
            Debug.Log(t.transform.childCount + "Children");



        }


        Bones = childs.ToArray();

    }


    void Start()
    {

      

    }

    private void Update()
    {



        if (Input.GetKeyDown(KeyCode.Space))
        {
            Debug.Log("MySawmp");
            Anim.SetInteger("Button", 1);
        }
      

        if (Input.GetKeyUp(KeyCode.Space))
        {
            Anim.SetInteger("Button", 0);
        }
    }

    private void LateUpdate()
    {
        Bones[0].rotation = Quaternion.Euler(RotationByHand);
    }

}



static class Utilities
{

    public static void GetAllChildren(Transform parent, ref List<Transform> transforms)
    {

        foreach (Transform t in parent)
        {

            transforms.Add(t);
            GetAllChildren(t, ref transforms);

        }
    }
}

So what you need to do is drag your ROOT bone into the inspector box labled “RootBone”
Once you do that and fire up the sim this script will grab all of the children of that root bone (AKA your armature) and put them into a list, THEN it takes that list and turns it into an array (I hear arrays are allot better on performance.)

Once you have all the bones referenced in the array, you can select the different elements of the array and manually control each bone from the script. There is a basic example at the bottom under LateUpdate. If you manipulate the HandRotation value in the inspector it should rotate the root bone of your model.

Still have allot to do, but this should be a good foundation to build off of.

(PS: I forgot to ask, how much experience do you have with script? And if you have any questions I am happy to explain what does what.
Ultimately, this is helping me learn new stuff, and I would like for you to learn as well.)

If you are confused as to the point of all those shenanigans, change the late update to:

    private void LateUpdate()
    {
        Bones[18].rotation = Quaternion.Euler(RotationByHand);

        // Front Right Paw
        Debug.DrawRay(Bones[43].position + Vector3.up, Vector3.down * 2f, Color.red);
        // Front Left Paw
        Debug.DrawRay(Bones[36].position + Vector3.up, Vector3.down * 2f, Color.red);
        // Back Right Paw
        Debug.DrawRay(Bones[64].position + Vector3.up, Vector3.down * 2f, Color.red);
        // Back Left Paw
        Debug.DrawRay(Bones[59].position + Vector3.up, Vector3.down * 2f, Color.red);
    }

Look at your array in the inspector (While the game/sim is running), find which number corresponds to the stuff I listed above, then plug em in. Boom you know where each of your cats paws are and what directions to send you actual rays for the data.

Now I have not been using terrain in my project because it isn’t as open as yours looks to be. (I’m doing caves and corridors instead, is easier to just build em with colliders.)
I did toss a terrain into my test scene though and am working on a formula to get the angle of it from any specific point. I am pretty sure the key command here is gonna be TerrainData.GetSteepness unless you have already tried that.
Position is easy, just wherever your ray hits, and we don’t need to worry about changing Vector3.Up unless you intend to muck about with gravity.

Thanks I’ll try

I’ve got foot rotation worked out partially. I am still tying to figure out how to keep the foot pointed forwards when you rotated the char. But I do have enough that the cats feet match the slope of the terrain they are on/near.
Or any bone for that matter It is a totally modular script if you are following along… Should work on any generic rig to so long as you swap in the right array numbers.
I am thinking maybe using that ground rotation on the hips and chest with a bit of offset for that death animation you have.
Still need to work out the forward direction for the feet though. Ill get back to you if I make any headway.

Allrighty I think I got foot rotation based on ground worked out. It is not perfect, but should do the job. Works on both objects AND planes so long as they are tagged ground. Should be easy to swap to another identifying method other than tags though.

The planes have a bit of an odd deal with how they handle themselves so the rotation on them is really jerky atm. Can be fixed with some slerping, Also you might need to tweak some variables in the foot roll assistants to get it just right.
Replace the x,y,z of the * Quaternion.Euler at the bottom of each FootRollAsistant with the wonderful floats provided call magic1,2, and 3 for easy tweaking from the inspector. I call em magic because you really never know what is gonna happen with em, tho generally two of em mess with the roll and one changes the yaw, you shouldn’t need to worry about yaw though. That should set itself correctly automatically (if you are using this part of the code on feet).

Depending on how the bones are oriented in your model you might have to swap a right with a forward or something similar. (My cats wrist bones right is oriented to the actual right of his wrist while he is standing. Depending on bone roll, yours might be different.)
I have not tried it yet but should also be able to apply this to any other bone in your chars body (Hint hint).

Anyway here it is so far. (we still got a long way to go, but tis the reality of making a custom rig IK system.)

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class Controler : MonoBehaviour
{
    public GameObject RootBone;

    public Transform[] Bones;

    private Animator Anim;

    public float Magic3;
    public float Magic2;
    public float Magic1;


    private Quaternion FootIkProductFL;
    public Vector3 FootRollAsistantFL;
    private Quaternion FootIkProductFR;
    public Vector3 FootRollAsistantFR;
    private Quaternion FootIkProductBL;
    public Vector3 FootRollAsistantBL;
    private Quaternion FootIkProductBR;
    public Vector3 FootRollAsistantBR;


    private void Awake()
    {
        Anim = GetComponent<Animator>();
        List<Transform> childs = new List<Transform>();

        Utilities.GetAllChildren(RootBone.transform, ref childs);

        foreach (Transform t in childs)
        {

            Debug.Log(t.transform);
            Debug.Log(t.transform.childCount + "Children");



        }


        Bones = childs.ToArray();

    }


    void Start()
    {



    }

    private void Update()
    {

        if (Input.GetKeyDown(KeyCode.Space))
        {
            Debug.Log("MySawmp");
            Anim.SetInteger("Button", 1);
        }


        if (Input.GetKeyUp(KeyCode.Space))
        {
            Anim.SetInteger("Button", 0);
        }
    }

    private void LateUpdate()
    {


        RaycastHit hit;
        Ray IkRayFL = new Ray(Bones[36].position + Vector3.up, Vector3.down * 1);

        Ray IkRayFR = new Ray(Bones[44].position + Vector3.up, Vector3.down * 1);

        Ray IkRayBL = new Ray(Bones[61].position + Vector3.up, Vector3.down * 1);

        Ray IkRayBR = new Ray(Bones[66].position + Vector3.up, Vector3.down * 1);


        // Front Left Paw
        if (Physics.Raycast(IkRayFL, out hit, 10f))
        {
            if (hit.transform.tag == "Ground")
            {

                Debug.DrawLine(hit.point, hit.point + hit.normal, Color.green);
                FootIkProductFL = Quaternion.LookRotation(new Vector3(Bones[36].forward.x, Bones[36].forward.y + FootRollAsistantFL.y, Bones[36].forward.z), Vector3.Cross(Bones[36].forward, -hit.normal));
                FootRollAsistantFL = Quaternion.LookRotation(Bones[36].right, Vector3.Cross(Bones[36].right, -hit.normal)) * Quaternion.Euler(new Vector3(-90, 0, 0)) * new Vector3(1, 1, 1);

                Bones[36].rotation = FootIkProductFL;


            }
        }
        //Front Right Paw
        if (Physics.Raycast(IkRayFR, out hit, 10f))
        {
            if (hit.transform.tag == "Ground")
            {
                //   Debug.Log(hit.point);
                //   Debug.Log(hit.normal);
                Debug.DrawLine(hit.point, hit.point + hit.normal, Color.green);
                FootIkProductFR = Quaternion.LookRotation(new Vector3(Bones[44].forward.x, Bones[44].forward.y + FootRollAsistantFR.y, Bones[44].forward.z), Vector3.Cross(Bones[44].forward, hit.normal));
                FootRollAsistantFR = Quaternion.LookRotation(Bones[44].right, Vector3.Cross(Bones[44].right, -hit.normal)) * Quaternion.Euler(new Vector3(0, 0, 0)) * new Vector3(1, 1, 1);

                Bones[44].rotation = FootIkProductFR;
            }
        }

        //Back Left Paw
        if (Physics.Raycast(IkRayBL, out hit, 10f))
        {
            if (hit.transform.tag == "Ground")
            {
                //   Debug.Log(hit.point);
                //   Debug.Log(hit.normal);
                Debug.DrawLine(hit.point, hit.point + hit.normal, Color.green);
                FootIkProductBL = Quaternion.LookRotation(new Vector3(Bones[61].forward.x, Bones[61].forward.y + FootRollAsistantBL.y, Bones[61].forward.z), Vector3.Cross(Bones[61].forward, -hit.normal));
                FootRollAsistantBL = Quaternion.LookRotation(Bones[61].right, Vector3.Cross(Bones[61].right, -hit.normal)) * Quaternion.Euler(new Vector3(0 , -70 , 0)) * new Vector3(1, 1, 1);

                Bones[61].rotation = FootIkProductBL;
            }

            //Back Right Paw
            if (Physics.Raycast(IkRayBR, out hit, 10f))
            {
                if (hit.transform.tag == "Ground")
                {
                    //   Debug.Log(hit.point);
                    //   Debug.Log(hit.normal);
                    Debug.DrawLine(hit.point, hit.point + hit.normal, Color.green);
                    FootIkProductBR = Quaternion.LookRotation(new Vector3(Bones[66].forward.x, Bones[66].forward.y + FootRollAsistantBR.y, Bones[66].forward.z), Vector3.Cross(Bones[66].forward, hit.normal));
                    FootRollAsistantBR = Quaternion.LookRotation(-Bones[66].right, Vector3.Cross(-Bones[66].right, hit.normal)) * Quaternion.Euler(new Vector3(0 , -30, 0)) * new Vector3(1, 1, 1);

                    Bones[66].rotation = FootIkProductBR;
                }
            }


        }

    }



    static class Utilities
    {

        public static void GetAllChildren(Transform parent, ref List<Transform> transforms)
        {

            foreach (Transform t in parent)
            {

                transforms.Add(t);
                GetAllChildren(t, ref transforms);

            }
        }
    }
}

I hope you can make use of some of this. Ima start messing with making the rest of the legs react to ground position. (Is gonna be tricky, but since the feet stay lvl no matter where the rest of the body goes I think I can work it out with some clamped rotation and a bit trial and error.)

EDIT: No wait, I think I missed something. The foot roll is not being effected by body roll… Darn I thought I had it there. Well, I am not messing with it more tonight. But if you have any ideas feel free to toss em out there.
No such thing as a bad idea, you would not imagine how many versions of this I went through to get here, lol.