void RepairBone(RagdollTransform bone) { if (bone == null) { return; } bool isFollow = bone.joint == null; // if (!isFollow) { // bone.transform.localRotation = bone.originalRotation; // bone.transform.localPosition = bone.originalPosition; // bone.SetKinematic(false); // } bone.transform.localScale = Vector3.one; if (!isFollow) { // bone.joint.connectedBody = bone.connectedBody; // bone.collider.isTrigger = false; bone.collider.gameObject.layer = Ragdoll.layer; if (bone.followTarget != null) { RepairBone(bone.followTarget); } } }
/* * ignore collisions with other physics bones on the same ragdoll */ public void IgnoreSelfCollisions(bool ignore) { if (CheckForErroredRagdoll("IgnoreSelfCollisions")) { return; } for (int i = 0; i < bonesCount; i++) { RagdollTransform boneA = allElements[i]; for (int x = i + 1; x < bonesCount; x++) { RagdollTransform boneB = allElements[x]; // dont handle connected joints, joint component already does if (boneB.joint && boneB.joint.connectedBody == boneA.rigidbody) { continue; } if (boneA.joint && boneA.joint.connectedBody == boneB.rigidbody) { continue; } Physics.IgnoreCollision(boneA.collider, boneB.collider, ignore); } } }
static Bounds GetBoxBounds(RagdollTransform bone, RagdollTransform topCutoff, RagdollTransform[] encapsulate, bool adjustMin) { Bounds bounds = new Bounds(); //encapsulate upper arms and upper legs positions for (int i = 0; i < 4; i++) { bounds.Encapsulate(bone.transform.InverseTransformPoint(encapsulate[i].transform.position)); } if (adjustMin) { Vector3 min = bounds.min; min.y = 0; bounds.min = min; } //adjust max bounds based on next bone Vector3 max = bounds.max; max.y = bone.transform.InverseTransformPoint(topCutoff.transform.position).y; bounds.max = max; return(bounds); }
/* * Set the bone's configurable joint target to the master local rotation */ void HandleJointFollow(RagdollTransform bone, float torque, int boneIndex) { if (!bone.joint) { return; } if (bone.joint.angularXMotion == ConfigurableJointMotion.Locked) { return; } //setting joint torque every frame was slow, so check here if its changed if (torque != lastTorques[boneIndex]) { lastTorques[boneIndex] = torque; jointDrive.positionSpring = torque; bone.joint.slerpDrive = jointDrive; } //set joints target rotation if (torque != 0) { Quaternion targetLocalRotation = bone.followTarget.transform.localRotation; bone.joint.targetRotation = localToJointSpaces[boneIndex] * Quaternion.Inverse(targetLocalRotation) * startLocalRotations[boneIndex]; } }
/* * delay the dismemberment for a few frames in order for physics exerted on the bone * to play out before we disable it */ IEnumerator DismemberBoneDelayed(Ragdoll ragdoll, RagdollTransform bone) { for (int i = 0; i < ragdoll.ragdollProfile.dismemberBoneFrameDelay; i++) { yield return(new WaitForFixedUpdate()); } DismemberBone(ragdoll, bone, false); }
/* * delay the dismemberment for a few frames in order for physics exerted on the bone * to play out before we disable it */ IEnumerator DismemberBoneDelayed(Ragdoll ragdoll, RagdollTransform bone, int delay) { for (int i = 0; i < delay; i++) { yield return(new WaitForFixedUpdate()); } DismemberBone(ragdoll, bone, 0, false); }
static Collider AddBoxCollider(RagdollTransform bone, Bounds bounds) { BoxCollider box = bone.AddComponent <BoxCollider>(); box.center = bounds.center; box.size = bounds.size; return(box); }
public void LoadSnapshot(float snapshotBlend, bool useFollowTarget) { RagdollTransform element = useFollowTarget && followTarget != null ? followTarget : this; TeleportTo( Vector3.Lerp(element.transform.position, snapshotPosition, snapshotBlend), Quaternion.Slerp(element.GetRotation(), snapshotRotation, snapshotBlend) ); }
public void DismemberBone(Ragdoll ragdoll, RagdollTransform bone, bool isFollowBone) { if (!isFollowBone) { bone.collider.gameObject.layer = LayerMask.NameToLayer(ignorePhysicsLayer); // bone.joint.connectedBody = null; // bone.collider.isTrigger = true; // bone.SetKinematic(true); } bone.transform.localScale = Vector3.one * dismemberScale; }
static void AddBreastColliders(Dictionary <HumanBodyBones, RagdollTransform> bones) { RagdollTransform[] encapsulate = new RagdollTransform[] { bones[HumanBodyBones.LeftUpperArm], bones[HumanBodyBones.RightUpperArm], bones[HumanBodyBones.LeftUpperLeg], bones[HumanBodyBones.RightUpperLeg], }; RagdollTransform hips = bones[HumanBodyBones.Hips]; RagdollTransform chest = bones[HumanBodyBones.Chest]; RagdollTransform head = bones[HumanBodyBones.Head]; hips.collider = AddBoxCollider(hips, GetBoxBounds(hips, chest, encapsulate, false)); chest.collider = AddBoxCollider(chest, GetBoxBounds(chest, head, encapsulate, true)); }
void InitializeVelocitySetValues() { animationVelocityTrackers = new VelocityTracker[Ragdoll.bonesCount]; for (int i = 0; i < Ragdoll.bonesCount; i++) { RagdollTransform bone = ragdoll.GetBone(Ragdoll.humanBones[i]); //track position (offset by ragdoll bone's rigidbody centor of mass) of the follow target Vector3 massCenterOffset = bone.transform.InverseTransformPoint(bone.rigidbody.worldCenterOfMass); animationVelocityTrackers[i] = new VelocityTracker(bone.followTarget.transform, massCenterOffset); } }
public void DismemberBone(Ragdoll ragdoll, RagdollTransform bone, int delay, bool isFollowBone = false) { InitializeDismemberedBones(); if (!isFollowBone) { if (!dismemberableBones.Contains(bone.bone.bone)) { return; } if (delay > 0) { ragdoll.StartCoroutine(DismemberBoneDelayed(ragdoll, bone, delay)); return; } dismemberedBones[bone.bone.bone] = bone; bone.collider.gameObject.layer = LayerMask.NameToLayer(ignorePhysicsLayer); // bone.joint.connectedBody = null; // bone.collider.isTrigger = true; // bone.SetKinematic(true); // dismember the follow target, so it reflects our dismemberment // (dismembers the animated model...) if (bone.followTarget != null) { DismemberBone(ragdoll, bone.followTarget, 0, true); } // dismember and disable any child bones (helps physics from getting all jittery) HumanBodyBones childBone = Ragdoll.GetChildBone(bone.bone.bone); if (childBone != HumanBodyBones.Hips) { RagdollTransform childBoneTransform = ragdoll.GetBone(childBone); if (!BoneDismembered(childBoneTransform)) { DismemberBone(ragdoll, childBoneTransform, 0, false); } } } bone.transform.localScale = Vector3.one * dismemberScale; }
static void BuildCapsules(Dictionary <HumanBodyBones, RagdollTransform> bones) { foreach (var k in capsuleBones) { RagdollTransform bone = bones[k]; int direction = k.ToString().Contains("Arm") ? 0 : 1; float distance; if (upperCapsuleBones.Contains(k)) { distance = bone.transform.InverseTransformPoint(bones[Ragdoll.GetChildBone(k)].transform.position)[direction]; } else { Vector3 endPoint = (bone.transform.position - bones[Ragdoll.GetParentBone(k)].transform.position) + bone.transform.position; distance = bone.transform.InverseTransformPoint(endPoint)[direction]; if (bone.transform.GetComponentsInChildren(typeof(Transform)).Length > 1) { Bounds bounds = new Bounds(); foreach (Transform child in bone.transform.GetComponentsInChildren(typeof(Transform))) { bounds.Encapsulate(bone.transform.InverseTransformPoint(child.position)); } if (distance > 0) { distance = bounds.max[direction]; } else { distance = bounds.min[direction]; } } } CapsuleCollider collider = bone.AddComponent <CapsuleCollider>(); collider.direction = direction; Vector3 center = Vector3.zero; center[direction] = distance * 0.5F; collider.center = center; collider.height = Mathf.Abs(distance); bone.collider = collider; } }
public bool Transform2HumanBone(Transform transform, out RagdollTransform bone) { bone = null; if (CheckForErroredRagdoll("Transform2HumanBone")) { return(false); } for (int i = 0; i < bonesCount; i++) { if (allElements[i].transform == transform) { bone = allElements[i]; return(true); } } return(false); }
/* * Adjust Ragdoll component values per bone to reflect the supplied * Ragdoll profile (default profile if none is supplied) */ public static void UpdateBonesToProfileValues(Dictionary <HumanBodyBones, RagdollTransform> bones, RagdollProfile profile, float initialHeadOffsetFromChest) { if (bones == null) { return; } if (profile == null) { return; } // if (profile == null) // profile = RagdollProfile.defaultProfile; Vector3 headOffset = profile.headOffset; //clamp head offset (values too high or too low become unstable for some reason) headOffset.y = Mathf.Clamp(headOffset.y, -initialHeadOffsetFromChest + .1f, 2); for (int i = 0; i < bonesCount; i++) { RagdollProfile.BoneProfile boneProfile = profile.boneData[humanBones[i]]; HumanBodyBones hBodyBone = humanBones[i]; RagdollTransform bone = bones[hBodyBone]; //set rigidbody values for bone UpdateRigidbodyToProfile(bone.rigidbody, boneProfile); //adjust collider values for bone UpdateColliderToProfile(hBodyBone, bone.collider, boneProfile, headOffset, initialHeadOffsetFromChest); //set joint values if (bone.joint) { UpdateJointToProfile(hBodyBone, bone.joint, boneProfile, headOffset); } } }
public void DismemberBone(string reason, Ragdoll ragdoll, RagdollTransform bone) { InitializeDismemberedBones(); if (!dismembermentAvailable) { return; } if (!BoneDismemberable(bone.bone.bone)) { return; } if (RagdollPhysics.RigidbodyGrabbed(bone.rigidbody)) { return; } // Debug.LogError("Dismembered " + reason); dismemberedBones[bone.bone.bone] = bone; // dismember the follow target, so it reflects our dismemberment // (dismembers the animated model...) if (bone.followTarget != null) { DismemberBone(ragdoll, bone.followTarget, true); } // dismember and disable any child bones (helps physics from getting all jittery) HumanBodyBones childBone = Ragdoll.GetChildBone(bone.bone.bone); RagdollTransform childBoneTransform = ragdoll.GetBone(childBone); if (!BoneDismembered(childBoneTransform)) { DismemberBone(reason, ragdoll, childBoneTransform); } ragdoll.StartCoroutine(DismemberBoneDelayed(ragdoll, bone)); }
static void BuildJoints(Dictionary <HumanBodyBones, RagdollTransform> bones) { foreach (var k in bones.Keys) { if (k == HumanBodyBones.Hips) { continue; } RagdollTransform bone = bones[k]; bone.joint = bone.AddComponent <ConfigurableJoint>(); // Setup connection and axis //bone.joint.autoConfigureConnectedAnchor = false; // turn off to handle degenerated scenarios, like spawning inside geometry. bone.joint.enablePreprocessing = false; bone.joint.anchor = Vector3.zero; bone.joint.connectedBody = bones[Ragdoll.GetParentBone(k)].rigidbody; // Setup limits SoftJointLimit limit = new SoftJointLimit(); limit.contactDistance = 0; // default to zero, which automatically sets contact distance. limit.limit = 0; bone.joint.lowAngularXLimit = bone.joint.highAngularXLimit = bone.joint.angularYLimit = bone.joint.angularZLimit = limit; bone.joint.xMotion = bone.joint.yMotion = bone.joint.zMotion = ConfigurableJointMotion.Locked; bone.joint.angularXMotion = bone.joint.angularYMotion = bone.joint.angularZMotion = ConfigurableJointMotion.Limited; bone.joint.rotationDriveMode = RotationDriveMode.Slerp; bone.joint.projectionMode = JointProjectionMode.PositionAndRotation; } }
public bool BoneDismembered(RagdollTransform bone) { return(BoneDismembered(bone.bone.bone)); }
/* * set the velocities we calculated in late update for each animated bone * on the actual ragdoll */ void SetPhysicsVelocities(float deltaTime) { float dot = Vector3.Dot(ragdoll.RootBone().transform.up, Vector3.up); float maxVelocityForGravityAdd2 = profile.maxGravityAddVelocity * profile.maxGravityAddVelocity; float fallDecayCurveSample = 1f - fallDecay; //set up curves backwards... whoops // for each physics bone... for (int i = 0; i < Ragdoll.bonesCount; i++) { HumanBodyBones unityBone = Ragdoll.humanBones[i]; RagdollTransform bone = ragdoll.GetBone(unityBone); if (ragdoll.BoneDismembered(bone)) { continue; } if (bone.rigidbody.isKinematic) { continue; } Vector3 ragdollBoneVelocty = bone.rigidbody.velocity; // get the manually set bone decay value float boneDecay = boneDecays[unityBone]; /* * calculate the force decay based on the overall fall decay and the bone profile's * fall force decay curve */ float forceDecay = Mathf.Clamp01(profile.boneData[unityBone].fallForceDecay.Evaluate(fallDecayCurveSample)); //subtract manual decay forceDecay = Mathf.Clamp01(forceDecay - boneDecay); // if we're flipped to extremely, stop trying to follow anim // makes it look like it's 'gliding' forward in superman stance if (dot < profile.loseFollowDot) { forceDecay = 0; } // if we're still using some force to follow if (forceDecay != 0) { Vector3 animVelocity = animationVelocityTrackers[i].velocity; /* * if animation velocity is below threshold magnitude, add some gravity to it */ if (animVelocity.sqrMagnitude < maxVelocityForGravityAdd2) { animVelocity.y = Physics.gravity.y * deltaTime; } /* * if bone decay was manually set to make room for external velocities, * use the most extreme component of each vector as the "target animated" velocity */ if (boneDecay != 0) { animVelocity = MaxAbs(ragdollBoneVelocty, animVelocity); } // set the velocity on the ragdoll rigidbody (based on the force decay) bone.rigidbody.velocity = Vector3.Lerp(ragdollBoneVelocty, animVelocity, forceDecay); } if (i != 0) { /* * calculate the force decay based on the overall fall decay and the bone profile's * fall force decay curve */ float torqueDecay = Mathf.Clamp01(profile.boneData[unityBone].fallTorqueDecay.Evaluate(fallDecayCurveSample)); //subtract manual decay torqueDecay = Mathf.Clamp01(torqueDecay - boneDecay); /* * handle joints target for the ragdoll joints */ HandleJointFollow(bone, profile.maxTorque * torqueDecay, i); } } CheckForFallEnd(fallDecay); }
/* * call to get the ragdoll bone references * * animator component must be humanoid */ public static bool BuildRagdollElements(Animator animator, out RagdollTransform[] allElements, out Dictionary <HumanBodyBones, RagdollTransform> boneElements) { allElements = null; boneElements = null; //check for null animator if (animator == null) { Debug.LogError("No animator found...(BuildRagdollFromPrebuilt"); return(false);// null; } List <RagdollTransform> allBonesList = new List <RagdollTransform>(); // instance ids of the bone transforms so we dont re-add them when checking all children bones below HashSet <int> usedPhysicsTransforms = new HashSet <int>(); //build bones list that use physics boneElements = new Dictionary <HumanBodyBones, RagdollTransform>(); for (int i = 0; i < Ragdoll.bonesCount; i++) { HumanBodyBones humanBodyBone = Ragdoll.humanBones[i]; Transform boneT = animator.GetBoneTransform(humanBodyBone); if (boneT == null) { Debug.LogError("Cant find physics bone: " + humanBodyBone + " on ragdoll: " + animator.name); boneElements = null; usedPhysicsTransforms = null; return(false); } usedPhysicsTransforms.Add(boneT.GetInstanceID()); RagdollTransform ragdollBone = new RagdollTransform(boneT, false, true, i == 0); boneElements.Add(humanBodyBone, ragdollBone); allBonesList.Add(ragdollBone); } //build other non physics bones //get all transform children of the hip bone Transform[] allChildren = allBonesList[0].transform.GetComponentsInChildren <Transform>(); for (int i = 0; i < allChildren.Length; i++) { Transform child = allChildren[i]; //if its not a physics bone if (!usedPhysicsTransforms.Contains(child.GetInstanceID())) { bool isPhysicsParent = child.GetComponentInChildren <Rigidbody>() != null; allBonesList.Add(new RagdollTransform(child, isPhysicsParent, false, false)); } } allElements = allBonesList.ToArray(); return(true); }
public void DismemberBone(string reason, RagdollTransform bone) { dismemberment.DismemberBone(reason, this, bone); }
public bool BoneDismembered(RagdollTransform bone) { return(dismemberment.BoneDismembered(bone)); }
public void DismemberBone(RagdollTransform bone, int delay) { dismemberment.DismemberBone(this, bone, delay, false); }
public void SetFollowTarget(RagdollTransform followTarget) { this.followTarget = followTarget; }