Skip to main content

Hair Physic Bones Breaking when Disabled

Key Problem

UploadWhen Inusing ProgressHair/Clothing physics as mentioned in this [article](Hair And Clothing Physics 0bf83805238d40ca9429d23f7121d843.md), the hair/clothing physics bones and joints are breaking apart when the gameObject is inactive then reactivated.

Expected Behavior

Hair/Clothing physics bones and joints keep their connection to the main gameobject even after deactivated and reactivated.

Key Solution

The cause of the problem is that to make the physics works, the physics bones/joints need to be unparented from their main gameObject, but when the main gameObject is deactivated, the joint will lost their connected rigibody.

The solution is to add a script that track all the MoveForce script (which is responsible in unparenting the physics bones) in the parent’s children, as well as their initial position relative to their main gameObject.

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

namespace CharacterCreation
{
    public class JointContainer : MonoBehaviour
    {
        MoveForce[] moveForces;
        List<Vector3> initialPos;
        List<Vector3> initialAngle;
        // Start is called before the first frame update
        void Start()
        {
            initialPos      = new List<Vector3>();
            initialAngle    = new List<Vector3>();
            moveForces = GetComponentsInChildren<MoveForce>(true);
            for(int i = 0; i < moveForces.Length; i++)
            {
                //Keep children initial position;
                initialPos.Add(transform.InverseTransformPoint(moveForces[i].transform.position));
                initialAngle.Add(moveForces[i].transform.eulerAngles - transform.eulerAngles);
            }
        }

        void OnDisable()
        {
            for(int i = 0; i < moveForces.Length; i++)
                if(moveForces[i])
                    moveForces[i].gameObject.SetActive(false);
        }

        void OnEnable()
        {
            if(moveForces == null)
                return;
            for(int i = 0; i < moveForces.Length; i++)
            {
                //Reposition the children's position relative to this transform;
                moveForces[i].transform.position      = transform.TransformPoint(initialPos[i]);
                moveForces[i].transform.eulerAngles   = transform.eulerAngles + initialAngle[i];
                moveForces[i].gameObject.SetActive(true);
            }
        }
    }
}

Note:

Seems that transform.TransformDirection doesn’t preserve up direction, that’s why we manually compute the eulerAngles instead.