├── ProjectSettings ├── ProjectVersion.txt ├── TagManager.asset ├── TimeManager.asset ├── AudioManager.asset ├── EditorSettings.asset ├── InputManager.asset ├── NavMeshAreas.asset ├── NetworkManager.asset ├── DynamicsManager.asset ├── GraphicsSettings.asset ├── ProjectSettings.asset ├── QualitySettings.asset ├── ClusterInputManager.asset ├── EditorBuildSettings.asset ├── Physics2DSettings.asset └── UnityConnectSettings.asset └── Assets ├── DynamicBone ├── Demo │ ├── c1.fbx │ ├── tail.FBX │ ├── Demo1.unity │ ├── Demo1.unity.meta │ ├── GameController.cs.meta │ ├── GameController.cs │ ├── tail.FBX.meta │ └── c1.fbx.meta ├── ReadMe.txt.meta ├── Demo.meta ├── Scripts.meta ├── Scripts │ ├── DynamicBone.cs.meta │ ├── DynamicBoneCollider.cs.meta │ ├── GPUSkinning.cs.meta │ ├── GPUSkinning_Bone.cs.meta │ ├── GPUSkinning_Bone.cs │ ├── DynamicBoneCollider.cs │ ├── GPUSkinning.cs │ └── DynamicBone.cs └── ReadMe.txt ├── Resources.meta ├── DynamicBone.meta └── Resources ├── GPUSkinning.shader.meta └── GPUSkinning.shader /ProjectSettings/ProjectVersion.txt: -------------------------------------------------------------------------------- 1 | m_EditorVersion: 5.6.2f1 2 | -------------------------------------------------------------------------------- /Assets/DynamicBone/Demo/c1.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenyong2github/DynamicBones-GPUSkinning/HEAD/Assets/DynamicBone/Demo/c1.fbx -------------------------------------------------------------------------------- /Assets/DynamicBone/Demo/tail.FBX: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenyong2github/DynamicBones-GPUSkinning/HEAD/Assets/DynamicBone/Demo/tail.FBX -------------------------------------------------------------------------------- /Assets/DynamicBone/ReadMe.txt.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bdbe6feeda2a62b45ad9a4e311031478 3 | TextScriptImporter: 4 | userData: 5 | -------------------------------------------------------------------------------- /ProjectSettings/TagManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenyong2github/DynamicBones-GPUSkinning/HEAD/ProjectSettings/TagManager.asset -------------------------------------------------------------------------------- /ProjectSettings/TimeManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenyong2github/DynamicBones-GPUSkinning/HEAD/ProjectSettings/TimeManager.asset -------------------------------------------------------------------------------- /Assets/DynamicBone/Demo/Demo1.unity: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenyong2github/DynamicBones-GPUSkinning/HEAD/Assets/DynamicBone/Demo/Demo1.unity -------------------------------------------------------------------------------- /Assets/DynamicBone/Demo/Demo1.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 902c84bf971339c459ce4b757e333a55 3 | DefaultImporter: 4 | userData: 5 | -------------------------------------------------------------------------------- /ProjectSettings/AudioManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenyong2github/DynamicBones-GPUSkinning/HEAD/ProjectSettings/AudioManager.asset -------------------------------------------------------------------------------- /ProjectSettings/EditorSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenyong2github/DynamicBones-GPUSkinning/HEAD/ProjectSettings/EditorSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/InputManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenyong2github/DynamicBones-GPUSkinning/HEAD/ProjectSettings/InputManager.asset -------------------------------------------------------------------------------- /ProjectSettings/NavMeshAreas.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenyong2github/DynamicBones-GPUSkinning/HEAD/ProjectSettings/NavMeshAreas.asset -------------------------------------------------------------------------------- /ProjectSettings/NetworkManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenyong2github/DynamicBones-GPUSkinning/HEAD/ProjectSettings/NetworkManager.asset -------------------------------------------------------------------------------- /ProjectSettings/DynamicsManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenyong2github/DynamicBones-GPUSkinning/HEAD/ProjectSettings/DynamicsManager.asset -------------------------------------------------------------------------------- /ProjectSettings/GraphicsSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenyong2github/DynamicBones-GPUSkinning/HEAD/ProjectSettings/GraphicsSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/ProjectSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenyong2github/DynamicBones-GPUSkinning/HEAD/ProjectSettings/ProjectSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/QualitySettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenyong2github/DynamicBones-GPUSkinning/HEAD/ProjectSettings/QualitySettings.asset -------------------------------------------------------------------------------- /Assets/DynamicBone/Demo.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 21a42390d25252341a66bc19a8addaea 3 | folderAsset: yes 4 | DefaultImporter: 5 | userData: 6 | -------------------------------------------------------------------------------- /Assets/DynamicBone/Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 993edbffbda2d3e4abd24f1bf074c5f2 3 | folderAsset: yes 4 | DefaultImporter: 5 | userData: 6 | -------------------------------------------------------------------------------- /ProjectSettings/ClusterInputManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenyong2github/DynamicBones-GPUSkinning/HEAD/ProjectSettings/ClusterInputManager.asset -------------------------------------------------------------------------------- /ProjectSettings/EditorBuildSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenyong2github/DynamicBones-GPUSkinning/HEAD/ProjectSettings/EditorBuildSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/Physics2DSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenyong2github/DynamicBones-GPUSkinning/HEAD/ProjectSettings/Physics2DSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/UnityConnectSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenyong2github/DynamicBones-GPUSkinning/HEAD/ProjectSettings/UnityConnectSettings.asset -------------------------------------------------------------------------------- /Assets/DynamicBone/Demo/GameController.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 178320cedf292cb4f8d6c0b737b35953 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | -------------------------------------------------------------------------------- /Assets/DynamicBone/Scripts/DynamicBone.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f9ac8d30c6a0d9642a11e5be4c440740 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | -------------------------------------------------------------------------------- /Assets/Resources.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 35ef4b485938546489c950aace5e6bee 3 | folderAsset: yes 4 | timeCreated: 1501578987 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/DynamicBone.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 823d9663195c4fe46ba3791fa9a25ee3 3 | folderAsset: yes 4 | timeCreated: 1501121978 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/DynamicBone/Scripts/DynamicBoneCollider.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: baedd976e12657241bf7ff2d1c685342 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | -------------------------------------------------------------------------------- /Assets/Resources/GPUSkinning.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a8875346e83e0e24e9787f20066e0eb5 3 | timeCreated: 1479260643 4 | licenseType: Free 5 | ShaderImporter: 6 | defaultTextures: [] 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/DynamicBone/Scripts/GPUSkinning.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fe898c8a2d730904e8a29bb8d9f10a64 3 | timeCreated: 1501578410 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/DynamicBone/Scripts/GPUSkinning_Bone.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9125b9fbe7714fb40972ae7ebfea42c3 3 | timeCreated: 1501578410 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/DynamicBone/Scripts/GPUSkinning_Bone.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class GPUSkinning_Bone 5 | { 6 | public Transform transform = null; 7 | 8 | public Matrix4x4 bindpose; 9 | 10 | public GPUSkinning_Bone parent = null; 11 | 12 | public GPUSkinning_Bone[] children = null; 13 | 14 | public Matrix4x4 animationMatrix; 15 | 16 | public string name 17 | { 18 | get 19 | { 20 | return transform.gameObject.name; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Assets/DynamicBone/Demo/GameController.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class GameController : MonoBehaviour 5 | { 6 | public GameObject m_Player; 7 | 8 | void Update() 9 | { 10 | m_Player.transform.Rotate(new Vector3(0, Input.GetAxis("Horizontal") * Time.deltaTime * 200, 0)); 11 | m_Player.transform.Translate(transform.forward * Input.GetAxis("Vertical") * Time.deltaTime * 4); 12 | } 13 | 14 | void OnGUI() 15 | { 16 | GUI.Label(new Rect(50, 50, 200, 20), "Press arrow key to move"); 17 | Animation a = m_Player.GetComponentInChildren(); 18 | a.enabled = GUI.Toggle(new Rect(50, 70, 200, 20), a.enabled, "Play Animation"); 19 | 20 | DynamicBone[] db = m_Player.GetComponents(); 21 | GUI.Label(new Rect(50, 100, 200, 20), "Choose dynamic bone:"); 22 | db[0].enabled = db[1].enabled = GUI.Toggle(new Rect(50, 120, 100, 20), db[0].enabled, "Breasts"); 23 | db[2].enabled = GUI.Toggle(new Rect(50, 140, 100, 20), db[2].enabled, "Tail"); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Assets/Resources/GPUSkinning.shader: -------------------------------------------------------------------------------- 1 | // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' 2 | 3 | Shader "Unlit/GPUSkinning" 4 | { 5 | Properties 6 | { 7 | _MainTex ("Texture", 2D) = "white" {} 8 | } 9 | SubShader 10 | { 11 | Tags { "RenderType" = "Opaque" } 12 | LOD 100 13 | 14 | Pass 15 | { 16 | CGPROGRAM 17 | #pragma vertex vert 18 | #pragma fragment frag 19 | 20 | #include "UnityCG.cginc" 21 | 22 | uniform float4x4 _Matrices[24]; 23 | 24 | struct appdata 25 | { 26 | float4 vertex : POSITION; 27 | float2 uv : TEXCOORD0; 28 | float4 uv1 : TEXCOORD1; 29 | float4 uv2 : TEXCOORD2; 30 | }; 31 | 32 | struct v2f 33 | { 34 | float2 uv : TEXCOORD0; 35 | float4 vertex : SV_POSITION; 36 | }; 37 | 38 | sampler2D _MainTex; 39 | float4 _MainTex_ST; 40 | 41 | v2f vert (appdata v) 42 | { 43 | v2f o; 44 | float4 uv1 = v.uv1; 45 | float4 uv2 = v.uv2; 46 | 47 | float4 pos = 48 | mul(_Matrices[uv1.x], v.vertex) * uv1.y + 49 | mul(_Matrices[uv1.z], v.vertex) * uv1.w + 50 | mul(_Matrices[uv2.x], v.vertex) * uv2.y + 51 | mul(_Matrices[uv2.z], v.vertex) * uv2.w; 52 | 53 | o.vertex = UnityObjectToClipPos(pos); 54 | o.uv = TRANSFORM_TEX(v.uv, _MainTex); 55 | return o; 56 | } 57 | 58 | fixed4 frag (v2f i) : SV_Target 59 | { 60 | fixed4 col = tex2D(_MainTex, i.uv); 61 | return col; 62 | } 63 | ENDCG 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Assets/DynamicBone/Demo/tail.FBX.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 19015a5957bbaa745a61cba005220542 3 | ModelImporter: 4 | serializedVersion: 19 5 | fileIDToRecycleName: 6 | 100000: Bone01 7 | 100002: Bone02 8 | 100004: Bone03 9 | 100006: Bone04 10 | 100008: Bone05 11 | 100010: Bone06 12 | 100012: Bone07 13 | 100014: Bone08 14 | 100016: //RootNode 15 | 100018: tail 16 | 100020: tail1 17 | 100022: tail2 18 | 100024: tail3 19 | 100026: tail4 20 | 100028: tail5 21 | 100030: tail6 22 | 100032: tail7 23 | 100034: tail8 24 | 400000: Bone01 25 | 400002: Bone02 26 | 400004: Bone03 27 | 400006: Bone04 28 | 400008: Bone05 29 | 400010: Bone06 30 | 400012: Bone07 31 | 400014: Bone08 32 | 400016: //RootNode 33 | 400018: tail 34 | 400020: tail1 35 | 400022: tail2 36 | 400024: tail3 37 | 400026: tail4 38 | 400028: tail5 39 | 400030: tail6 40 | 400032: tail7 41 | 400034: tail8 42 | 2300000: tail 43 | 3300000: tail 44 | 4300000: tail 45 | 9500000: //RootNode 46 | 11100000: //RootNode 47 | 13700000: tail 48 | materials: 49 | importMaterials: 0 50 | materialName: 0 51 | materialSearch: 1 52 | animations: 53 | legacyGenerateAnimations: 4 54 | bakeSimulation: 0 55 | resampleCurves: 1 56 | optimizeGameObjects: 0 57 | motionNodeName: 58 | rigImportErrors: 59 | rigImportWarnings: 60 | animationImportErrors: 61 | animationImportWarnings: 62 | animationRetargetingWarnings: 63 | animationDoRetargetingWarnings: 0 64 | animationCompression: 1 65 | animationRotationError: 0.5 66 | animationPositionError: 0.5 67 | animationScaleError: 0.5 68 | animationWrapMode: 0 69 | extraExposedTransformPaths: [] 70 | clipAnimations: [] 71 | isReadable: 1 72 | meshes: 73 | lODScreenPercentages: [] 74 | globalScale: 0.01 75 | meshCompression: 0 76 | addColliders: 0 77 | importBlendShapes: 1 78 | swapUVChannels: 0 79 | generateSecondaryUV: 0 80 | useFileUnits: 1 81 | optimizeMeshForGPU: 1 82 | keepQuads: 0 83 | weldVertices: 1 84 | secondaryUVAngleDistortion: 8 85 | secondaryUVAreaDistortion: 15.000001 86 | secondaryUVHardAngle: 88 87 | secondaryUVPackMargin: 4 88 | useFileScale: 0 89 | tangentSpace: 90 | normalSmoothAngle: 60 91 | normalImportMode: 0 92 | tangentImportMode: 3 93 | importAnimation: 0 94 | copyAvatar: 0 95 | humanDescription: 96 | serializedVersion: 2 97 | human: [] 98 | skeleton: [] 99 | armTwist: 0.5 100 | foreArmTwist: 0.5 101 | upperLegTwist: 0.5 102 | legTwist: 0.5 103 | armStretch: 0.05 104 | legStretch: 0.05 105 | feetSpacing: 0 106 | rootMotionBoneName: 107 | rootMotionBoneRotation: {x: 0, y: 0, z: 0, w: 1} 108 | hasTranslationDoF: 0 109 | hasExtraRoot: 1 110 | skeletonHasParents: 0 111 | lastHumanDescriptionAvatarSource: {instanceID: 0} 112 | animationType: 1 113 | humanoidOversampling: 1 114 | additionalBone: 0 115 | userData: 116 | assetBundleName: 117 | assetBundleVariant: 118 | -------------------------------------------------------------------------------- /Assets/DynamicBone/ReadMe.txt: -------------------------------------------------------------------------------- 1 | Dynamic Bone apply physics to character's bones or joints. 2 | With simple setup, your character's hair, cloth, breasts or any part will move realistically. 3 | 4 | Open Assets/DynamicBone/Demo/Demo1 to see how it works. 5 | If you have any questions or suggestions, please contact willhongcom@gmail.com. 6 | 7 | 8 | ------------------------------------------------------------------------- 9 | Basic setup: 10 | 11 | 1. Prepare a properly setup character, both Mecanim and legacy rigs are supported. 12 | 2. Select the game object you want to apply Dynamic Bone. 13 | 3. In the component menu, select Dynamic Bone -> Dynamic Bone. 14 | 4. In the inspector, select root object. 15 | 5. Adjust dynamic bone parameters (see detail descriptions in the following section). 16 | 17 | 18 | You can add collider objects if required: 19 | 20 | 1. Select game object the collider will attached. 21 | 2. In the component menu, select Dynamic Bone -> Dynamic Bone Collider. 22 | 3. Adjust position and size of the collider. 23 | 4. In Dynamic Bone component, increase size of colliders and append corresponding object. 24 | 25 | 26 | ------------------------------------------------------------------------- 27 | Dynamic Bone Component Description: 28 | 29 | - Root 30 | The root of the transform hierarchy to apply physics. 31 | 32 | - Update Rate 33 | Internal physics simulation rate, measures in frames per seconds. 34 | 35 | - UpdateMode 36 | Normal: Normal update. 37 | AnimatePhysics: Updates during the physic loop in order to synchronized with the physics engine. 38 | UnscaledTime: Updates independently of Time.timeScale. 39 | 40 | - Damping 41 | How much the bones slowed down. 42 | 43 | - Elasticity 44 | How much the force applied to return each bone to original orientation. 45 | 46 | - Stiffness 47 | How much bone's original orientation are preserved. 48 | 49 | - Inert 50 | How much character's position change is ignored in physics simulation. 51 | 52 | - Radius 53 | Each bone can be a sphere to collide with colliders. Radius describe sphere's size. 54 | 55 | - Damping Distrib, Elasticity Distrib, Stiffness Distrib, Inert Distrib, Radius Distrib 56 | How parameters change over hierarchy chain. Curve values are multiplied to corresponding parameters. 57 | 58 | - End Length 59 | If End Length is not zero, an extra bone is generated at the end of transform hierarchy, 60 | length is multiplied by last two bone's distance. 61 | 62 | - End Offset 63 | If End Offset is not zero, an extra bone is generated at the end of transform hierarchy, 64 | offset is in character's local space. 65 | 66 | - Gravity 67 | The force apply to bones, in world space. Partial force apply to character's initial pose is cancelled out. 68 | 69 | - Force 70 | The force apply to bones, in world space. 71 | 72 | - Colliders 73 | Collider objects interact with the bones. Bones are never penetrate into colliders. 74 | 75 | - Exclusions 76 | Bones exclude from physics simulation. 77 | 78 | - Freeze Axis 79 | Constrain bones to move on specified plane. 80 | 81 | - Distant Disable, Reference Object, Distance To Object 82 | Disable physics simulation automatically if character is far from camera or player. 83 | If there is no reference object, default main camera is used. 84 | 85 | Dynamic Bone Collider Component Description: 86 | 87 | - Center 88 | The center of the sphere or capsule, in the object's local space. 89 | 90 | - Radius 91 | The radius of the sphere or capsule, will be scaled by the transform's scale. 92 | 93 | - Height 94 | The height of the capsule, including two half-spheres, will be scaled by the transform's scale. 95 | 96 | - Direction 97 | The axis of the capsule's height. 98 | 99 | - Bound 100 | Constrain bones to outside bound or inside bound. 101 | 102 | 103 | ------------------------------------------------------------------------- 104 | Version History 105 | 106 | 1.0.1 Initial release. 107 | 1.0.2 Improve inspector UI. 108 | 1.0.3 Fix inert unstable when enabled / disabled. 109 | 1.1.0 Use curve to setup parameters over hierarchy chain. 110 | Collider can configured to constrain bones inside bound. 111 | 1.1.1 Add exclusion setting. 112 | 1.1.2 Deal with negative scale problem. 113 | 1.1.3 Fix bug with bones contain scale. 114 | 1.1.4 Add freeze axis. 115 | Fix bug when added via script. 116 | 1.1.5 Add distant disable. 117 | Reduce GC alloc. 118 | 1.1.6 Fix capsule collider bug. 119 | 1.1.7 Unity 5 support. 120 | 1.1.8 Fix problems caused by negative scale. 121 | 1.1.9 Improve detecting negative scale. 122 | Fix bug if collider is set as inside. 123 | Add UpdateMode setting. 124 | 1.1.10 Fix problems caused by negative scale after Unity 5.4. -------------------------------------------------------------------------------- /Assets/DynamicBone/Scripts/DynamicBoneCollider.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | [AddComponentMenu("Dynamic Bone/Dynamic Bone Collider")] 4 | public class DynamicBoneCollider : MonoBehaviour 5 | { 6 | public Vector3 m_Center = Vector3.zero; 7 | public float m_Radius = 0.5f; 8 | public float m_Height = 0; 9 | 10 | public enum Direction 11 | { 12 | X, Y, Z 13 | } 14 | public Direction m_Direction = Direction.X; 15 | 16 | public enum Bound 17 | { 18 | Outside, 19 | Inside 20 | } 21 | public Bound m_Bound = Bound.Outside; 22 | 23 | void OnValidate() 24 | { 25 | m_Radius = Mathf.Max(m_Radius, 0); 26 | m_Height = Mathf.Max(m_Height, 0); 27 | } 28 | 29 | public void Collide(ref Vector3 particlePosition, float particleRadius) 30 | { 31 | float radius = m_Radius * Mathf.Abs(transform.lossyScale.x); 32 | float h = m_Height * 0.5f - m_Radius; 33 | if (h <= 0) 34 | { 35 | if (m_Bound == Bound.Outside) 36 | OutsideSphere(ref particlePosition, particleRadius, transform.TransformPoint(m_Center), radius); 37 | else 38 | InsideSphere(ref particlePosition, particleRadius, transform.TransformPoint(m_Center), radius); 39 | } 40 | else 41 | { 42 | Vector3 c0 = m_Center; 43 | Vector3 c1 = m_Center; 44 | 45 | switch (m_Direction) 46 | { 47 | case Direction.X: 48 | c0.x -= h; 49 | c1.x += h; 50 | break; 51 | case Direction.Y: 52 | c0.y -= h; 53 | c1.y += h; 54 | break; 55 | case Direction.Z: 56 | c0.z -= h; 57 | c1.z += h; 58 | break; 59 | } 60 | if (m_Bound == Bound.Outside) 61 | OutsideCapsule(ref particlePosition, particleRadius, transform.TransformPoint(c0), transform.TransformPoint(c1), radius); 62 | else 63 | InsideCapsule(ref particlePosition, particleRadius, transform.TransformPoint(c0), transform.TransformPoint(c1), radius); 64 | } 65 | } 66 | 67 | static void OutsideSphere(ref Vector3 particlePosition, float particleRadius, Vector3 sphereCenter, float sphereRadius) 68 | { 69 | float r = sphereRadius + particleRadius; 70 | float r2 = r * r; 71 | Vector3 d = particlePosition - sphereCenter; 72 | float len2 = d.sqrMagnitude; 73 | 74 | // if is inside sphere, project onto sphere surface 75 | if (len2 > 0 && len2 < r2) 76 | { 77 | float len = Mathf.Sqrt(len2); 78 | particlePosition = sphereCenter + d * (r / len); 79 | } 80 | } 81 | 82 | static void InsideSphere(ref Vector3 particlePosition, float particleRadius, Vector3 sphereCenter, float sphereRadius) 83 | { 84 | float r = sphereRadius - particleRadius; 85 | float r2 = r * r; 86 | Vector3 d = particlePosition - sphereCenter; 87 | float len2 = d.sqrMagnitude; 88 | 89 | // if is outside sphere, project onto sphere surface 90 | if (len2 > r2) 91 | { 92 | float len = Mathf.Sqrt(len2); 93 | particlePosition = sphereCenter + d * (r / len); 94 | } 95 | } 96 | 97 | static void OutsideCapsule(ref Vector3 particlePosition, float particleRadius, Vector3 capsuleP0, Vector3 capsuleP1, float capsuleRadius) 98 | { 99 | float r = capsuleRadius + particleRadius; 100 | float r2 = r * r; 101 | Vector3 dir = capsuleP1 - capsuleP0; 102 | Vector3 d = particlePosition - capsuleP0; 103 | float t = Vector3.Dot(d, dir); 104 | 105 | if (t <= 0) 106 | { 107 | // check sphere1 108 | float len2 = d.sqrMagnitude; 109 | if (len2 > 0 && len2 < r2) 110 | { 111 | float len = Mathf.Sqrt(len2); 112 | particlePosition = capsuleP0 + d * (r / len); 113 | } 114 | } 115 | else 116 | { 117 | float dl = dir.sqrMagnitude; 118 | if (t >= dl) 119 | { 120 | // check sphere2 121 | d = particlePosition - capsuleP1; 122 | float len2 = d.sqrMagnitude; 123 | if (len2 > 0 && len2 < r2) 124 | { 125 | float len = Mathf.Sqrt(len2); 126 | particlePosition = capsuleP1 + d * (r / len); 127 | } 128 | } 129 | else if (dl > 0) 130 | { 131 | // check cylinder 132 | t /= dl; 133 | d -= dir * t; 134 | float len2 = d.sqrMagnitude; 135 | if (len2 > 0 && len2 < r2) 136 | { 137 | float len = Mathf.Sqrt(len2); 138 | particlePosition += d * ((r - len) / len); 139 | } 140 | } 141 | } 142 | } 143 | 144 | static void InsideCapsule(ref Vector3 particlePosition, float particleRadius, Vector3 capsuleP0, Vector3 capsuleP1, float capsuleRadius) 145 | { 146 | float r = capsuleRadius - particleRadius; 147 | float r2 = r * r; 148 | Vector3 dir = capsuleP1 - capsuleP0; 149 | Vector3 d = particlePosition - capsuleP0; 150 | float t = Vector3.Dot(d, dir); 151 | 152 | if (t <= 0) 153 | { 154 | // check sphere1 155 | float len2 = d.sqrMagnitude; 156 | if (len2 > r2) 157 | { 158 | float len = Mathf.Sqrt(len2); 159 | particlePosition = capsuleP0 + d * (r / len); 160 | } 161 | } 162 | else 163 | { 164 | float dl = dir.sqrMagnitude; 165 | if (t >= dl) 166 | { 167 | // check sphere2 168 | d = particlePosition - capsuleP1; 169 | float len2 = d.sqrMagnitude; 170 | if (len2 > r2) 171 | { 172 | float len = Mathf.Sqrt(len2); 173 | particlePosition = capsuleP1 + d * (r / len); 174 | } 175 | } 176 | else if (dl > 0) 177 | { 178 | // check cylinder 179 | t /= dl; 180 | d -= dir * t; 181 | float len2 = d.sqrMagnitude; 182 | if (len2 > r2) 183 | { 184 | float len = Mathf.Sqrt(len2); 185 | particlePosition += d * ((r - len) / len); 186 | } 187 | } 188 | } 189 | } 190 | 191 | void OnDrawGizmosSelected() 192 | { 193 | if (!enabled) 194 | return; 195 | 196 | if (m_Bound == Bound.Outside) 197 | Gizmos.color = Color.yellow; 198 | else 199 | Gizmos.color = Color.magenta; 200 | float radius = m_Radius * Mathf.Abs(transform.lossyScale.x); 201 | float h = m_Height * 0.5f - m_Radius; 202 | if (h <= 0) 203 | { 204 | Gizmos.DrawWireSphere(transform.TransformPoint(m_Center), radius); 205 | } 206 | else 207 | { 208 | Vector3 c0 = m_Center; 209 | Vector3 c1 = m_Center; 210 | 211 | switch (m_Direction) 212 | { 213 | case Direction.X: 214 | c0.x -= h; 215 | c1.x += h; 216 | break; 217 | case Direction.Y: 218 | c0.y -= h; 219 | c1.y += h; 220 | break; 221 | case Direction.Z: 222 | c0.z -= h; 223 | c1.z += h; 224 | break; 225 | } 226 | Gizmos.DrawWireSphere(transform.TransformPoint(c0), radius); 227 | Gizmos.DrawWireSphere(transform.TransformPoint(c1), radius); 228 | } 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /Assets/DynamicBone/Scripts/GPUSkinning.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | #if UNITY_EDITOR 3 | using UnityEditor; 4 | #endif 5 | using System.Collections; 6 | using System.Collections.Generic; 7 | 8 | public class GPUSkinning : MonoBehaviour 9 | { 10 | public SkinnedMeshRenderer smr = null; 11 | 12 | private Mesh mesh = null; 13 | 14 | private GPUSkinning_Bone[] bones = null; 15 | 16 | private int rootBoneIndex = 0; 17 | 18 | private MeshFilter mf = null; 19 | 20 | private MeshRenderer mr = null; 21 | 22 | private Material newMtrl = null; 23 | 24 | private Mesh newMesh = null; 25 | 26 | private Matrix4x4[] matricesUniformBlock = null; 27 | 28 | private int shaderPropID_Matrices = 0; 29 | 30 | public Transform root = null; 31 | 32 | private void Start () 33 | { 34 | shaderPropID_Matrices = Shader.PropertyToID("_Matrices"); 35 | 36 | smr = GetComponentInChildren(); 37 | mesh = smr.sharedMesh; 38 | 39 | // Init Bones 40 | int numBones = smr.bones.Length; 41 | bones = new GPUSkinning_Bone[numBones]; 42 | for(int i = 0; i < numBones; ++i) 43 | { 44 | GPUSkinning_Bone bone = new GPUSkinning_Bone(); 45 | bones[i] = bone; 46 | bone.transform = smr.bones[i]; 47 | bone.bindpose = mesh.bindposes[i]/*smr to bone*/; 48 | } 49 | 50 | matricesUniformBlock = new Matrix4x4[numBones]; 51 | 52 | // Construct Bones' Hierarchy 53 | for(int i = 0; i < numBones; ++i) 54 | { 55 | if(bones[i].transform == smr.rootBone) 56 | { 57 | rootBoneIndex = i; 58 | break; 59 | } 60 | } 61 | System.Action CollectChildren = null; 62 | CollectChildren = (currentBone) => 63 | { 64 | List children = new List(); 65 | for (int j = 0; j < currentBone.transform.childCount; ++j) 66 | { 67 | Transform childTransform = currentBone.transform.GetChild(j); 68 | GPUSkinning_Bone childBone = GetBoneByTransform(childTransform); 69 | if (childBone != null) 70 | { 71 | childBone.parent = currentBone; 72 | children.Add(childBone); 73 | CollectChildren(childBone); 74 | } 75 | } 76 | currentBone.children = children.ToArray(); 77 | }; 78 | CollectChildren(bones[rootBoneIndex]); 79 | 80 | // New MeshFilter MeshRenderer 81 | mf = gameObject.AddComponent(); 82 | mr = gameObject.AddComponent(); 83 | 84 | newMtrl = new Material(Shader.Find("Unlit/GPUSkinning")); 85 | newMtrl.CopyPropertiesFromMaterial(smr.sharedMaterial); 86 | mr.sharedMaterial = newMtrl; 87 | 88 | // Fetch bone-weight storing as tangents 89 | int numVertices = mesh.vertexCount; 90 | Vector4[] tangents = new Vector4[mesh.vertexCount]; 91 | Vector4[] uv2 = new Vector4[numVertices]; 92 | Vector4[] uv3 = new Vector4[numVertices]; 93 | 94 | for (int i = 0; i < numVertices; ++i) 95 | { 96 | BoneWeight boneWeight = mesh.boneWeights[i]; 97 | tangents[i].x = boneWeight.boneIndex0; 98 | tangents[i].y = boneWeight.weight0; 99 | tangents[i].z = boneWeight.boneIndex1; 100 | tangents[i].w = boneWeight.weight1; 101 | 102 | 103 | Vector4 skinData_01 = new Vector4(); 104 | skinData_01.x = boneWeight.boneIndex0; 105 | skinData_01.y = boneWeight.weight0; 106 | skinData_01.z = boneWeight.boneIndex1; 107 | skinData_01.w = boneWeight.weight1; 108 | uv2[i] = skinData_01; 109 | 110 | Vector4 skinData_23 = new Vector4(); 111 | skinData_23.x = boneWeight.boneIndex2; 112 | skinData_23.y = boneWeight.weight2; 113 | skinData_23.z = boneWeight.boneIndex3; 114 | skinData_23.w = boneWeight.weight3; 115 | uv3[i] = skinData_23; 116 | 117 | } 118 | 119 | // New Mesh 120 | newMesh = new Mesh(); 121 | newMesh.vertices = mesh.vertices; 122 | newMesh.normals = mesh.normals; 123 | newMesh.tangents = tangents; 124 | newMesh.uv = mesh.uv; 125 | newMesh.triangles = mesh.triangles; 126 | mf.sharedMesh = newMesh; 127 | 128 | newMesh.SetUVs(1, new List(uv2)); 129 | newMesh.SetUVs(2, new List(uv3)); 130 | 131 | /* 132 | // Fetch animations' data 133 | #if UNITY_EDITOR 134 | int boneAnimationsCount = 0; 135 | boneAnimations = new GPUSkinning_BoneAnimation[GetComponent().runtimeAnimatorController.animationClips.Length]; 136 | foreach(AnimationClip animClip in GetComponent().runtimeAnimatorController.animationClips) 137 | { 138 | GPUSkinning_BoneAnimation boneAnimation = ScriptableObject.CreateInstance(); 139 | boneAnimation.fps = 30; 140 | boneAnimation.animName = animClip.name; 141 | boneAnimation.frames = new GPUSkinning_BoneAnimationFrame[(int)(animClip.length * boneAnimation.fps)]; 142 | boneAnimation.length = animClip.length; 143 | boneAnimations[boneAnimationsCount++] = boneAnimation; 144 | 145 | for(int frameIndex = 0; frameIndex < boneAnimation.frames.Length; ++frameIndex) 146 | { 147 | GPUSkinning_BoneAnimationFrame frame = new GPUSkinning_BoneAnimationFrame(); 148 | boneAnimation.frames[frameIndex] = frame; 149 | float second = (float)(frameIndex) / (float)boneAnimation.fps; 150 | 151 | List bones2 = new List(); 152 | List matrices = new List(); 153 | List bonesHierarchyNames = new List(); 154 | EditorCurveBinding[] curvesBinding = AnimationUtility.GetCurveBindings(animClip); 155 | foreach(var curveBinding in curvesBinding) 156 | { 157 | GPUSkinning_Bone bone = GetBoneByHierarchyName(curveBinding.path); 158 | 159 | if(bones2.Contains(bone)) 160 | { 161 | continue; 162 | } 163 | bones2.Add(bone); 164 | 165 | bonesHierarchyNames.Add(GetBoneHierarchyName(bone)); 166 | 167 | AnimationCurve curveRX = AnimationUtility.GetEditorCurve(animClip, curveBinding.path, curveBinding.type, "m_LocalRotation.x"); 168 | AnimationCurve curveRY = AnimationUtility.GetEditorCurve(animClip, curveBinding.path, curveBinding.type, "m_LocalRotation.y"); 169 | AnimationCurve curveRZ = AnimationUtility.GetEditorCurve(animClip, curveBinding.path, curveBinding.type, "m_LocalRotation.z"); 170 | AnimationCurve curveRW = AnimationUtility.GetEditorCurve(animClip, curveBinding.path, curveBinding.type, "m_LocalRotation.w"); 171 | 172 | AnimationCurve curvePX = AnimationUtility.GetEditorCurve(animClip, curveBinding.path, curveBinding.type, "m_LocalPosition.x"); 173 | AnimationCurve curvePY = AnimationUtility.GetEditorCurve(animClip, curveBinding.path, curveBinding.type, "m_LocalPosition.y"); 174 | AnimationCurve curvePZ = AnimationUtility.GetEditorCurve(animClip, curveBinding.path, curveBinding.type, "m_LocalPosition.z"); 175 | 176 | float curveRX_v = curveRX.Evaluate(second); 177 | float curveRY_v = curveRY.Evaluate(second); 178 | float curveRZ_v = curveRZ.Evaluate(second); 179 | float curveRW_v = curveRW.Evaluate(second); 180 | 181 | float curvePX_v = curvePX.Evaluate(second); 182 | float curvePY_v = curvePY.Evaluate(second); 183 | float curvePZ_v = curvePZ.Evaluate(second); 184 | 185 | Vector3 translation = new Vector3(curvePX_v, curvePY_v, curvePZ_v); 186 | Quaternion rotation = new Quaternion(curveRX_v, curveRY_v, curveRZ_v, curveRW_v); 187 | NormalizeQuaternion(ref rotation); 188 | matrices.Add( 189 | Matrix4x4.TRS(translation, rotation, Vector3.one) 190 | ); 191 | } 192 | 193 | frame.bones = bones2.ToArray(); 194 | frame.matrices = matrices.ToArray(); 195 | frame.bonesHierarchyNames = bonesHierarchyNames.ToArray(); 196 | } 197 | } 198 | AssetDatabase.CreateAsset(boneAnimations[0], "Assets/GPUSkinning/Resources/anim0.asset"); 199 | AssetDatabase.Refresh(); 200 | #else 201 | boneAnimations = new GPUSkinning_BoneAnimation[] { Resources.Load("anim0") as GPUSkinning_BoneAnimation }; 202 | foreach(var boneAnimation in boneAnimations) 203 | { 204 | foreach(var frame in boneAnimation.frames) 205 | { 206 | int numBones2 = frame.bonesHierarchyNames.Length; 207 | frame.bones = new GPUSkinning_Bone[numBones2]; 208 | for(int i = 0; i < numBones2; ++i) 209 | { 210 | frame.bones[i] = GetBoneByHierarchyName(frame.bonesHierarchyNames[i]); 211 | } 212 | } 213 | } 214 | #endif 215 | 216 | 217 | GameObject.Destroy(transform.Find("pelvis").gameObject); 218 | GameObject.Destroy(transform.Find("mutant_mesh").gameObject); 219 | Object.Destroy(gameObject.GetComponent()); 220 | */ 221 | //smr.enabled = false; 222 | 223 | //PrintBones(); 224 | } 225 | 226 | 227 | private float second = 0.0f; 228 | private void Update() 229 | { 230 | //UpdateBoneAnimationMatrix(null, second); 231 | Play(); 232 | //second += Time.deltaTime; 233 | } 234 | 235 | 236 | public void UpdateBones(List particles) 237 | { 238 | Matrix4x4 rootMatrix = Matrix4x4.TRS(gameObject.transform.position, gameObject.transform.rotation, Vector3.one); 239 | 240 | for (int i = 0; i < particles.Count; ++i) 241 | { 242 | Quaternion rotation = particles[i].m_Transform.rotation; 243 | NormalizeQuaternion(ref rotation); 244 | matricesUniformBlock[i] = rootMatrix.inverse * Matrix4x4.TRS(particles[i].m_Transform.position, rotation, Vector3.one) * bones[i].bindpose; 245 | } 246 | } 247 | 248 | public void Play() 249 | { 250 | /* 251 | for (int i = 0; i < bones.Length; ++i) 252 | { 253 | 254 | Matrix4x4 rootMatrix = Matrix4x4.TRS(gameObject.transform.position, gameObject.transform.rotation, Vector3.one); 255 | 256 | matricesUniformBlock[i] = Matrix4x4.TRS(bones[i].transform.position, bones[i].transform.rotation, Vector3.one)* bones[i].bindpose * rootMatrix.inverse; 257 | } 258 | */ 259 | 260 | newMtrl.SetMatrixArray(shaderPropID_Matrices, matricesUniformBlock); 261 | } 262 | 263 | private void OnDestroy() 264 | { 265 | if(newMtrl != null) 266 | { 267 | Object.Destroy(newMtrl); 268 | } 269 | if(newMesh != null) 270 | { 271 | Object.Destroy(newMesh); 272 | } 273 | } 274 | 275 | private GPUSkinning_Bone GetBoneByTransform(Transform transform) 276 | { 277 | foreach(GPUSkinning_Bone bone in bones) 278 | { 279 | if(bone.transform == transform) 280 | { 281 | return bone; 282 | } 283 | } 284 | return null; 285 | } 286 | 287 | private GPUSkinning_Bone GetBoneByHierarchyName(string hierarchyName) 288 | { 289 | System.Func Search = null; 290 | Search = (bone, name) => 291 | { 292 | if(name == hierarchyName) 293 | { 294 | return bone; 295 | } 296 | foreach(GPUSkinning_Bone child in bone.children) 297 | { 298 | GPUSkinning_Bone result = Search(child, name + "/" + child.name); 299 | if(result != null) 300 | { 301 | return result; 302 | } 303 | } 304 | return null; 305 | }; 306 | 307 | return Search(bones[rootBoneIndex], bones[rootBoneIndex].name); 308 | } 309 | 310 | private string GetBoneHierarchyName(GPUSkinning_Bone bone) 311 | { 312 | string str = string.Empty; 313 | 314 | GPUSkinning_Bone currentBone = bone; 315 | while(currentBone != null) 316 | { 317 | if(str == string.Empty) 318 | { 319 | str = currentBone.name; 320 | } 321 | else 322 | { 323 | str = currentBone.name + "/" + str; 324 | } 325 | 326 | currentBone = currentBone.parent; 327 | } 328 | 329 | return str; 330 | } 331 | 332 | private void PrintBones() 333 | { 334 | string text = string.Empty; 335 | 336 | System.Action PrintBone = null; 337 | PrintBone = (bone, prefix) => 338 | { 339 | text += prefix + bone.transform.gameObject.name + "\n"; 340 | prefix += " "; 341 | foreach(var childBone in bone.children) 342 | { 343 | PrintBone(childBone, prefix); 344 | } 345 | }; 346 | 347 | PrintBone(bones[rootBoneIndex], string.Empty); 348 | 349 | Debug.LogError(text); 350 | } 351 | 352 | private void NormalizeQuaternion (ref Quaternion q) 353 | { 354 | float sum = 0; 355 | for (int i = 0; i < 4; ++i) 356 | sum += q[i] * q[i]; 357 | float magnitudeInverse = 1 / Mathf.Sqrt(sum); 358 | for (int i = 0; i < 4; ++i) 359 | q[i] *= magnitudeInverse; 360 | } 361 | } 362 | -------------------------------------------------------------------------------- /Assets/DynamicBone/Demo/c1.fbx.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ba128457d0ea5e3439dbe4a53b9d1273 3 | ModelImporter: 4 | serializedVersion: 19 5 | fileIDToRecycleName: 6 | 100000: abdomen 7 | 100002: abdomen2 8 | 100004: //RootNode 9 | 100006: chest 10 | 100008: Genesis2Female 11 | 100010: Genesis2Female.Shape 12 | 100012: head 13 | 100014: hip 14 | 100016: lBigToe 15 | 100018: lCarpal1 16 | 100020: lCarpal2 17 | 100022: lCollar 18 | 100024: lEye 19 | 100026: lFoot 20 | 100028: lForeArm 21 | 100030: lHand 22 | 100032: lIndex1 23 | 100034: lIndex2 24 | 100036: lIndex3 25 | 100038: lMid1 26 | 100040: lMid2 27 | 100042: lMid3 28 | 100044: lowerJaw 29 | 100046: lPectoral 30 | 100048: lPinky1 31 | 100050: lPinky2 32 | 100052: lPinky3 33 | 100054: lRing1 34 | 100056: lRing2 35 | 100058: lRing3 36 | 100060: lShin 37 | 100062: lShldr 38 | 100064: lSmallToe1 39 | 100066: lSmallToe2 40 | 100068: lSmallToe3 41 | 100070: lSmallToe4 42 | 100072: lThigh 43 | 100074: lThumb1 44 | 100076: lThumb2 45 | 100078: lThumb3 46 | 100080: lToe 47 | 100082: neck 48 | 100084: pelvis 49 | 100086: rBigToe 50 | 100088: rCarpal1 51 | 100090: rCarpal2 52 | 100092: rCollar 53 | 100094: rEye 54 | 100096: rFoot 55 | 100098: rForeArm 56 | 100100: rHand 57 | 100102: rIndex1 58 | 100104: rIndex2 59 | 100106: rIndex3 60 | 100108: rMid1 61 | 100110: rMid2 62 | 100112: rMid3 63 | 100114: rPectoral 64 | 100116: rPinky1 65 | 100118: rPinky2 66 | 100120: rPinky3 67 | 100122: rRing1 68 | 100124: rRing2 69 | 100126: rRing3 70 | 100128: rShin 71 | 100130: rShldr 72 | 100132: rSmallToe1 73 | 100134: rSmallToe2 74 | 100136: rSmallToe3 75 | 100138: rSmallToe4 76 | 100140: rThigh 77 | 100142: rThumb1 78 | 100144: rThumb2 79 | 100146: rThumb3 80 | 100148: rToe 81 | 100150: tongue01 82 | 100152: tongue02 83 | 100154: tongue03 84 | 100156: tongue04 85 | 100158: tongue05 86 | 100160: tongueBase 87 | 100162: tongueTip 88 | 100164: upperJaw 89 | 400000: abdomen 90 | 400002: abdomen2 91 | 400004: //RootNode 92 | 400006: chest 93 | 400008: Genesis2Female 94 | 400010: Genesis2Female.Shape 95 | 400012: head 96 | 400014: hip 97 | 400016: lBigToe 98 | 400018: lCarpal1 99 | 400020: lCarpal2 100 | 400022: lCollar 101 | 400024: lEye 102 | 400026: lFoot 103 | 400028: lForeArm 104 | 400030: lHand 105 | 400032: lIndex1 106 | 400034: lIndex2 107 | 400036: lIndex3 108 | 400038: lMid1 109 | 400040: lMid2 110 | 400042: lMid3 111 | 400044: lowerJaw 112 | 400046: lPectoral 113 | 400048: lPinky1 114 | 400050: lPinky2 115 | 400052: lPinky3 116 | 400054: lRing1 117 | 400056: lRing2 118 | 400058: lRing3 119 | 400060: lShin 120 | 400062: lShldr 121 | 400064: lSmallToe1 122 | 400066: lSmallToe2 123 | 400068: lSmallToe3 124 | 400070: lSmallToe4 125 | 400072: lThigh 126 | 400074: lThumb1 127 | 400076: lThumb2 128 | 400078: lThumb3 129 | 400080: lToe 130 | 400082: neck 131 | 400084: pelvis 132 | 400086: rBigToe 133 | 400088: rCarpal1 134 | 400090: rCarpal2 135 | 400092: rCollar 136 | 400094: rEye 137 | 400096: rFoot 138 | 400098: rForeArm 139 | 400100: rHand 140 | 400102: rIndex1 141 | 400104: rIndex2 142 | 400106: rIndex3 143 | 400108: rMid1 144 | 400110: rMid2 145 | 400112: rMid3 146 | 400114: rPectoral 147 | 400116: rPinky1 148 | 400118: rPinky2 149 | 400120: rPinky3 150 | 400122: rRing1 151 | 400124: rRing2 152 | 400126: rRing3 153 | 400128: rShin 154 | 400130: rShldr 155 | 400132: rSmallToe1 156 | 400134: rSmallToe2 157 | 400136: rSmallToe3 158 | 400138: rSmallToe4 159 | 400140: rThigh 160 | 400142: rThumb1 161 | 400144: rThumb2 162 | 400146: rThumb3 163 | 400148: rToe 164 | 400150: tongue01 165 | 400152: tongue02 166 | 400154: tongue03 167 | 400156: tongue04 168 | 400158: tongue05 169 | 400160: tongueBase 170 | 400162: tongueTip 171 | 400164: upperJaw 172 | 4300000: Genesis2Female.Shape 173 | 7400000: Animation 174 | 9500000: //RootNode 175 | 11100000: //RootNode 176 | 13700000: Genesis2Female.Shape 177 | materials: 178 | importMaterials: 0 179 | materialName: 0 180 | materialSearch: 1 181 | animations: 182 | legacyGenerateAnimations: 4 183 | bakeSimulation: 0 184 | resampleCurves: 1 185 | optimizeGameObjects: 0 186 | motionNodeName: 187 | rigImportErrors: 188 | rigImportWarnings: 189 | animationImportErrors: 190 | animationImportWarnings: 191 | animationRetargetingWarnings: 192 | animationDoRetargetingWarnings: 0 193 | animationCompression: 1 194 | animationRotationError: 0.5 195 | animationPositionError: 0.5 196 | animationScaleError: 0.5 197 | animationWrapMode: 0 198 | extraExposedTransformPaths: [] 199 | clipAnimations: 200 | - serializedVersion: 16 201 | name: Animation 202 | takeName: Animation 203 | firstFrame: 0 204 | lastFrame: 206 205 | wrapMode: 2 206 | orientationOffsetY: 0 207 | level: 0 208 | cycleOffset: 0 209 | loop: 0 210 | hasAdditiveReferencePose: 0 211 | loopTime: 0 212 | loopBlend: 0 213 | loopBlendOrientation: 0 214 | loopBlendPositionY: 0 215 | loopBlendPositionXZ: 0 216 | keepOriginalOrientation: 0 217 | keepOriginalPositionY: 1 218 | keepOriginalPositionXZ: 0 219 | heightFromFeet: 0 220 | mirror: 0 221 | bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000 222 | curves: [] 223 | events: [] 224 | transformMask: 225 | - path: 226 | weight: 1 227 | - path: Genesis2Female 228 | weight: 1 229 | - path: Genesis2Female/Genesis2Female.Shape 230 | weight: 1 231 | - path: Genesis2Female/hip 232 | weight: 1 233 | - path: Genesis2Female/hip/abdomen 234 | weight: 1 235 | - path: Genesis2Female/hip/abdomen/abdomen2 236 | weight: 1 237 | - path: Genesis2Female/hip/abdomen/abdomen2/chest 238 | weight: 1 239 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/lCollar 240 | weight: 1 241 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/lCollar/lShldr 242 | weight: 1 243 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/lCollar/lShldr/lForeArm 244 | weight: 1 245 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/lCollar/lShldr/lForeArm/lHand 246 | weight: 1 247 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/lCollar/lShldr/lForeArm/lHand/lCarpal1 248 | weight: 1 249 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/lCollar/lShldr/lForeArm/lHand/lCarpal1/lIndex1 250 | weight: 1 251 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/lCollar/lShldr/lForeArm/lHand/lCarpal1/lIndex1/lIndex2 252 | weight: 1 253 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/lCollar/lShldr/lForeArm/lHand/lCarpal1/lIndex1/lIndex2/lIndex3 254 | weight: 1 255 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/lCollar/lShldr/lForeArm/lHand/lCarpal1/lMid1 256 | weight: 1 257 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/lCollar/lShldr/lForeArm/lHand/lCarpal1/lMid1/lMid2 258 | weight: 1 259 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/lCollar/lShldr/lForeArm/lHand/lCarpal1/lMid1/lMid2/lMid3 260 | weight: 1 261 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/lCollar/lShldr/lForeArm/lHand/lCarpal2 262 | weight: 1 263 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/lCollar/lShldr/lForeArm/lHand/lCarpal2/lPinky1 264 | weight: 1 265 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/lCollar/lShldr/lForeArm/lHand/lCarpal2/lPinky1/lPinky2 266 | weight: 1 267 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/lCollar/lShldr/lForeArm/lHand/lCarpal2/lPinky1/lPinky2/lPinky3 268 | weight: 1 269 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/lCollar/lShldr/lForeArm/lHand/lCarpal2/lRing1 270 | weight: 1 271 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/lCollar/lShldr/lForeArm/lHand/lCarpal2/lRing1/lRing2 272 | weight: 1 273 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/lCollar/lShldr/lForeArm/lHand/lCarpal2/lRing1/lRing2/lRing3 274 | weight: 1 275 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/lCollar/lShldr/lForeArm/lHand/lThumb1 276 | weight: 1 277 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/lCollar/lShldr/lForeArm/lHand/lThumb1/lThumb2 278 | weight: 1 279 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/lCollar/lShldr/lForeArm/lHand/lThumb1/lThumb2/lThumb3 280 | weight: 1 281 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/lPectoral 282 | weight: 1 283 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/neck 284 | weight: 1 285 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/neck/head 286 | weight: 1 287 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/neck/head/lEye 288 | weight: 1 289 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/neck/head/lowerJaw 290 | weight: 1 291 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/neck/head/lowerJaw/tongueBase 292 | weight: 1 293 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/neck/head/lowerJaw/tongueBase/tongue01 294 | weight: 1 295 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/neck/head/lowerJaw/tongueBase/tongue01/tongue02 296 | weight: 1 297 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/neck/head/lowerJaw/tongueBase/tongue01/tongue02/tongue03 298 | weight: 1 299 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/neck/head/lowerJaw/tongueBase/tongue01/tongue02/tongue03/tongue04 300 | weight: 1 301 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/neck/head/lowerJaw/tongueBase/tongue01/tongue02/tongue03/tongue04/tongue05 302 | weight: 1 303 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/neck/head/lowerJaw/tongueBase/tongue01/tongue02/tongue03/tongue04/tongue05/tongueTip 304 | weight: 1 305 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/neck/head/rEye 306 | weight: 1 307 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/neck/head/upperJaw 308 | weight: 1 309 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/rCollar 310 | weight: 1 311 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/rCollar/rShldr 312 | weight: 1 313 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/rCollar/rShldr/rForeArm 314 | weight: 1 315 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/rCollar/rShldr/rForeArm/rHand 316 | weight: 1 317 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/rCollar/rShldr/rForeArm/rHand/rCarpal1 318 | weight: 1 319 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/rCollar/rShldr/rForeArm/rHand/rCarpal1/rIndex1 320 | weight: 1 321 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/rCollar/rShldr/rForeArm/rHand/rCarpal1/rIndex1/rIndex2 322 | weight: 1 323 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/rCollar/rShldr/rForeArm/rHand/rCarpal1/rIndex1/rIndex2/rIndex3 324 | weight: 1 325 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/rCollar/rShldr/rForeArm/rHand/rCarpal1/rMid1 326 | weight: 1 327 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/rCollar/rShldr/rForeArm/rHand/rCarpal1/rMid1/rMid2 328 | weight: 1 329 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/rCollar/rShldr/rForeArm/rHand/rCarpal1/rMid1/rMid2/rMid3 330 | weight: 1 331 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/rCollar/rShldr/rForeArm/rHand/rCarpal2 332 | weight: 1 333 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/rCollar/rShldr/rForeArm/rHand/rCarpal2/rPinky1 334 | weight: 1 335 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/rCollar/rShldr/rForeArm/rHand/rCarpal2/rPinky1/rPinky2 336 | weight: 1 337 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/rCollar/rShldr/rForeArm/rHand/rCarpal2/rPinky1/rPinky2/rPinky3 338 | weight: 1 339 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/rCollar/rShldr/rForeArm/rHand/rCarpal2/rRing1 340 | weight: 1 341 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/rCollar/rShldr/rForeArm/rHand/rCarpal2/rRing1/rRing2 342 | weight: 1 343 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/rCollar/rShldr/rForeArm/rHand/rCarpal2/rRing1/rRing2/rRing3 344 | weight: 1 345 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/rCollar/rShldr/rForeArm/rHand/rThumb1 346 | weight: 1 347 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/rCollar/rShldr/rForeArm/rHand/rThumb1/rThumb2 348 | weight: 1 349 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/rCollar/rShldr/rForeArm/rHand/rThumb1/rThumb2/rThumb3 350 | weight: 1 351 | - path: Genesis2Female/hip/abdomen/abdomen2/chest/rPectoral 352 | weight: 1 353 | - path: Genesis2Female/hip/pelvis 354 | weight: 1 355 | - path: Genesis2Female/hip/pelvis/lThigh 356 | weight: 1 357 | - path: Genesis2Female/hip/pelvis/lThigh/lShin 358 | weight: 1 359 | - path: Genesis2Female/hip/pelvis/lThigh/lShin/lFoot 360 | weight: 1 361 | - path: Genesis2Female/hip/pelvis/lThigh/lShin/lFoot/lToe 362 | weight: 1 363 | - path: Genesis2Female/hip/pelvis/lThigh/lShin/lFoot/lToe/lBigToe 364 | weight: 1 365 | - path: Genesis2Female/hip/pelvis/lThigh/lShin/lFoot/lToe/lSmallToe1 366 | weight: 1 367 | - path: Genesis2Female/hip/pelvis/lThigh/lShin/lFoot/lToe/lSmallToe2 368 | weight: 1 369 | - path: Genesis2Female/hip/pelvis/lThigh/lShin/lFoot/lToe/lSmallToe3 370 | weight: 1 371 | - path: Genesis2Female/hip/pelvis/lThigh/lShin/lFoot/lToe/lSmallToe4 372 | weight: 1 373 | - path: Genesis2Female/hip/pelvis/rThigh 374 | weight: 1 375 | - path: Genesis2Female/hip/pelvis/rThigh/rShin 376 | weight: 1 377 | - path: Genesis2Female/hip/pelvis/rThigh/rShin/rFoot 378 | weight: 1 379 | - path: Genesis2Female/hip/pelvis/rThigh/rShin/rFoot/rToe 380 | weight: 1 381 | - path: Genesis2Female/hip/pelvis/rThigh/rShin/rFoot/rToe/rBigToe 382 | weight: 1 383 | - path: Genesis2Female/hip/pelvis/rThigh/rShin/rFoot/rToe/rSmallToe1 384 | weight: 1 385 | - path: Genesis2Female/hip/pelvis/rThigh/rShin/rFoot/rToe/rSmallToe2 386 | weight: 1 387 | - path: Genesis2Female/hip/pelvis/rThigh/rShin/rFoot/rToe/rSmallToe3 388 | weight: 1 389 | - path: Genesis2Female/hip/pelvis/rThigh/rShin/rFoot/rToe/rSmallToe4 390 | weight: 1 391 | maskType: 0 392 | maskSource: {instanceID: 0} 393 | additiveReferencePoseFrame: 0 394 | isReadable: 0 395 | meshes: 396 | lODScreenPercentages: [] 397 | globalScale: 0.01 398 | meshCompression: 0 399 | addColliders: 0 400 | importBlendShapes: 0 401 | swapUVChannels: 0 402 | generateSecondaryUV: 0 403 | useFileUnits: 1 404 | optimizeMeshForGPU: 1 405 | keepQuads: 0 406 | weldVertices: 1 407 | secondaryUVAngleDistortion: 8 408 | secondaryUVAreaDistortion: 15.000001 409 | secondaryUVHardAngle: 88 410 | secondaryUVPackMargin: 4 411 | useFileScale: 0 412 | tangentSpace: 413 | normalSmoothAngle: 60 414 | normalImportMode: 0 415 | tangentImportMode: 2 416 | importAnimation: 1 417 | copyAvatar: 0 418 | humanDescription: 419 | serializedVersion: 2 420 | human: [] 421 | skeleton: [] 422 | armTwist: 0.5 423 | foreArmTwist: 0.5 424 | upperLegTwist: 0.5 425 | legTwist: 0.5 426 | armStretch: 0.05 427 | legStretch: 0.05 428 | feetSpacing: 0 429 | rootMotionBoneName: 430 | rootMotionBoneRotation: {x: 0, y: 0, z: 0, w: 1} 431 | hasTranslationDoF: 0 432 | hasExtraRoot: 1 433 | skeletonHasParents: 0 434 | lastHumanDescriptionAvatarSource: {instanceID: 0} 435 | animationType: 1 436 | humanoidOversampling: 1 437 | additionalBone: 0 438 | userData: 439 | assetBundleName: 440 | assetBundleVariant: 441 | -------------------------------------------------------------------------------- /Assets/DynamicBone/Scripts/DynamicBone.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections.Generic; 3 | 4 | [AddComponentMenu("Dynamic Bone/Dynamic Bone")] 5 | public class DynamicBone : MonoBehaviour 6 | { 7 | public Transform m_Root = null; 8 | public float m_UpdateRate = 60.0f; 9 | public enum UpdateMode 10 | { 11 | Normal, 12 | AnimatePhysics, 13 | UnscaledTime 14 | } 15 | public UpdateMode m_UpdateMode = UpdateMode.Normal; 16 | [Range(0, 1)] 17 | public float m_Damping = 0.1f; 18 | public AnimationCurve m_DampingDistrib = null; 19 | [Range(0, 1)] 20 | public float m_Elasticity = 0.1f; 21 | public AnimationCurve m_ElasticityDistrib = null; 22 | [Range(0, 1)] 23 | public float m_Stiffness = 0.1f; 24 | public AnimationCurve m_StiffnessDistrib = null; 25 | [Range(0, 1)] 26 | public float m_Inert = 0; 27 | public AnimationCurve m_InertDistrib = null; 28 | public float m_Radius = 0; 29 | public AnimationCurve m_RadiusDistrib = null; 30 | 31 | public float m_EndLength = 0; 32 | public Vector3 m_EndOffset = Vector3.zero; 33 | public Vector3 m_Gravity = Vector3.zero; 34 | public Vector3 m_Force = Vector3.zero; 35 | public List m_Colliders = null; 36 | public List m_Exclusions = null; 37 | public enum FreezeAxis 38 | { 39 | None, X, Y, Z 40 | } 41 | public FreezeAxis m_FreezeAxis = FreezeAxis.None; 42 | public bool m_DistantDisable = false; 43 | public Transform m_ReferenceObject = null; 44 | public float m_DistanceToObject = 20; 45 | 46 | Vector3 m_LocalGravity = Vector3.zero; 47 | Vector3 m_ObjectMove = Vector3.zero; 48 | Vector3 m_ObjectPrevPosition = Vector3.zero; 49 | float m_BoneTotalLength = 0; 50 | float m_ObjectScale = 1.0f; 51 | float m_Time = 0; 52 | float m_Weight = 1.0f; 53 | bool m_DistantDisabled = false; 54 | 55 | public bool m_GPUSkinning = false; 56 | GPUSkinning gpuSkinning = null; 57 | 58 | public class Particle 59 | { 60 | public string m_Name = ""; 61 | public Transform m_Transform = null; 62 | public int m_ParentIndex = -1; 63 | public float m_Damping = 0; 64 | public float m_Elasticity = 0; 65 | public float m_Stiffness = 0; 66 | public float m_Inert = 0; 67 | public float m_Radius = 0; 68 | public float m_BoneLength = 0; 69 | 70 | public Vector3 m_Position = Vector3.zero; 71 | public Vector3 m_PrevPosition = Vector3.zero; 72 | public Vector3 m_EndOffset = Vector3.zero; 73 | public Vector3 m_InitLocalPosition = Vector3.zero; 74 | public Quaternion m_InitLocalRotation = Quaternion.identity; 75 | } 76 | 77 | public List m_Particles = new List(); 78 | 79 | void Start() 80 | { 81 | SetupParticles(); 82 | 83 | if (m_GPUSkinning) 84 | { 85 | gpuSkinning = gameObject.AddComponent(); 86 | gpuSkinning.root = m_Root; 87 | } 88 | } 89 | 90 | void FixedUpdate() 91 | { 92 | if (m_UpdateMode == UpdateMode.AnimatePhysics) 93 | PreUpdate(); 94 | } 95 | 96 | void Update() 97 | { 98 | if (m_UpdateMode != UpdateMode.AnimatePhysics) 99 | PreUpdate(); 100 | } 101 | 102 | void LateUpdate() 103 | { 104 | 105 | if (m_DistantDisable) 106 | CheckDistance(); 107 | 108 | if (m_Weight > 0 && !(m_DistantDisable && m_DistantDisabled)) 109 | { 110 | #if UNITY_5 111 | float dt = m_UpdateMode == UpdateMode.UnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime; 112 | #else 113 | float dt = Time.deltaTime; 114 | #endif 115 | UpdateDynamicBones(dt); 116 | } 117 | 118 | 119 | if (m_GPUSkinning) 120 | { 121 | gpuSkinning.UpdateBones(m_Particles); 122 | gpuSkinning.Play(); 123 | } 124 | } 125 | 126 | void PreUpdate() 127 | { 128 | if (m_Weight > 0 && !(m_DistantDisable && m_DistantDisabled)) 129 | InitTransforms(); 130 | } 131 | 132 | void CheckDistance() 133 | { 134 | Transform rt = m_ReferenceObject; 135 | if (rt == null && Camera.main != null) 136 | rt = Camera.main.transform; 137 | if (rt != null) 138 | { 139 | float d = (rt.position - transform.position).sqrMagnitude; 140 | bool disable = d > m_DistanceToObject * m_DistanceToObject; 141 | if (disable != m_DistantDisabled) 142 | { 143 | if (!disable) 144 | ResetParticlesPosition(); 145 | m_DistantDisabled = disable; 146 | } 147 | } 148 | } 149 | 150 | void OnEnable() 151 | { 152 | ResetParticlesPosition(); 153 | } 154 | 155 | void OnDisable() 156 | { 157 | InitTransforms(); 158 | } 159 | 160 | void OnValidate() 161 | { 162 | m_UpdateRate = Mathf.Max(m_UpdateRate, 0); 163 | m_Damping = Mathf.Clamp01(m_Damping); 164 | m_Elasticity = Mathf.Clamp01(m_Elasticity); 165 | m_Stiffness = Mathf.Clamp01(m_Stiffness); 166 | m_Inert = Mathf.Clamp01(m_Inert); 167 | m_Radius = Mathf.Max(m_Radius, 0); 168 | 169 | if (Application.isEditor && Application.isPlaying) 170 | { 171 | InitTransforms(); 172 | SetupParticles(); 173 | } 174 | } 175 | 176 | void OnDrawGizmosSelected() 177 | { 178 | if (!enabled || m_Root == null) 179 | return; 180 | 181 | if (Application.isEditor && !Application.isPlaying && transform.hasChanged) 182 | { 183 | InitTransforms(); 184 | SetupParticles(); 185 | } 186 | 187 | Gizmos.color = Color.white; 188 | for (int i = 0; i < m_Particles.Count; ++i) 189 | { 190 | Particle p = m_Particles[i]; 191 | if (p.m_ParentIndex >= 0) 192 | { 193 | Particle p0 = m_Particles[p.m_ParentIndex]; 194 | Gizmos.DrawLine(p.m_Position, p0.m_Position); 195 | } 196 | if (p.m_Radius > 0) 197 | Gizmos.DrawWireSphere(p.m_Position, p.m_Radius * m_ObjectScale); 198 | } 199 | } 200 | 201 | public void SetWeight(float w) 202 | { 203 | if (m_Weight != w) 204 | { 205 | if (w == 0) 206 | InitTransforms(); 207 | else if (m_Weight == 0) 208 | ResetParticlesPosition(); 209 | m_Weight = w; 210 | } 211 | } 212 | 213 | public float GetWeight() 214 | { 215 | return m_Weight; 216 | } 217 | 218 | void UpdateDynamicBones(float t) 219 | { 220 | if (m_Root == null) 221 | return; 222 | 223 | m_ObjectScale = Mathf.Abs(transform.lossyScale.x); 224 | m_ObjectMove = transform.position - m_ObjectPrevPosition; 225 | m_ObjectPrevPosition = transform.position; 226 | 227 | int loop = 1; 228 | if (m_UpdateRate > 0) 229 | { 230 | float dt = 1.0f / m_UpdateRate; 231 | m_Time += t; 232 | loop = 0; 233 | 234 | while (m_Time >= dt) 235 | { 236 | m_Time -= dt; 237 | if (++loop >= 3) 238 | { 239 | m_Time = 0; 240 | break; 241 | } 242 | } 243 | } 244 | 245 | if (loop > 0) 246 | { 247 | for (int i = 0; i < loop; ++i) 248 | { 249 | UpdateParticles1(); 250 | UpdateParticles2(); 251 | m_ObjectMove = Vector3.zero; 252 | } 253 | } 254 | else 255 | { 256 | SkipUpdateParticles(); 257 | } 258 | 259 | ApplyParticlesToTransforms(); 260 | } 261 | 262 | void SetupParticles() 263 | { 264 | m_Particles.Clear(); 265 | if (m_Root == null) 266 | return; 267 | 268 | m_LocalGravity = m_Root.InverseTransformDirection(m_Gravity); 269 | m_ObjectScale = Mathf.Abs(transform.lossyScale.x); 270 | m_ObjectPrevPosition = transform.position; 271 | m_ObjectMove = Vector3.zero; 272 | m_BoneTotalLength = 0; 273 | AppendParticles(m_Root, -1, 0); 274 | 275 | for (int i = 0; i < m_Particles.Count; ++i) 276 | { 277 | Particle p = m_Particles[i]; 278 | p.m_Damping = m_Damping; 279 | p.m_Elasticity = m_Elasticity; 280 | p.m_Stiffness = m_Stiffness; 281 | p.m_Inert = m_Inert; 282 | p.m_Radius = m_Radius; 283 | 284 | if (m_BoneTotalLength > 0) 285 | { 286 | float a = p.m_BoneLength / m_BoneTotalLength; 287 | if (m_DampingDistrib != null && m_DampingDistrib.keys.Length > 0) 288 | p.m_Damping *= m_DampingDistrib.Evaluate(a); 289 | if (m_ElasticityDistrib != null && m_ElasticityDistrib.keys.Length > 0) 290 | p.m_Elasticity *= m_ElasticityDistrib.Evaluate(a); 291 | if (m_StiffnessDistrib != null && m_StiffnessDistrib.keys.Length > 0) 292 | p.m_Stiffness *= m_StiffnessDistrib.Evaluate(a); 293 | if (m_InertDistrib != null && m_InertDistrib.keys.Length > 0) 294 | p.m_Inert *= m_InertDistrib.Evaluate(a); 295 | if (m_RadiusDistrib != null && m_RadiusDistrib.keys.Length > 0) 296 | p.m_Radius *= m_RadiusDistrib.Evaluate(a); 297 | } 298 | 299 | p.m_Damping = Mathf.Clamp01(p.m_Damping); 300 | p.m_Elasticity = Mathf.Clamp01(p.m_Elasticity); 301 | p.m_Stiffness = Mathf.Clamp01(p.m_Stiffness); 302 | p.m_Inert = Mathf.Clamp01(p.m_Inert); 303 | p.m_Radius = Mathf.Max(p.m_Radius, 0); 304 | } 305 | } 306 | 307 | void AppendParticles(Transform b, int parentIndex, float boneLength) 308 | { 309 | Particle p = new Particle(); 310 | p.m_Transform = b; 311 | p.m_ParentIndex = parentIndex; 312 | if (b != null) 313 | { 314 | p.m_Name = b.gameObject.name; 315 | p.m_Position = p.m_PrevPosition = b.position; 316 | p.m_InitLocalPosition = b.localPosition; 317 | p.m_InitLocalRotation = b.localRotation; 318 | } 319 | else // end bone 320 | { 321 | Transform pb = m_Particles[parentIndex].m_Transform; 322 | if (m_EndLength > 0) 323 | { 324 | Transform ppb = pb.parent; 325 | if (ppb != null) 326 | p.m_EndOffset = pb.InverseTransformPoint((pb.position * 2 - ppb.position)) * m_EndLength; 327 | else 328 | p.m_EndOffset = new Vector3(m_EndLength, 0, 0); 329 | } 330 | else 331 | { 332 | p.m_EndOffset = pb.InverseTransformPoint(transform.TransformDirection(m_EndOffset) + pb.position); 333 | } 334 | p.m_Position = p.m_PrevPosition = pb.TransformPoint(p.m_EndOffset); 335 | } 336 | 337 | if (parentIndex >= 0) 338 | { 339 | boneLength += (m_Particles[parentIndex].m_Transform.position - p.m_Position).magnitude; 340 | p.m_BoneLength = boneLength; 341 | m_BoneTotalLength = Mathf.Max(m_BoneTotalLength, boneLength); 342 | } 343 | 344 | int index = m_Particles.Count; 345 | m_Particles.Add(p); 346 | 347 | if (b != null) 348 | { 349 | for (int i = 0; i < b.childCount; ++i) 350 | { 351 | bool exclude = false; 352 | if (m_Exclusions != null) 353 | { 354 | for (int j = 0; j < m_Exclusions.Count; ++j) 355 | { 356 | Transform e = m_Exclusions[j]; 357 | if (e == b.GetChild(i)) 358 | { 359 | exclude = true; 360 | break; 361 | } 362 | } 363 | } 364 | if (!exclude) 365 | AppendParticles(b.GetChild(i), index, boneLength); 366 | } 367 | 368 | if (b.childCount == 0 && (m_EndLength > 0 || m_EndOffset != Vector3.zero)) 369 | AppendParticles(null, index, boneLength); 370 | } 371 | } 372 | 373 | void InitTransforms() 374 | { 375 | for (int i = 0; i < m_Particles.Count; ++i) 376 | { 377 | Particle p = m_Particles[i]; 378 | if (p.m_Transform != null) 379 | { 380 | p.m_Transform.localPosition = p.m_InitLocalPosition; 381 | p.m_Transform.localRotation = p.m_InitLocalRotation; 382 | } 383 | } 384 | } 385 | 386 | void ResetParticlesPosition() 387 | { 388 | for (int i = 0; i < m_Particles.Count; ++i) 389 | { 390 | Particle p = m_Particles[i]; 391 | if (p.m_Transform != null) 392 | { 393 | p.m_Position = p.m_PrevPosition = p.m_Transform.position; 394 | } 395 | else // end bone 396 | { 397 | Transform pb = m_Particles[p.m_ParentIndex].m_Transform; 398 | p.m_Position = p.m_PrevPosition = pb.TransformPoint(p.m_EndOffset); 399 | } 400 | } 401 | m_ObjectPrevPosition = transform.position; 402 | } 403 | 404 | void UpdateParticles1() 405 | { 406 | Vector3 force = m_Gravity; 407 | Vector3 fdir = m_Gravity.normalized; 408 | Vector3 rf = m_Root.TransformDirection(m_LocalGravity); 409 | Vector3 pf = fdir * Mathf.Max(Vector3.Dot(rf, fdir), 0); // project current gravity to rest gravity 410 | force -= pf; // remove projected gravity 411 | force = (force + m_Force) * m_ObjectScale; 412 | 413 | for (int i = 0; i < m_Particles.Count; ++i) 414 | { 415 | Particle p = m_Particles[i]; 416 | if (p.m_ParentIndex >= 0) 417 | { 418 | // verlet integration 419 | Vector3 v = p.m_Position - p.m_PrevPosition; 420 | Vector3 rmove = m_ObjectMove * p.m_Inert; 421 | p.m_PrevPosition = p.m_Position + rmove; 422 | p.m_Position += v * (1 - p.m_Damping) + force + rmove; 423 | } 424 | else 425 | { 426 | p.m_PrevPosition = p.m_Position; 427 | p.m_Position = p.m_Transform.position; 428 | } 429 | } 430 | } 431 | 432 | void UpdateParticles2() 433 | { 434 | Plane movePlane = new Plane(); 435 | 436 | for (int i = 1; i < m_Particles.Count; ++i) 437 | { 438 | Particle p = m_Particles[i]; 439 | Particle p0 = m_Particles[p.m_ParentIndex]; 440 | 441 | float restLen; 442 | if (p.m_Transform != null) 443 | restLen = (p0.m_Transform.position - p.m_Transform.position).magnitude; 444 | else 445 | restLen = p0.m_Transform.localToWorldMatrix.MultiplyVector(p.m_EndOffset).magnitude; 446 | 447 | // keep shape 448 | float stiffness = Mathf.Lerp(1.0f, p.m_Stiffness, m_Weight); 449 | if (stiffness > 0 || p.m_Elasticity > 0) 450 | { 451 | Matrix4x4 m0 = p0.m_Transform.localToWorldMatrix; 452 | m0.SetColumn(3, p0.m_Position); 453 | Vector3 restPos; 454 | if (p.m_Transform != null) 455 | restPos = m0.MultiplyPoint3x4(p.m_Transform.localPosition); 456 | else 457 | restPos = m0.MultiplyPoint3x4(p.m_EndOffset); 458 | 459 | Vector3 d = restPos - p.m_Position; 460 | p.m_Position += d * p.m_Elasticity; 461 | 462 | if (stiffness > 0) 463 | { 464 | d = restPos - p.m_Position; 465 | float len = d.magnitude; 466 | float maxlen = restLen * (1 - stiffness) * 2; 467 | if (len > maxlen) 468 | p.m_Position += d * ((len - maxlen) / len); 469 | } 470 | } 471 | 472 | // collide 473 | if (m_Colliders != null) 474 | { 475 | float particleRadius = p.m_Radius * m_ObjectScale; 476 | for (int j = 0; j < m_Colliders.Count; ++j) 477 | { 478 | DynamicBoneCollider c = m_Colliders[j]; 479 | if (c != null && c.enabled) 480 | c.Collide(ref p.m_Position, particleRadius); 481 | } 482 | } 483 | 484 | // freeze axis, project to plane 485 | if (m_FreezeAxis != FreezeAxis.None) 486 | { 487 | switch (m_FreezeAxis) 488 | { 489 | case FreezeAxis.X: 490 | movePlane.SetNormalAndPosition(p0.m_Transform.right, p0.m_Position); 491 | break; 492 | case FreezeAxis.Y: 493 | movePlane.SetNormalAndPosition(p0.m_Transform.up, p0.m_Position); 494 | break; 495 | case FreezeAxis.Z: 496 | movePlane.SetNormalAndPosition(p0.m_Transform.forward, p0.m_Position); 497 | break; 498 | } 499 | p.m_Position -= movePlane.normal * movePlane.GetDistanceToPoint(p.m_Position); 500 | } 501 | 502 | // keep length 503 | Vector3 dd = p0.m_Position - p.m_Position; 504 | float leng = dd.magnitude; 505 | if (leng > 0) 506 | p.m_Position += dd * ((leng - restLen) / leng); 507 | } 508 | } 509 | 510 | // only update stiffness and keep bone length 511 | void SkipUpdateParticles() 512 | { 513 | for (int i = 0; i < m_Particles.Count; ++i) 514 | { 515 | Particle p = m_Particles[i]; 516 | if (p.m_ParentIndex >= 0) 517 | { 518 | p.m_PrevPosition += m_ObjectMove; 519 | p.m_Position += m_ObjectMove; 520 | 521 | Particle p0 = m_Particles[p.m_ParentIndex]; 522 | 523 | float restLen; 524 | if (p.m_Transform != null) 525 | restLen = (p0.m_Transform.position - p.m_Transform.position).magnitude; 526 | else 527 | restLen = p0.m_Transform.localToWorldMatrix.MultiplyVector(p.m_EndOffset).magnitude; 528 | 529 | // keep shape 530 | float stiffness = Mathf.Lerp(1.0f, p.m_Stiffness, m_Weight); 531 | if (stiffness > 0) 532 | { 533 | Matrix4x4 m0 = p0.m_Transform.localToWorldMatrix; 534 | m0.SetColumn(3, p0.m_Position); 535 | Vector3 restPos; 536 | if (p.m_Transform != null) 537 | restPos = m0.MultiplyPoint3x4(p.m_Transform.localPosition); 538 | else 539 | restPos = m0.MultiplyPoint3x4(p.m_EndOffset); 540 | 541 | Vector3 d = restPos - p.m_Position; 542 | float len = d.magnitude; 543 | float maxlen = restLen * (1 - stiffness) * 2; 544 | if (len > maxlen) 545 | p.m_Position += d * ((len - maxlen) / len); 546 | } 547 | 548 | // keep length 549 | Vector3 dd = p0.m_Position - p.m_Position; 550 | float leng = dd.magnitude; 551 | if (leng > 0) 552 | p.m_Position += dd * ((leng - restLen) / leng); 553 | } 554 | else 555 | { 556 | p.m_PrevPosition = p.m_Position; 557 | p.m_Position = p.m_Transform.position; 558 | } 559 | } 560 | } 561 | 562 | static Vector3 MirrorVector(Vector3 v, Vector3 axis) 563 | { 564 | return v - axis * (Vector3.Dot(v, axis) * 2); 565 | } 566 | 567 | void ApplyParticlesToTransforms() 568 | { 569 | #if !UNITY_5_4_OR_NEWER 570 | // detect negative scale 571 | Vector3 ax = Vector3.right; 572 | Vector3 ay = Vector3.up; 573 | Vector3 az = Vector3.forward; 574 | bool nx = false, ny = false, nz = false; 575 | 576 | Vector3 loosyScale = transform.lossyScale; 577 | if (loosyScale.x < 0 || loosyScale.y < 0 || loosyScale.z < 0) 578 | { 579 | Transform mirrorObject = transform; 580 | do 581 | { 582 | Vector3 ls = mirrorObject.localScale; 583 | nx = ls.x < 0; 584 | if (nx) 585 | ax = mirrorObject.right; 586 | ny = ls.y < 0; 587 | if (ny) 588 | ay = mirrorObject.up; 589 | nz = ls.z < 0; 590 | if (nz) 591 | az = mirrorObject.forward; 592 | if (nx || ny || nz) 593 | break; 594 | 595 | mirrorObject = mirrorObject.parent; 596 | } 597 | while (mirrorObject != null); 598 | } 599 | #endif 600 | 601 | for (int i = 1; i < m_Particles.Count; ++i) 602 | { 603 | Particle p = m_Particles[i]; 604 | Particle p0 = m_Particles[p.m_ParentIndex]; 605 | 606 | if (p0.m_Transform.childCount <= 1) // do not modify bone orientation if has more then one child 607 | { 608 | Vector3 v; 609 | if (p.m_Transform != null) 610 | v = p.m_Transform.localPosition; 611 | else 612 | v = p.m_EndOffset; 613 | Vector3 v2 = p.m_Position - p0.m_Position; 614 | #if !UNITY_5_4_OR_NEWER 615 | if (nx) 616 | v2 = MirrorVector(v2, ax); 617 | if (ny) 618 | v2 = MirrorVector(v2, ay); 619 | if (nz) 620 | v2 = MirrorVector(v2, az); 621 | #endif 622 | Quaternion rot = Quaternion.FromToRotation(p0.m_Transform.TransformDirection(v), v2); 623 | p0.m_Transform.rotation = rot * p0.m_Transform.rotation; 624 | } 625 | 626 | if (p.m_Transform != null) 627 | p.m_Transform.position = p.m_Position; 628 | } 629 | } 630 | } 631 | --------------------------------------------------------------------------------