using UnityEngine; using System.Collections; namespace RootMotion.Dynamics { public static class PuppetMasterTools { public static void PositionRagdoll(PuppetMaster puppetMaster) { Rigidbody[] rigidbodies = puppetMaster.transform.GetComponentsInChildren(); if (rigidbodies.Length == 0) return; foreach (Muscle m in puppetMaster.muscles) if (m.joint == null || m.target == null) return; Vector3[] swingAxes = new Vector3[rigidbodies.Length]; for (int i = 0; i < rigidbodies.Length; i++) { if (rigidbodies[i].transform.childCount == 1) { swingAxes[i] = rigidbodies[i].transform.InverseTransformDirection(rigidbodies[i].transform.GetChild(0).position - rigidbodies[i].transform.position); } } foreach (Rigidbody r in rigidbodies) { foreach (Muscle m in puppetMaster.muscles) { if (m.joint.GetComponent() == r) { r.transform.position = m.target.position; } } } for (int i = 0; i < rigidbodies.Length; i++) { if (rigidbodies[i].transform.childCount == 1) { Vector3 childPosition = rigidbodies[i].transform.GetChild(0).position; rigidbodies[i].transform.rotation = Quaternion.FromToRotation(rigidbodies[i].transform.rotation * swingAxes[i], childPosition - rigidbodies[i].transform.position) * rigidbodies[i].transform.rotation; rigidbodies[i].transform.GetChild(0).position = childPosition; } } } public static void RealignRagdoll(PuppetMaster puppetMaster) { foreach (Muscle m in puppetMaster.muscles) { if (m.joint == null || m.joint.transform == null || m.target == null) { Debug.LogWarning("Muscles incomplete, can not realign ragdoll."); return; } } foreach (Muscle m in puppetMaster.muscles) { if (m.target != null) { Transform[] children = new Transform[m.joint.transform.childCount]; for (int c = 0 ; c < children.Length; c++) { children[c] = m.joint.transform.GetChild(c); } foreach (Transform c in children) c.parent = null; BoxCollider box = m.joint.GetComponent(); Vector3 boxSizeWorldSpace = Vector3.zero; Vector3 boxCenterWorldSpace = Vector3.zero; if (box != null) { boxSizeWorldSpace = box.transform.TransformVector(box.size); boxCenterWorldSpace = box.transform.TransformVector(box.center); } CapsuleCollider capsule = m.joint.GetComponent(); Vector3 capsuleCenterWorldSpace = Vector3.zero; Vector3 capsuleDirectionWorldSpace = Vector3.zero; if (capsule != null) { capsuleCenterWorldSpace = capsule.transform.TransformVector(capsule.center); capsuleDirectionWorldSpace = capsule.transform.TransformVector(DirectionIntToVector3(capsule.direction)); } SphereCollider sphere = m.joint.GetComponent(); Vector3 sphereCenterWorldSpace = Vector3.zero; if (sphere != null) { sphereCenterWorldSpace = sphere.transform.TransformVector(sphere.center); } Vector3 jointAxisWorldSpace = m.joint.transform.TransformVector(m.joint.axis); Vector3 jointSecondaryAxisWorldSpace = m.joint.transform.TransformVector(m.joint.secondaryAxis); // Rotate the bone m.joint.transform.rotation = m.target.rotation; if (box != null) { box.size = box.transform.InverseTransformVector(boxSizeWorldSpace); box.center = box.transform.InverseTransformVector(boxCenterWorldSpace); } if (capsule != null) { capsule.center = capsule.transform.InverseTransformVector(capsuleCenterWorldSpace); Vector3 directionLocalSpace = capsule.transform.InverseTransformDirection(capsuleDirectionWorldSpace); capsule.direction = DirectionVector3ToInt(directionLocalSpace); } if (sphere != null) { sphere.center = sphere.transform.InverseTransformVector(sphereCenterWorldSpace); } m.joint.axis = m.joint.transform.InverseTransformVector(jointAxisWorldSpace); m.joint.secondaryAxis = m.joint.transform.InverseTransformVector(jointSecondaryAxisWorldSpace); foreach (Transform c in children) c.parent = m.joint.transform; } } } private static Vector3 DirectionIntToVector3(int dir) { if (dir == 0) return Vector3.right; if (dir == 1) return Vector3.up; return Vector3.forward; } private static int DirectionVector3ToInt(Vector3 dir) { float dotX = Vector3.Dot(dir, Vector3.right); float dotY = Vector3.Dot(dir, Vector3.up); float dotZ = Vector3.Dot(dir, Vector3.forward); float absDotX = Mathf.Abs(dotX); float absDotY = Mathf.Abs(dotY); float absDotZ = Mathf.Abs(dotZ); int rotatedDirection = 0; if (absDotY > absDotX && absDotY > absDotZ) rotatedDirection = 1; if (absDotZ > absDotX && absDotZ > absDotY) rotatedDirection = 2; return rotatedDirection; } } }