Merging SkinnedMesh into another and use existing bones

Hey guys, this has been a weeklong issue that is driving me up a wall.

Let me explain my situation. I have a “body” that I want to swap out among a series of different bodys. These bodies are submeshes of one big .fbx. However, I load them manually as a Mesh reference from the inspector. The boneweights are configured for the “main” mesh. What I’m trying to do is merge the body SkinnedMesh together with the main SkinnedMesh and use that one bone structure(both grab references to the main mesh’s bones). The bones are in exact order, the boneweights correctly reference their desired bone, and everything else looks all good - however, I’m suffering from kraken animation. The animation is not playing correctly and the body only is deforming incorrectly. Here is the script, unfortunately I can’t provide screenshots nor videos of the issue.

Any help is greatly appreciated. <3

public class SkinnedMeshCombiner : MonoBehaviour
    {
        private List<GameObject> disabledObjects = new List<GameObject>();

        private SkinnedMeshRenderer skinnedMeshRenderer;

        private Dictionary<Transform, Vector3> initialBonePositions = new Dictionary<Transform, Vector3> ();
        private Dictionary<Transform, Quaternion> initialBoneRotations = new Dictionary<Transform, Quaternion> ();

        public void Combine ()
        {
            SkinnedMeshRenderer[] smRenderers = GetComponentsInChildren<SkinnedMeshRenderer> ();

            for (int index = 0; index < smRenderers[0].bones.Length; index++)
            {
                Transform bone = smRenderers[0].bones[index];
                Vector3 dummy;
                if (!initialBonePositions.TryGetValue (bone, out dummy))
                {
                    initialBonePositions.Add (bone, bone.localPosition);
                    initialBoneRotations.Add (bone, bone.localRotation);
                }
            }


            List<Transform> bones = new List<Transform> ();
            List<BoneWeight> boneWeights = new List<BoneWeight> ();
            List<CombineInstance> combineInstances = new List<CombineInstance> ();

            //store then zero out the position, rotation, and scales, as the mesh combiner needs the worker to be at the origin
            Vector3 startingLocalScale = transform.localScale;
            Vector3 startingRootScale = transform.parent.localScale;

            transform.localScale = Vector3.one;
            transform.parent.localScale = Vector3.one;

            Vector3 startingPosition = transform.position;
            Quaternion startingRotation = transform.rotation;

            transform.position = Vector3.zero;
            transform.rotation = Quaternion.Euler (Vector3.zero);

            foreach (Transform bone in smRenderers[0].bones)
            {
                //Necessary to correct the offset of the hand-held tools
                Vector3 storedLocalPosition;
                if (initialBonePositions.TryGetValue(bone, out storedLocalPosition))
                {
                    bone.localPosition = storedLocalPosition;
                    bone.localRotation = initialBoneRotations[bone];
                }

                bones.Add(bone);
            }

            for (int s = 0; s < smRenderers.Length; s++)
            {
                if (smRenderers[s].gameObject.activeSelf && smRenderers[s] != skinnedMeshRenderer)
                {
                    for (int i = 0; i < smRenderers[s].sharedMesh.boneWeights.Length; i++)
                    {
                        BoneWeight bw = smRenderers[s].sharedMesh.boneWeights[i];
                        boneWeights.Add (bw);
                    }

                    CombineInstance ci = new CombineInstance ();
                    ci.mesh = smRenderers[s].sharedMesh;
                    ci.transform = smRenderers[s].transform.localToWorldMatrix;
                    //ci.transform = Matrix4x4.TRS (smRenderers[s].transform.position, smRenderers[s].transform.rotation, smRenderers[s].transform.localScale);
                    combineInstances.Add (ci);

                    smRenderers[s].gameObject.SetActive (false);
                    disabledObjects.Add (smRenderers[s].gameObject);
                }
            }

            List<Matrix4x4> bindposes = new List<Matrix4x4> ();

            for (int b = 0; b < bones.Count; b++)
            {
                bindposes.Add (bones[b].worldToLocalMatrix);
            }

            if (skinnedMeshRenderer == null) skinnedMeshRenderer = gameObject.AddComponent<SkinnedMeshRenderer> ();
            skinnedMeshRenderer.sharedMesh = new Mesh ();
            skinnedMeshRenderer.sharedMesh.CombineMeshes (combineInstances.ToArray (), true, true);

            skinnedMeshRenderer.sharedMaterial = smRenderers [0].sharedMaterial;

            skinnedMeshRenderer.bones = bones.ToArray ();
            skinnedMeshRenderer.rootBone = transform.FindChild("Base HumanPelvis");
            skinnedMeshRenderer.sharedMesh.boneWeights = boneWeights.ToArray();
            skinnedMeshRenderer.sharedMesh.bindposes = bindposes.ToArray();
            skinnedMeshRenderer.sharedMesh.RecalculateBounds ();

            //reset the position, rotation, and scales
            transform.localScale = startingLocalScale;
            transform.parent.localScale = startingRootScale;

            transform.position = startingPosition;
            transform.rotation = startingRotation;
        }

        public void Uncombine ()
        {
            for (int i = 0; i < disabledObjects.Count; i++)
            {
                GameObject go = disabledObjects[i];
                if (go != null)
                {
                    // Can be null if modified externally, e.g., when initial leaf clothes are destroyed
                    go.SetActive (true);
                }
            }
            disabledObjects.Clear ();

            if (skinnedMeshRenderer != null)
            {
                Destroy (skinnedMeshRenderer.sharedMesh);
            }
        }
    }

does this thread help?

any one found easy solution please

Maybe this character merge asset can help you.

It works with skinned meshes and supports any effects like normal maps and etc. Animations are not broken after merging and work perfectly with any 3D character customization system.

thank’s i will try

1 Like