Unity创建布娃娃ragdoll源码以及布娃娃的坑
项目要做死亡自然一点就用布娃娃系统,其实可以用其他插件
选用了自带的布娃娃,出现一个问题每个角色的骨骼结构和命名一样,不想每次来个新模型都要打开工具把每个部位拖到布娃娃创建界面里面,创建布娃娃
顺便谈一谈布娃娃的坑
1.播放布娃娃的时候要把animator勾掉,不然不生效
2.部位穿插拉伸,要把部位Character Joint组件上面的Enable Projection勾上
3.激活布娃娃弹得很高,就是刚体的速度,把rigidbody的速度置为0
4.如果布娃娃动作僵硬,肯定用错骨骼来绑定布娃娃导致的
5.布娃娃穿透场景碰撞的问题,其实这个由于速度太快引起的,可以设置rigidbody的碰撞检测模式collisionDetectionMode
6.受力不要全部部位都给力,一般都是给一个部位就够了,不然各种力作用引起怪异表现
7.关于倒地之后抖动问题,这个只能加个检测,如果所有刚体速度小于某个数则关闭刚体功能
8.关于播放布娃娃之前发现部位有部分穿插到其他碰撞器,这个时候给个检测时间,把碰撞器变成触发器,知道没碰撞则变成碰撞器
默认值是Discrete,可以使用Continuous,建议只是触发布娃娃的时候动态修改模式,不然会对性能有影响
源码代码
using UnityEngine;
using UnityEditor;
using System.Collections;
using System;class CreateRagdoll : ScriptableWizard
{public Transform root;public Transform leftHips;public Transform leftKnee;public Transform leftFoot;public Transform rightHips;public Transform rightKnee;public Transform rightFoot;public Transform leftArm;public Transform leftElbow;public Transform rightArm;public Transform rightElbow;public Transform middleSpine;public Transform head;public float totalMass = 20;public float strength = 0.0F;Vector3 right = Vector3.right;Vector3 up = Vector3.up;Vector3 forward = Vector3.forward;Vector3 worldRight = Vector3.right;Vector3 worldUp = Vector3.up;Vector3 worldForward = Vector3.forward;public bool flipForward = false;class BoneInfo{public string name;public Transform anchor;public CharacterJoint joint;public BoneInfo parent;public float minLimit;public float maxLimit;public float swingLimit;public Vector3 axis;public Vector3 normalAxis;public float radiusScale;public Type colliderType;public ArrayList children = new ArrayList();public float density;public float summedMass;// The mass of this and all children bodies}ArrayList bones;BoneInfo rootBone;string CheckConsistency(){PrepareBones();Hashtable map = new Hashtable();foreach (BoneInfo bone in bones){if (bone.anchor){if (map[bone.anchor] != null){BoneInfo oldBone = (BoneInfo)map[bone.anchor];return String.Format("{0} and {1} may not be assigned to the same bone.", bone.name, oldBone.name);}map[bone.anchor] = bone;}}foreach (BoneInfo bone in bones){if (bone.anchor == null)return String.Format("{0} has not been assigned yet.\n", bone.name);}return "";}void OnDrawGizmos(){if (root){Gizmos.color = Color.red; Gizmos.DrawRay(root.position, root.TransformDirection(right));Gizmos.color = Color.green; Gizmos.DrawRay(root.position, root.TransformDirection(up));Gizmos.color = Color.blue; Gizmos.DrawRay(root.position, root.TransformDirection(forward));}}[MenuItem("GameObject/Create Ragdoll")]static void CreateWizard(){ScriptableWizard.DisplayWizard("Create Ragdoll", typeof(CreateRagdoll));}void DecomposeVector(out Vector3 normalCompo, out Vector3 tangentCompo, Vector3 outwardDir, Vector3 outwardNormal){outwardNormal = outwardNormal.normalized;normalCompo = outwardNormal * Vector3.Dot(outwardDir, outwardNormal);tangentCompo = outwardDir - normalCompo;}void CalculateAxes(){if (head != null && root != null)up = CalculateDirectionAxis(root.InverseTransformPoint(head.position));if (rightElbow != null && root != null){Vector3 removed, temp;DecomposeVector(out temp, out removed, root.InverseTransformPoint(rightElbow.position), up);right = CalculateDirectionAxis(removed);}forward = Vector3.Cross(right, up);if (flipForward)forward = -forward;}void OnWizardUpdate(){errorString = CheckConsistency();CalculateAxes();if (errorString.Length != 0){helpString = "Drag all bones from the hierarchy into their slots.\nMake sure your character is in T-Stand.\n";}else{helpString = "Make sure your character is in T-Stand.\nMake sure the blue axis faces in the same direction the chracter is looking.\nUse flipForward to flip the direction";}isValid = errorString.Length == 0;}void PrepareBones(){if (root){worldRight = root.TransformDirection(right);worldUp = root.TransformDirection(up);worldForward = root.TransformDirection(forward);}bones = new ArrayList();rootBone = new BoneInfo();rootBone.name = "Root";rootBone.anchor = root;rootBone.parent = null;rootBone.density = 2.5F;bones.Add(rootBone);AddMirroredJoint("Hips", leftHips, rightHips, "Root", worldRight, worldForward, -20, 70, 30, typeof(CapsuleCollider), 0.3F, 1.5F);AddMirroredJoint("Knee", leftKnee, rightKnee, "Hips", worldRight, worldForward, -80, 0, 0, typeof(CapsuleCollider), 0.25F, 1.5F);// AddMirroredJoint ("Hips", leftHips, rightHips, "Root", worldRight, worldForward, -0, -70, 30, typeof(CapsuleCollider), 0.3F, 1.5F);// AddMirroredJoint ("Knee", leftKnee, rightKnee, "Hips", worldRight, worldForward, -0, -50, 0, typeof(CapsuleCollider), .25F, 1.5F);AddJoint("Middle Spine", middleSpine, "Root", worldRight, worldForward, -20, 20, 10, null, 1, 2.5F);AddMirroredJoint("Arm", leftArm, rightArm, "Middle Spine", worldUp, worldForward, -70, 10, 50, typeof(CapsuleCollider), 0.25F, 1.0F);AddMirroredJoint("Elbow", leftElbow, rightElbow, "Arm", worldForward, worldUp, -90, 0, 0, typeof(CapsuleCollider), 0.20F, 1.0F);AddJoint("Head", head, "Middle Spine", worldRight, worldForward, -40, 25, 25, null, 1, 1.0F);}void OnWizardCreate(){Cleanup();BuildCapsules();AddBreastColliders();AddHeadCollider();BuildBodies();BuildJoints();CalculateMass();}BoneInfo FindBone(string name){foreach (BoneInfo bone in bones){if (bone.name == name)return bone;}return null;}void AddMirroredJoint(string name, Transform leftAnchor, Transform rightAnchor, string parent, Vector3 worldTwistAxis, Vector3 worldSwingAxis, float minLimit, float maxLimit, float swingLimit, Type colliderType, float radiusScale, float density){AddJoint("Left " + name, leftAnchor, parent, worldTwistAxis, worldSwingAxis, minLimit, maxLimit, swingLimit, colliderType, radiusScale, density);AddJoint("Right " + name, rightAnchor, parent, worldTwistAxis, worldSwingAxis, minLimit, maxLimit, swingLimit, colliderType, radiusScale, density);}void AddJoint(string name, Transform anchor, string parent, Vector3 worldTwistAxis, Vector3 worldSwingAxis, float minLimit, float maxLimit, float swingLimit, Type colliderType, float radiusScale, float density){BoneInfo bone = new BoneInfo();bone.name = name;bone.anchor = anchor;bone.axis = worldTwistAxis;bone.normalAxis = worldSwingAxis;bone.minLimit = minLimit;bone.maxLimit = maxLimit;bone.swingLimit = swingLimit;bone.density = density;bone.colliderType = colliderType;bone.radiusScale = radiusScale;if (FindBone(parent) != null)bone.parent = FindBone(parent);else if (name.StartsWith("Left"))bone.parent = FindBone("Left " + parent);else if (name.StartsWith("Right"))bone.parent = FindBone("Right " + parent);bone.parent.children.Add(bone);bones.Add(bone);}void BuildCapsules(){foreach (BoneInfo bone in bones){if (bone.colliderType != typeof(CapsuleCollider))continue;int direction;float distance;if (bone.children.Count == 1){BoneInfo childBone = (BoneInfo)bone.children[0];Vector3 endPoint = childBone.anchor.position;CalculateDirection(bone.anchor.InverseTransformPoint(endPoint), out direction, out distance);}else{Vector3 endPoint = (bone.anchor.position - bone.parent.anchor.position) + bone.anchor.position;CalculateDirection(bone.anchor.InverseTransformPoint(endPoint), out direction, out distance);if (bone.anchor.GetComponentsInChildren(typeof(Transform)).Length > 1){Bounds bounds = new Bounds();foreach (Transform child in bone.anchor.GetComponentsInChildren(typeof(Transform))){bounds.Encapsulate(bone.anchor.InverseTransformPoint(child.position));}if (distance > 0)distance = bounds.max[direction];elsedistance = bounds.min[direction];}}CapsuleCollider collider = bone.anchor.gameObject.AddComponent<CapsuleCollider>();collider.direction = direction;Vector3 center = Vector3.zero;center[direction] = distance * 0.5F;collider.center = center;collider.height = Mathf.Abs(distance);collider.radius = Mathf.Abs(distance * bone.radiusScale);}}void Cleanup(){foreach (BoneInfo bone in bones){if (!bone.anchor)continue;Component[] joints = bone.anchor.GetComponentsInChildren(typeof(Joint));foreach (Joint joint in joints)DestroyImmediate(joint);Component[] bodies = bone.anchor.GetComponentsInChildren(typeof(Rigidbody));foreach (Rigidbody body in bodies)DestroyImmediate(body);Component[] colliders = bone.anchor.GetComponentsInChildren(typeof(Collider));foreach (Collider collider in colliders)DestroyImmediate(collider);}}void BuildBodies(){foreach (BoneInfo bone in bones){Rigidbody ri = bone.anchor.gameObject.AddComponent<Rigidbody>();ri.mass = bone.density;}}void BuildJoints(){foreach (BoneInfo bone in bones){if (bone.parent == null)continue;CharacterJoint joint = (CharacterJoint)bone.anchor.gameObject.AddComponent<CharacterJoint>();bone.joint = joint;// Setup connection and axisjoint.axis = CalculateDirectionAxis(bone.anchor.InverseTransformDirection(bone.axis));joint.swingAxis = CalculateDirectionAxis(bone.anchor.InverseTransformDirection(bone.normalAxis));joint.anchor = Vector3.zero;joint.connectedBody = bone.parent.anchor.GetComponent<Rigidbody>();// Setup limitsSoftJointLimit limit = new SoftJointLimit();limit.limit = bone.minLimit;joint.lowTwistLimit = limit;limit.limit = bone.maxLimit;joint.highTwistLimit = limit;limit.limit = bone.swingLimit;joint.swing1Limit = limit;limit.limit = 0;joint.swing2Limit = limit;}}void CalculateMassRecurse(BoneInfo bone){float mass = bone.anchor.GetComponent<Rigidbody>().mass;foreach (BoneInfo child in bone.children){CalculateMassRecurse(child);mass += child.summedMass;}bone.summedMass = mass;}void CalculateMass(){// Calculate allChildMass by summing all bodiesCalculateMassRecurse(rootBone);// Rescale the mass so that the whole character weights totalMassfloat massScale = totalMass / rootBone.summedMass;foreach (BoneInfo bone in bones)bone.anchor.GetComponent<Rigidbody>().mass *= massScale;// Recalculate allChildMass by summing all bodiesCalculateMassRecurse(rootBone);}///@todo: This should take into account the inertia tensor.JointDrive CalculateSpringDamper(float frequency, float damping, float mass){JointDrive drive = new JointDrive();drive.positionSpring = 9 * frequency * frequency * mass;drive.positionDamper = 4.5F * frequency * damping * mass;return drive;}static void CalculateDirection(Vector3 point, out int direction, out float distance){// Calculate longest axisdirection = 0;if (Mathf.Abs(point[1]) > Mathf.Abs(point[0]))direction = 1;if (Mathf.Abs(point[2]) > Mathf.Abs(point[direction]))direction = 2;distance = point[direction];}static Vector3 CalculateDirectionAxis(Vector3 point){int direction = 0;float distance;CalculateDirection(point, out direction, out distance);Vector3 axis = Vector3.zero;if (distance > 0)axis[direction] = 1.0F;elseaxis[direction] = -1.0F;return axis;}static int SmallestComponent(Vector3 point){int direction = 0;if (Mathf.Abs(point[1]) < Mathf.Abs(point[0]))direction = 1;if (Mathf.Abs(point[2]) < Mathf.Abs(point[direction]))direction = 2;return direction;}static int LargestComponent(Vector3 point){int direction = 0;if (Mathf.Abs(point[1]) > Mathf.Abs(point[0]))direction = 1;if (Mathf.Abs(point[2]) > Mathf.Abs(point[direction]))direction = 2;return direction;}static int SecondLargestComponent(Vector3 point){int smallest = SmallestComponent(point);int largest = LargestComponent(point);if (smallest < largest){int temp = largest;largest = smallest;smallest = temp;}if (smallest == 0 && largest == 1)return 2;else if (smallest == 0 && largest == 2)return 1;elsereturn 0;}Bounds Clip(Bounds bounds, Transform relativeTo, Transform clipTransform, bool below){int axis = LargestComponent(bounds.size);if (Vector3.Dot(worldUp, relativeTo.TransformPoint(bounds.max)) > Vector3.Dot(worldUp, relativeTo.TransformPoint(bounds.min)) == below){Vector3 min = bounds.min;min[axis] = relativeTo.InverseTransformPoint(clipTransform.position)[axis];bounds.min = min;}else{Vector3 max = bounds.max;max[axis] = relativeTo.InverseTransformPoint(clipTransform.position)[axis];bounds.max = max;}return bounds;}Bounds GetBreastBounds(Transform relativeTo){// Root boundsBounds bounds = new Bounds();bounds.Encapsulate(relativeTo.InverseTransformPoint(leftHips.position));bounds.Encapsulate(relativeTo.InverseTransformPoint(rightHips.position));bounds.Encapsulate(relativeTo.InverseTransformPoint(leftArm.position));bounds.Encapsulate(relativeTo.InverseTransformPoint(rightArm.position));Vector3 size = bounds.size;size[SmallestComponent(bounds.size)] = size[LargestComponent(bounds.size)] / 2.0F;bounds.size = size;return bounds;}void AddBreastColliders(){// Middle spine and rootif (middleSpine != null && root != null){Bounds bounds;BoxCollider box;// Middle spine boundsbounds = Clip(GetBreastBounds(root), root, middleSpine, false);box = (BoxCollider)root.gameObject.AddComponent<BoxCollider>();box.center = bounds.center;box.size = bounds.size;bounds = Clip(GetBreastBounds(middleSpine), middleSpine, middleSpine, true);box = (BoxCollider)middleSpine.gameObject.AddComponent<BoxCollider>();box.center = bounds.center;box.size = bounds.size;}// Only rootelse{Bounds bounds = new Bounds();bounds.Encapsulate(root.InverseTransformPoint(leftHips.position));bounds.Encapsulate(root.InverseTransformPoint(rightHips.position));bounds.Encapsulate(root.InverseTransformPoint(leftArm.position));bounds.Encapsulate(root.InverseTransformPoint(rightArm.position));Vector3 size = bounds.size;size[SmallestComponent(bounds.size)] = size[LargestComponent(bounds.size)] / 2.0F;BoxCollider box = (BoxCollider)root.gameObject.AddComponent<BoxCollider>();box.center = bounds.center;box.size = size;}}void AddHeadCollider(){if (head.GetComponent<Collider>())Destroy(head.GetComponent<Collider>());float radius = Vector3.Distance(leftArm.transform.position, rightArm.transform.position);radius /= 4;SphereCollider sphere = (SphereCollider)head.gameObject.AddComponent<SphereCollider>();sphere.radius = radius;Vector3 center = Vector3.zero;int direction;float distance;CalculateDirection(head.InverseTransformPoint(root.position), out direction, out distance);if (distance > 0)center[direction] = -radius;elsecenter[direction] = radius;sphere.center = center;}}
一般项目中都要搞这些自动化工具,不过前提是美术命名规范,骨骼的名字统一
我按照一个角色为例,把对应的骨骼名字定义好
然后调用下面代码CreateHumanRagdoll
using UnityEngine;
using UnityEditor;
using System.Collections;
using System;class MyCreateRagdoll
{public static string rootName = "Character1_Hips";public static string leftHipsName = "Character1_LeftUpLeg";public static string leftKneeName = "Character1_LeftLeg";public static string leftFootName = "Character1_LeftFoot";public static string rightHipsName = "Character1_RightUpLeg";public static string rightKneeName = "Character1_RightLeg";public static string rightFootName = "Character1_RightFoot";public static string leftArmName = "Character1_LeftArm";public static string leftElbowName = "Character1_LeftForeArm";public static string rightArmName = "Character1_RightArm";public static string rightElbowName = "Character1_RightForeArm";public static string middleSpineName = "Character1_Spine2";public static string headName = "Character1_Head";[MenuItem("GameObject/Create MyRagdoll", false, 1)]static void CreateRagdoll(){GameObject go = Selection.activeGameObject;if (null != go){CreateHumanRagdoll(go);}}public static void CreateHumanRagdoll(GameObject go){MyCreateRagdoll rb = new MyCreateRagdoll();Transform[] tt = go.GetComponentsInChildren<Transform>();foreach (Transform t in tt){if (t.name == rootName){rb.root = t;}else if (t.name == leftHipsName){rb.leftHips = t;}else if (t.name == leftKneeName){rb.leftKnee = t;}else if (t.name == leftFootName){rb.leftFoot = t;}else if (t.name == rightHipsName){rb.rightHips = t;}else if (t.name == rightKneeName){rb.rightKnee = t;}else if (t.name == rightFootName){rb.rightFoot = t;}else if (t.name == leftArmName){rb.leftArm = t;}else if (t.name == leftElbowName){rb.leftElbow = t;}else if (t.name == rightArmName){rb.rightArm = t;}else if (t.name == rightElbowName){rb.rightElbow = t;}else if (t.name == middleSpineName){rb.middleSpine = t;}else if (t.name == headName){rb.head = t;}}rb.PrepareBones();rb.OnWizardCreate();}public Transform root;public Transform leftHips;public Transform leftKnee;public Transform leftFoot;public Transform rightHips;public Transform rightKnee;public Transform rightFoot;public Transform leftArm;public Transform leftElbow;public Transform rightArm;public Transform rightElbow;public Transform middleSpine;public Transform head;public float totalMass = 20;public float strength = 0.0F;Vector3 right = Vector3.right;Vector3 up = Vector3.up;Vector3 forward = Vector3.forward;Vector3 worldRight = Vector3.right;Vector3 worldUp = Vector3.up;Vector3 worldForward = Vector3.forward;public bool flipForward = false;class BoneInfo{public string name;public Transform anchor;public CharacterJoint joint;public BoneInfo parent;public float minLimit;public float maxLimit;public float swingLimit;public Vector3 axis;public Vector3 normalAxis;public float radiusScale;public Type colliderType;public ArrayList children = new ArrayList();public float density;public float summedMass;// The mass of this and all children bodies}ArrayList bones;BoneInfo rootBone;string CheckConsistency(){PrepareBones();Hashtable map = new Hashtable();foreach (BoneInfo bone in bones){if (bone.anchor){if (map[bone.anchor] != null){BoneInfo oldBone = (BoneInfo)map[bone.anchor];return String.Format("{0} and {1} may not be assigned to the same bone.", bone.name, oldBone.name);}map[bone.anchor] = bone;}}foreach (BoneInfo bone in bones){if (bone.anchor == null)return String.Format("{0} has not been assigned yet.\n", bone.name);}return "";}void OnDrawGizmos(){if (root){Gizmos.color = Color.red; Gizmos.DrawRay(root.position, root.TransformDirection(right));Gizmos.color = Color.green; Gizmos.DrawRay(root.position, root.TransformDirection(up));Gizmos.color = Color.blue; Gizmos.DrawRay(root.position, root.TransformDirection(forward));}}[MenuItem("GameObject/Create Ragdoll")]static void CreateWizard(){ScriptableWizard.DisplayWizard("Create Ragdoll", typeof(CreateRagdoll));}void DecomposeVector(out Vector3 normalCompo, out Vector3 tangentCompo, Vector3 outwardDir, Vector3 outwardNormal){outwardNormal = outwardNormal.normalized;normalCompo = outwardNormal * Vector3.Dot(outwardDir, outwardNormal);tangentCompo = outwardDir - normalCompo;}void CalculateAxes(){if (head != null && root != null)up = CalculateDirectionAxis(root.InverseTransformPoint(head.position));if (rightElbow != null && root != null){Vector3 removed, temp;DecomposeVector(out temp, out removed, root.InverseTransformPoint(rightElbow.position), up);right = CalculateDirectionAxis(removed);}forward = Vector3.Cross(right, up);if (flipForward)forward = -forward;}void PrepareBones(){if (root){worldRight = root.TransformDirection(right);worldUp = root.TransformDirection(up);worldForward = root.TransformDirection(forward);}bones = new ArrayList();rootBone = new BoneInfo();rootBone.name = "Root";rootBone.anchor = root;rootBone.parent = null;rootBone.density = 2.5F;bones.Add(rootBone);AddMirroredJoint("Hips", leftHips, rightHips, "Root", worldRight, worldForward, -20, 70, 30, typeof(CapsuleCollider), 0.3F, 1.5F);AddMirroredJoint("Knee", leftKnee, rightKnee, "Hips", worldRight, worldForward, -80, 0, 0, typeof(CapsuleCollider), 0.25F, 1.5F);// AddMirroredJoint ("Hips", leftHips, rightHips, "Root", worldRight, worldForward, -0, -70, 30, typeof(CapsuleCollider), 0.3F, 1.5F);// AddMirroredJoint ("Knee", leftKnee, rightKnee, "Hips", worldRight, worldForward, -0, -50, 0, typeof(CapsuleCollider), .25F, 1.5F);AddJoint("Middle Spine", middleSpine, "Root", worldRight, worldForward, -20, 20, 10, null, 1, 2.5F);AddMirroredJoint("Arm", leftArm, rightArm, "Middle Spine", worldUp, worldForward, -70, 10, 50, typeof(CapsuleCollider), 0.25F, 1.0F);AddMirroredJoint("Elbow", leftElbow, rightElbow, "Arm", worldForward, worldUp, -90, 0, 0, typeof(CapsuleCollider), 0.20F, 1.0F);AddJoint("Head", head, "Middle Spine", worldRight, worldForward, -40, 25, 25, null, 1, 1.0F);}void OnWizardCreate(){Cleanup();BuildCapsules();AddBreastColliders();AddHeadCollider();BuildBodies();BuildJoints();CalculateMass();}BoneInfo FindBone(string name){foreach (BoneInfo bone in bones){if (bone.name == name)return bone;}return null;}void AddMirroredJoint(string name, Transform leftAnchor, Transform rightAnchor, string parent, Vector3 worldTwistAxis, Vector3 worldSwingAxis, float minLimit, float maxLimit, float swingLimit, Type colliderType, float radiusScale, float density){AddJoint("Left " + name, leftAnchor, parent, worldTwistAxis, worldSwingAxis, minLimit, maxLimit, swingLimit, colliderType, radiusScale, density);AddJoint("Right " + name, rightAnchor, parent, worldTwistAxis, worldSwingAxis, minLimit, maxLimit, swingLimit, colliderType, radiusScale, density);}void AddJoint(string name, Transform anchor, string parent, Vector3 worldTwistAxis, Vector3 worldSwingAxis, float minLimit, float maxLimit, float swingLimit, Type colliderType, float radiusScale, float density){BoneInfo bone = new BoneInfo();bone.name = name;bone.anchor = anchor;bone.axis = worldTwistAxis;bone.normalAxis = worldSwingAxis;bone.minLimit = minLimit;bone.maxLimit = maxLimit;bone.swingLimit = swingLimit;bone.density = density;bone.colliderType = colliderType;bone.radiusScale = radiusScale;if (FindBone(parent) != null)bone.parent = FindBone(parent);else if (name.StartsWith("Left"))bone.parent = FindBone("Left " + parent);else if (name.StartsWith("Right"))bone.parent = FindBone("Right " + parent);bone.parent.children.Add(bone);bones.Add(bone);}void BuildCapsules(){foreach (BoneInfo bone in bones){if (bone.colliderType != typeof(CapsuleCollider))continue;int direction;float distance;if (bone.children.Count == 1){BoneInfo childBone = (BoneInfo)bone.children[0];Vector3 endPoint = childBone.anchor.position;CalculateDirection(bone.anchor.InverseTransformPoint(endPoint), out direction, out distance);}else{Vector3 endPoint = (bone.anchor.position - bone.parent.anchor.position) + bone.anchor.position;CalculateDirection(bone.anchor.InverseTransformPoint(endPoint), out direction, out distance);if (bone.anchor.GetComponentsInChildren(typeof(Transform)).Length > 1){Bounds bounds = new Bounds();foreach (Transform child in bone.anchor.GetComponentsInChildren(typeof(Transform))){bounds.Encapsulate(bone.anchor.InverseTransformPoint(child.position));}if (distance > 0)distance = bounds.max[direction];elsedistance = bounds.min[direction];}}CapsuleCollider collider = bone.anchor.gameObject.AddComponent<CapsuleCollider>();collider.direction = direction;Vector3 center = Vector3.zero;center[direction] = distance * 0.5F;collider.center = center;collider.height = Mathf.Abs(distance);collider.radius = Mathf.Abs(distance * bone.radiusScale);}}void Cleanup(){foreach (BoneInfo bone in bones){if (!bone.anchor)continue;Component[] joints = bone.anchor.GetComponentsInChildren(typeof(Joint));foreach (Joint joint in joints)GameObject.DestroyImmediate(joint);Component[] bodies = bone.anchor.GetComponentsInChildren(typeof(Rigidbody));foreach (Rigidbody body in bodies)GameObject.DestroyImmediate(body);Component[] colliders = bone.anchor.GetComponentsInChildren(typeof(Collider));foreach (Collider collider in colliders)GameObject.DestroyImmediate(collider);}}void BuildBodies(){foreach (BoneInfo bone in bones){Rigidbody ri = bone.anchor.gameObject.AddComponent<Rigidbody>();ri.mass = bone.density;}}void BuildJoints(){foreach (BoneInfo bone in bones){if (bone.parent == null)continue;CharacterJoint joint = (CharacterJoint)bone.anchor.gameObject.AddComponent<CharacterJoint>();bone.joint = joint;// Setup connection and axisjoint.axis = CalculateDirectionAxis(bone.anchor.InverseTransformDirection(bone.axis));joint.swingAxis = CalculateDirectionAxis(bone.anchor.InverseTransformDirection(bone.normalAxis));joint.anchor = Vector3.zero;joint.connectedBody = bone.parent.anchor.GetComponent<Rigidbody>();// Setup limitsSoftJointLimit limit = new SoftJointLimit();limit.limit = bone.minLimit;joint.lowTwistLimit = limit;limit.limit = bone.maxLimit;joint.highTwistLimit = limit;limit.limit = bone.swingLimit;joint.swing1Limit = limit;limit.limit = 0;joint.swing2Limit = limit;}}void CalculateMassRecurse(BoneInfo bone){float mass = bone.anchor.GetComponent<Rigidbody>().mass;foreach (BoneInfo child in bone.children){CalculateMassRecurse(child);mass += child.summedMass;}bone.summedMass = mass;}void CalculateMass(){// Calculate allChildMass by summing all bodiesCalculateMassRecurse(rootBone);// Rescale the mass so that the whole character weights totalMassfloat massScale = totalMass / rootBone.summedMass;foreach (BoneInfo bone in bones)bone.anchor.GetComponent<Rigidbody>().mass *= massScale;// Recalculate allChildMass by summing all bodiesCalculateMassRecurse(rootBone);}///@todo: This should take into account the inertia tensor.JointDrive CalculateSpringDamper(float frequency, float damping, float mass){JointDrive drive = new JointDrive();drive.positionSpring = 9 * frequency * frequency * mass;drive.positionDamper = 4.5F * frequency * damping * mass;return drive;}static void CalculateDirection(Vector3 point, out int direction, out float distance){// Calculate longest axisdirection = 0;if (Mathf.Abs(point[1]) > Mathf.Abs(point[0]))direction = 1;if (Mathf.Abs(point[2]) > Mathf.Abs(point[direction]))direction = 2;distance = point[direction];}static Vector3 CalculateDirectionAxis(Vector3 point){int direction = 0;float distance;CalculateDirection(point, out direction, out distance);Vector3 axis = Vector3.zero;if (distance > 0)axis[direction] = 1.0F;elseaxis[direction] = -1.0F;return axis;}static int SmallestComponent(Vector3 point){int direction = 0;if (Mathf.Abs(point[1]) < Mathf.Abs(point[0]))direction = 1;if (Mathf.Abs(point[2]) < Mathf.Abs(point[direction]))direction = 2;return direction;}static int LargestComponent(Vector3 point){int direction = 0;if (Mathf.Abs(point[1]) > Mathf.Abs(point[0]))direction = 1;if (Mathf.Abs(point[2]) > Mathf.Abs(point[direction]))direction = 2;return direction;}static int SecondLargestComponent(Vector3 point){int smallest = SmallestComponent(point);int largest = LargestComponent(point);if (smallest < largest){int temp = largest;largest = smallest;smallest = temp;}if (smallest == 0 && largest == 1)return 2;else if (smallest == 0 && largest == 2)return 1;elsereturn 0;}Bounds Clip(Bounds bounds, Transform relativeTo, Transform clipTransform, bool below){int axis = LargestComponent(bounds.size);if (Vector3.Dot(worldUp, relativeTo.TransformPoint(bounds.max)) > Vector3.Dot(worldUp, relativeTo.TransformPoint(bounds.min)) == below){Vector3 min = bounds.min;min[axis] = relativeTo.InverseTransformPoint(clipTransform.position)[axis];bounds.min = min;}else{Vector3 max = bounds.max;max[axis] = relativeTo.InverseTransformPoint(clipTransform.position)[axis];bounds.max = max;}return bounds;}Bounds GetBreastBounds(Transform relativeTo){// Root boundsBounds bounds = new Bounds();bounds.Encapsulate(relativeTo.InverseTransformPoint(leftHips.position));bounds.Encapsulate(relativeTo.InverseTransformPoint(rightHips.position));bounds.Encapsulate(relativeTo.InverseTransformPoint(leftArm.position));bounds.Encapsulate(relativeTo.InverseTransformPoint(rightArm.position));Vector3 size = bounds.size;size[SmallestComponent(bounds.size)] = size[LargestComponent(bounds.size)] / 2.0F;bounds.size = size;return bounds;}void AddBreastColliders(){// Middle spine and rootif (middleSpine != null && root != null){Bounds bounds;BoxCollider box;// Middle spine boundsbounds = Clip(GetBreastBounds(root), root, middleSpine, false);box = (BoxCollider)root.gameObject.AddComponent<BoxCollider>();box.center = bounds.center;box.size = bounds.size;bounds = Clip(GetBreastBounds(middleSpine), middleSpine, middleSpine, true);box = (BoxCollider)middleSpine.gameObject.AddComponent<BoxCollider>();box.center = bounds.center;box.size = bounds.size;}// Only rootelse{Bounds bounds = new Bounds();bounds.Encapsulate(root.InverseTransformPoint(leftHips.position));bounds.Encapsulate(root.InverseTransformPoint(rightHips.position));bounds.Encapsulate(root.InverseTransformPoint(leftArm.position));bounds.Encapsulate(root.InverseTransformPoint(rightArm.position));Vector3 size = bounds.size;size[SmallestComponent(bounds.size)] = size[LargestComponent(bounds.size)] / 2.0F;BoxCollider box = (BoxCollider)root.gameObject.AddComponent<BoxCollider>();box.center = bounds.center;box.size = size;}}void AddHeadCollider(){if (head.GetComponent<Collider>())GameObject.Destroy(head.GetComponent<Collider>());float radius = Vector3.Distance(leftArm.transform.position, rightArm.transform.position);radius /= 4;SphereCollider sphere = (SphereCollider)head.gameObject.AddComponent<SphereCollider>();sphere.radius = radius;Vector3 center = Vector3.zero;int direction;float distance;CalculateDirection(head.InverseTransformPoint(root.position), out direction, out distance);if (distance > 0)center[direction] = -radius;elsecenter[direction] = radius;sphere.center = center;}}
工程
链接:https://pan.baidu.com/s/1IYU9ayDaUFTMSBjh6lQ1HQ 密码:k7lg
Unity创建布娃娃ragdoll源码以及布娃娃的坑相关推荐
- Unity中的UGUI源码解析之事件系统(9)-输入模块(下)
Unity中的UGUI源码解析之事件系统(9)-输入模块(下) 接上一篇文章, 继续介绍输入模块. StandaloneInputModule类是上一篇文章介绍的抽象类PointerInputModu ...
- 【Linux 内核】进程管理 ( 内核线程概念 | 内核线程、普通进程、用户线程 | 内核线程与普通进程区别 | 内核线程主要用途 | 内核线程创建函数 kernel_thread 源码 )
文章目录 一.内核线程概念 二.内核线程.普通进程.用户线程 三.内核线程.普通进程区别 四.内核线程主要用途 五.内核线程创建函数 kernel_thread 源码 一.内核线程概念 直接 由 Li ...
- 【Android 安全】DEX 加密 ( 代理 Application 开发 | 加载 dex 文件 | 使用反射获取方法创建本应用的 dexElements | 各版本创建 dex 数组源码对比 )
文章目录 一.不同 Android 系统创建 dex 数组源码对比 二.不同 Android 系统创建 dex 数组源码对比 三. Android 5.1 及以下系统反射方法并创建 Element[] ...
- lmbs PHP,PHP的GD2函数创建折线图源码示例
PHP的GD2函数创建折线图源码示例 代码来自 codego.net/tags/4/1/ if(!is_numeric($data[$i])) die("error id:1"); ...
- rts游戏服务器源码,unity即时战略游戏源码Real-time strategy (RTS) game kit
unity即时战略游戏源码Real-time strategy (RTS) game kit (Modern Tactics) 1.2.1 Requires Unity 4.5.2 or hig ...
- linux源码共享,Android之高仿飞鸽传书热点创建与共享源码
这两天,无意中看到飞鸽传书这个小东东,然后又突然对他的wifi热点创建与共享比较感兴趣,于是乎把他的APK给反编译了,很蛋疼的还原了一下他的这一小模块代码,感觉效果差不多,所以跟大家分享一下,下面我们 ...
- Unity中的UGUI源码解析之事件系统(2)-EventSystem组件
Unity中的UGUI源码解析之事件系统(2)-EventSystem组件 今天介绍我们的第一个主角: EventSystem. EventSystem在整个事件系统中处于中心, 相当于事件系统的管理 ...
- Unity中的UGUI源码解析之事件系统(8)-输入模块(中)
Unity中的UGUI源码解析之事件系统(8)-输入模块(中) 接上一篇文章, 继续介绍输入模块. Unity中主要处理的是指针事件, 也就是在2d平面上跟踪指针设备输入坐标的的事件, 这一类事件有鼠 ...
- Unity中的UGUI源码解析之图形对象(Graphic)(2)-ICanvasElement
Unity中的UGUI源码解析之图形对象(Graphic)(2)-ICanvasElement 在上一篇文章中, 我们对整个Graphic部分做了概述, 这篇文章我们介绍ICanvasElement和 ...
最新文章
- javascript选择器_如何通过选择正确JavaScript选择器来避免沮丧
- 100多次竞赛后,他研发了一个几乎可以解决所有机器学习问题的框架
- 轻松实现远程批量拷贝文件脚本(女学生作品)
- 图像的阈值分割(迭代法选择阈值)
- 优秀产品经理(CEO)必须get的财税知识
- XML Web Service 安全性
- Android 自定义组件随着手指自动画圆
- Python和Java就业前景对比
- java源程序可以有几个主类_Java源程序是由类定义组成的,每个程序可以定义若干个类,但只有一个类是主类。_学小易找答案...
- Hadoop入门(二十四)Mapreduce的求TopK程序
- 【转】iPython入门技巧
- Spring 常见问题( 持续更新... ... )
- 经典:一文详解socket
- Intellij IDEA 2016 使用
- python 函数重载_python中有函数重载吗
- linux下巧用tail命令 创建自解压tar文件
- 初中计算机考试操作题免费,初中信息技术考excel操作题.doc
- shell脚本下的教你如果运用for,while,unti循环,以及区别l
- python 按比例缩小图片
- 5G移动通信网的定位技术发展趋势