1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138 |
- using UnityEngine;
- using System.Collections.Generic;
- using System.Threading;
- [AddComponentMenu("Dynamic Bone/Dynamic Bone")]
- public class DynamicBone : MonoBehaviour
- {
- #if UNITY_5_3_OR_NEWER
- [Tooltip("The roots of the transform hierarchy to apply physics.")]
- #endif
- public Transform m_Root = null;
- public List<Transform> m_Roots = null;
- #if UNITY_5_3_OR_NEWER
- [Tooltip("Internal physics simulation rate.")]
- #endif
- public float m_UpdateRate = 60.0f;
- public enum UpdateMode
- {
- Normal,
- AnimatePhysics,
- UnscaledTime,
- Default
- }
- public UpdateMode m_UpdateMode = UpdateMode.Default;
- #if UNITY_5_3_OR_NEWER
- [Tooltip("How much the bones slowed down.")]
- #endif
- [Range(0, 1)]
- public float m_Damping = 0.1f;
- public AnimationCurve m_DampingDistrib = null;
- #if UNITY_5_3_OR_NEWER
- [Tooltip("How much the force applied to return each bone to original orientation.")]
- #endif
- [Range(0, 1)]
- public float m_Elasticity = 0.1f;
- public AnimationCurve m_ElasticityDistrib = null;
- #if UNITY_5_3_OR_NEWER
- [Tooltip("How much bone's original orientation are preserved.")]
- #endif
- [Range(0, 1)]
- public float m_Stiffness = 0.1f;
- public AnimationCurve m_StiffnessDistrib = null;
- #if UNITY_5_3_OR_NEWER
- [Tooltip("How much character's position change is ignored in physics simulation.")]
- #endif
- [Range(0, 1)]
- public float m_Inert = 0;
- public AnimationCurve m_InertDistrib = null;
- #if UNITY_5_3_OR_NEWER
- [Tooltip("How much the bones slowed down when collide.")]
- #endif
- public float m_Friction = 0;
- public AnimationCurve m_FrictionDistrib = null;
- #if UNITY_5_3_OR_NEWER
- [Tooltip("Each bone can be a sphere to collide with colliders. Radius describe sphere's size.")]
- #endif
- public float m_Radius = 0;
- public AnimationCurve m_RadiusDistrib = null;
- #if UNITY_5_3_OR_NEWER
- [Tooltip("If End Length is not zero, an extra bone is generated at the end of transform hierarchy.")]
- #endif
- public float m_EndLength = 0;
- #if UNITY_5_3_OR_NEWER
- [Tooltip("If End Offset is not zero, an extra bone is generated at the end of transform hierarchy.")]
- #endif
- public Vector3 m_EndOffset = Vector3.zero;
- #if UNITY_5_3_OR_NEWER
- [Tooltip("The force apply to bones. Partial force apply to character's initial pose is cancelled out.")]
- #endif
- public Vector3 m_Gravity = Vector3.zero;
- #if UNITY_5_3_OR_NEWER
- [Tooltip("The force apply to bones.")]
- #endif
- public Vector3 m_Force = Vector3.zero;
- #if UNITY_5_3_OR_NEWER
- [Tooltip("Control how physics blends with existing animation.")]
- #endif
- [Range(0, 1)]
- public float m_BlendWeight = 1.0f;
- #if UNITY_5_3_OR_NEWER
- [Tooltip("Collider objects interact with the bones.")]
- #endif
- public List<DynamicBoneColliderBase> m_Colliders = null;
- #if UNITY_5_3_OR_NEWER
- [Tooltip("Bones exclude from physics simulation.")]
- #endif
- public List<Transform> m_Exclusions = null;
- public enum FreezeAxis
- {
- None, X, Y, Z
- }
- #if UNITY_5_3_OR_NEWER
- [Tooltip("Constrain bones to move on specified plane.")]
- #endif
- public FreezeAxis m_FreezeAxis = FreezeAxis.None;
- #if UNITY_5_3_OR_NEWER
- [Tooltip("Disable physics simulation automatically if character is far from camera or player.")]
- #endif
- public bool m_DistantDisable = false;
- public Transform m_ReferenceObject = null;
- public float m_DistanceToObject = 20;
- [HideInInspector]
- public bool m_Multithread = true;
- Vector3 m_ObjectMove;
- Vector3 m_ObjectPrevPosition;
- float m_ObjectScale;
- float m_Time = 0;
- float m_Weight = 1.0f;
- bool m_DistantDisabled = false;
- bool m_WorkAdded = false;
- int m_PreUpdateCount = 0;
- class Particle
- {
- public Transform m_Transform;
- public int m_ParentIndex;
- public int m_ChildCount;
- public float m_Damping;
- public float m_Elasticity;
- public float m_Stiffness;
- public float m_Inert;
- public float m_Friction;
- public float m_Radius;
- public float m_BoneLength;
- public bool m_isCollide;
- public bool m_TransformNotNull;
- public Vector3 m_Position;
- public Vector3 m_PrevPosition;
- public Vector3 m_EndOffset;
- public Vector3 m_InitLocalPosition;
- public Quaternion m_InitLocalRotation;
- // prepare data
- public Vector3 m_TransformPosition;
- public Vector3 m_TransformLocalPosition;
- public Matrix4x4 m_TransformLocalToWorldMatrix;
- }
- class ParticleTree
- {
- public Transform m_Root;
- public Vector3 m_LocalGravity;
- public Matrix4x4 m_RootWorldToLocalMatrix;
- public float m_BoneTotalLength;
- public List<Particle> m_Particles = new List<Particle>();
- // prepare data
- public Vector3 m_RestGravity;
- }
- List<ParticleTree> m_ParticleTrees = new List<ParticleTree>();
- // prepare data
- float m_DeltaTime;
- List<DynamicBoneColliderBase> m_EffectiveColliders;
- // multithread
- static List<DynamicBone> s_PendingWorks = new List<DynamicBone>();
- static List<DynamicBone> s_EffectiveWorks = new List<DynamicBone>();
- static AutoResetEvent s_AllWorksDoneEvent;
- static int s_RemainWorkCount;
- static Semaphore s_WorkQueueSemaphore;
- static int s_WorkQueueIndex;
- static int s_UpdateCount;
- static int s_PrepareFrame;
- void Start()
- {
- SetupParticles();
- }
- void FixedUpdate()
- {
- if (m_UpdateMode == UpdateMode.AnimatePhysics)
- {
- PreUpdate();
- }
- }
- void Update()
- {
- if (m_UpdateMode != UpdateMode.AnimatePhysics)
- {
- PreUpdate();
- }
- if (m_PreUpdateCount > 0 && m_Multithread)
- {
- AddPendingWork(this);
- m_WorkAdded = true;
- }
- ++s_UpdateCount;
- }
- void LateUpdate()
- {
- if (m_PreUpdateCount == 0)
- return;
- if (s_UpdateCount > 0)
- {
- s_UpdateCount = 0;
- ++s_PrepareFrame;
- }
- SetWeight(m_BlendWeight);
- if (m_WorkAdded)
- {
- m_WorkAdded = false;
- ExecuteWorks();
- }
- else
- {
- CheckDistance();
- if (IsNeedUpdate())
- {
- Prepare();
- UpdateParticles();
- ApplyParticlesToTransforms();
- }
- }
- m_PreUpdateCount = 0;
- }
- void Prepare()
- {
- m_DeltaTime = Time.deltaTime;
- #if UNITY_5_3_OR_NEWER
- if (m_UpdateMode == UpdateMode.UnscaledTime)
- {
- m_DeltaTime = Time.unscaledDeltaTime;
- }
- else if (m_UpdateMode == UpdateMode.AnimatePhysics)
- {
- m_DeltaTime = Time.fixedDeltaTime * m_PreUpdateCount;
- }
- #endif
- m_ObjectScale = Mathf.Abs(transform.lossyScale.x);
- m_ObjectMove = transform.position - m_ObjectPrevPosition;
- m_ObjectPrevPosition = transform.position;
- for (int i = 0; i < m_ParticleTrees.Count; ++i)
- {
- ParticleTree pt = m_ParticleTrees[i];
- pt.m_RestGravity = pt.m_Root.TransformDirection(pt.m_LocalGravity);
- for (int j = 0; j < pt.m_Particles.Count; ++j)
- {
- Particle p = pt.m_Particles[j];
- if (p.m_TransformNotNull)
- {
- p.m_TransformPosition = p.m_Transform.position;
- p.m_TransformLocalPosition = p.m_Transform.localPosition;
- p.m_TransformLocalToWorldMatrix = p.m_Transform.localToWorldMatrix;
- }
- }
- }
- if (m_EffectiveColliders != null)
- {
- m_EffectiveColliders.Clear();
- }
- if (m_Colliders != null)
- {
- for (int i = 0; i < m_Colliders.Count; ++i)
- {
- DynamicBoneColliderBase c = m_Colliders[i];
- if (c != null && c.enabled)
- {
- if (m_EffectiveColliders == null)
- {
- m_EffectiveColliders = new List<DynamicBoneColliderBase>();
- }
- m_EffectiveColliders.Add(c);
- if (c.PrepareFrame != s_PrepareFrame) // colliders used by many dynamic bones only prepares once
- {
- c.Prepare();
- c.PrepareFrame = s_PrepareFrame;
- }
- }
- }
- }
- }
- bool IsNeedUpdate()
- {
- return m_Weight > 0 && !(m_DistantDisable && m_DistantDisabled);
- }
- void PreUpdate()
- {
- if (IsNeedUpdate())
- {
- InitTransforms();
- }
- ++m_PreUpdateCount;
- }
- void CheckDistance()
- {
- if (!m_DistantDisable)
- return;
- Transform rt = m_ReferenceObject;
- if (rt == null && Camera.main != null)
- {
- rt = Camera.main.transform;
- }
- if (rt != null)
- {
- float d2 = (rt.position - transform.position).sqrMagnitude;
- bool disable = d2 > m_DistanceToObject * m_DistanceToObject;
- if (disable != m_DistantDisabled)
- {
- if (!disable)
- {
- ResetParticlesPosition();
- }
- m_DistantDisabled = disable;
- }
- }
- }
- void OnEnable()
- {
- ResetParticlesPosition();
- }
- void OnDisable()
- {
- InitTransforms();
- }
- void OnValidate()
- {
- m_UpdateRate = Mathf.Max(m_UpdateRate, 0);
- m_Damping = Mathf.Clamp01(m_Damping);
- m_Elasticity = Mathf.Clamp01(m_Elasticity);
- m_Stiffness = Mathf.Clamp01(m_Stiffness);
- m_Inert = Mathf.Clamp01(m_Inert);
- m_Friction = Mathf.Clamp01(m_Friction);
- m_Radius = Mathf.Max(m_Radius, 0);
- if (Application.isEditor && Application.isPlaying)
- {
- if (IsRootChanged())
- {
- InitTransforms();
- SetupParticles();
- }
- else
- {
- UpdateParameters();
- }
- }
- }
- bool IsRootChanged()
- {
- var roots = new List<Transform>();
- if (m_Root != null)
- {
- roots.Add(m_Root);
- }
- if (m_Roots != null)
- {
- foreach (var root in m_Roots)
- {
- if (root != null && !roots.Contains(root))
- {
- roots.Add(root);
- }
- }
- }
- if (roots.Count != m_ParticleTrees.Count)
- return true;
- for (int i = 0; i < roots.Count; ++i)
- {
- if (roots[i] != m_ParticleTrees[i].m_Root)
- return true;
- }
- return false;
- }
- void OnDidApplyAnimationProperties()
- {
- UpdateParameters();
- }
- void OnDrawGizmosSelected()
- {
- if (!enabled)
- return;
- if (Application.isEditor && !Application.isPlaying && transform.hasChanged)
- {
- InitTransforms();
- SetupParticles();
- }
- Gizmos.color = Color.white;
- for (int i = 0; i < m_ParticleTrees.Count; ++i)
- {
- DrawGizmos(m_ParticleTrees[i]);
- }
- }
- void DrawGizmos(ParticleTree pt)
- {
- for (int i = 0; i < pt.m_Particles.Count; ++i)
- {
- Particle p = pt.m_Particles[i];
- if (p.m_ParentIndex >= 0)
- {
- Particle p0 = pt.m_Particles[p.m_ParentIndex];
- Gizmos.DrawLine(p.m_Position, p0.m_Position);
- }
- if (p.m_Radius > 0)
- {
- Gizmos.DrawWireSphere(p.m_Position, p.m_Radius * m_ObjectScale);
- }
- }
- }
- public void SetWeight(float w)
- {
- if (m_Weight != w)
- {
- if (w == 0)
- {
- InitTransforms();
- }
- else if (m_Weight == 0)
- {
- ResetParticlesPosition();
- }
- m_Weight = m_BlendWeight = w;
- }
- }
- public float GetWeight()
- {
- return m_Weight;
- }
- void UpdateParticles()
- {
- if (m_ParticleTrees.Count <= 0)
- return;
- int loop = 1;
- float timeVar = 1;
- float dt = m_DeltaTime;
- if (m_UpdateMode == UpdateMode.Default)
- {
- if (m_UpdateRate > 0)
- {
- timeVar = dt * m_UpdateRate;
- }
- }
- else
- {
- if (m_UpdateRate > 0)
- {
- float frameTime = 1.0f / m_UpdateRate;
- m_Time += dt;
- loop = 0;
- while (m_Time >= frameTime)
- {
- m_Time -= frameTime;
- if (++loop >= 3)
- {
- m_Time = 0;
- break;
- }
- }
- }
- }
- if (loop > 0)
- {
- for (int i = 0; i < loop; ++i)
- {
- UpdateParticles1(timeVar, i);
- UpdateParticles2(timeVar);
- }
- }
- else
- {
- SkipUpdateParticles();
- }
- }
- public void SetupParticles()
- {
- m_ParticleTrees.Clear();
- if (m_Root != null)
- {
- AppendParticleTree(m_Root);
- }
- if (m_Roots != null)
- {
- for (int i = 0; i < m_Roots.Count; ++i)
- {
- Transform root = m_Roots[i];
- if (root == null)
- continue;
- if (m_ParticleTrees.Exists(x => x.m_Root == root))
- continue;
- AppendParticleTree(root);
- }
- }
- m_ObjectScale = Mathf.Abs(transform.lossyScale.x);
- m_ObjectPrevPosition = transform.position;
- m_ObjectMove = Vector3.zero;
- for (int i = 0; i < m_ParticleTrees.Count; ++i)
- {
- ParticleTree pt = m_ParticleTrees[i];
- AppendParticles(pt, pt.m_Root, -1, 0);
- }
- UpdateParameters();
- }
- void AppendParticleTree(Transform root)
- {
- if (root == null)
- return;
- var pt = new ParticleTree();
- pt.m_Root = root;
- pt.m_RootWorldToLocalMatrix = root.worldToLocalMatrix;
- m_ParticleTrees.Add(pt);
- }
- void AppendParticles(ParticleTree pt, Transform b, int parentIndex, float boneLength)
- {
- var p = new Particle();
- p.m_Transform = b;
- p.m_TransformNotNull = b != null;
- p.m_ParentIndex = parentIndex;
- if (b != null)
- {
- p.m_Position = p.m_PrevPosition = b.position;
- p.m_InitLocalPosition = b.localPosition;
- p.m_InitLocalRotation = b.localRotation;
- }
- else // end bone
- {
- Transform pb = pt.m_Particles[parentIndex].m_Transform;
- if (m_EndLength > 0)
- {
- Transform ppb = pb.parent;
- if (ppb != null)
- {
- p.m_EndOffset = pb.InverseTransformPoint((pb.position * 2 - ppb.position)) * m_EndLength;
- }
- else
- {
- p.m_EndOffset = new Vector3(m_EndLength, 0, 0);
- }
- }
- else
- {
- p.m_EndOffset = pb.InverseTransformPoint(transform.TransformDirection(m_EndOffset) + pb.position);
- }
- p.m_Position = p.m_PrevPosition = pb.TransformPoint(p.m_EndOffset);
- p.m_InitLocalPosition = Vector3.zero;
- p.m_InitLocalRotation = Quaternion.identity;
- }
- if (parentIndex >= 0)
- {
- boneLength += (pt.m_Particles[parentIndex].m_Transform.position - p.m_Position).magnitude;
- p.m_BoneLength = boneLength;
- pt.m_BoneTotalLength = Mathf.Max(pt.m_BoneTotalLength, boneLength);
- ++pt.m_Particles[parentIndex].m_ChildCount;
- }
- int index = pt.m_Particles.Count;
- pt.m_Particles.Add(p);
- if (b != null)
- {
- for (int i = 0; i < b.childCount; ++i)
- {
- Transform child = b.GetChild(i);
- bool exclude = false;
- if (m_Exclusions != null)
- {
- exclude = m_Exclusions.Contains(child);
- }
- if (!exclude)
- {
- AppendParticles(pt, child, index, boneLength);
- }
- else if (m_EndLength > 0 || m_EndOffset != Vector3.zero)
- {
- AppendParticles(pt, null, index, boneLength);
- }
- }
- if (b.childCount == 0 && (m_EndLength > 0 || m_EndOffset != Vector3.zero))
- {
- AppendParticles(pt, null, index, boneLength);
- }
- }
- }
- public void UpdateParameters()
- {
- SetWeight(m_BlendWeight);
- for (int i = 0; i < m_ParticleTrees.Count; ++i)
- {
- UpdateParameters(m_ParticleTrees[i]);
- }
- }
- void UpdateParameters(ParticleTree pt)
- {
- // m_LocalGravity = m_Root.InverseTransformDirection(m_Gravity);
- pt.m_LocalGravity = pt.m_RootWorldToLocalMatrix.MultiplyVector(m_Gravity).normalized * m_Gravity.magnitude;
- for (int i = 0; i < pt.m_Particles.Count; ++i)
- {
- Particle p = pt.m_Particles[i];
- p.m_Damping = m_Damping;
- p.m_Elasticity = m_Elasticity;
- p.m_Stiffness = m_Stiffness;
- p.m_Inert = m_Inert;
- p.m_Friction = m_Friction;
- p.m_Radius = m_Radius;
- if (pt.m_BoneTotalLength > 0)
- {
- float a = p.m_BoneLength / pt.m_BoneTotalLength;
- if (m_DampingDistrib != null && m_DampingDistrib.keys.Length > 0)
- p.m_Damping *= m_DampingDistrib.Evaluate(a);
- if (m_ElasticityDistrib != null && m_ElasticityDistrib.keys.Length > 0)
- p.m_Elasticity *= m_ElasticityDistrib.Evaluate(a);
- if (m_StiffnessDistrib != null && m_StiffnessDistrib.keys.Length > 0)
- p.m_Stiffness *= m_StiffnessDistrib.Evaluate(a);
- if (m_InertDistrib != null && m_InertDistrib.keys.Length > 0)
- p.m_Inert *= m_InertDistrib.Evaluate(a);
- if (m_FrictionDistrib != null && m_FrictionDistrib.keys.Length > 0)
- p.m_Friction *= m_FrictionDistrib.Evaluate(a);
- if (m_RadiusDistrib != null && m_RadiusDistrib.keys.Length > 0)
- p.m_Radius *= m_RadiusDistrib.Evaluate(a);
- }
- p.m_Damping = Mathf.Clamp01(p.m_Damping);
- p.m_Elasticity = Mathf.Clamp01(p.m_Elasticity);
- p.m_Stiffness = Mathf.Clamp01(p.m_Stiffness);
- p.m_Inert = Mathf.Clamp01(p.m_Inert);
- p.m_Friction = Mathf.Clamp01(p.m_Friction);
- p.m_Radius = Mathf.Max(p.m_Radius, 0);
- }
- }
- void InitTransforms()
- {
- for (int i = 0; i < m_ParticleTrees.Count; ++i)
- {
- InitTransforms(m_ParticleTrees[i]);
- }
- }
- void InitTransforms(ParticleTree pt)
- {
- for (int i = 0; i < pt.m_Particles.Count; ++i)
- {
- Particle p = pt.m_Particles[i];
- if (p.m_TransformNotNull)
- {
- p.m_Transform.localPosition = p.m_InitLocalPosition;
- p.m_Transform.localRotation = p.m_InitLocalRotation;
- }
- }
- }
- void ResetParticlesPosition()
- {
- for (int i = 0; i < m_ParticleTrees.Count; ++i)
- {
- ResetParticlesPosition(m_ParticleTrees[i]);
- }
- m_ObjectPrevPosition = transform.position;
- }
- void ResetParticlesPosition(ParticleTree pt)
- {
- for (int i = 0; i < pt.m_Particles.Count; ++i)
- {
- Particle p = pt.m_Particles[i];
- if (p.m_TransformNotNull)
- {
- p.m_Position = p.m_PrevPosition = p.m_Transform.position;
- }
- else // end bone
- {
- Transform pb = pt.m_Particles[p.m_ParentIndex].m_Transform;
- p.m_Position = p.m_PrevPosition = pb.TransformPoint(p.m_EndOffset);
- }
- p.m_isCollide = false;
- }
- }
- void UpdateParticles1(float timeVar, int loopIndex)
- {
- for (int i = 0; i < m_ParticleTrees.Count; ++i)
- {
- UpdateParticles1(m_ParticleTrees[i], timeVar, loopIndex);
- }
- }
- void UpdateParticles1(ParticleTree pt, float timeVar, int loopIndex)
- {
- Vector3 force = m_Gravity;
- Vector3 fdir = m_Gravity.normalized;
- Vector3 pf = fdir * Mathf.Max(Vector3.Dot(pt.m_RestGravity, fdir), 0); // project current gravity to rest gravity
- force -= pf; // remove projected gravity
- force = (force + m_Force) * (m_ObjectScale * timeVar);
- Vector3 objectMove = loopIndex == 0 ? m_ObjectMove : Vector3.zero; // only first loop consider object move
- for (int i = 0; i < pt.m_Particles.Count; ++i)
- {
- Particle p = pt.m_Particles[i];
- if (p.m_ParentIndex >= 0)
- {
- // verlet integration
- Vector3 v = p.m_Position - p.m_PrevPosition;
- Vector3 rmove = objectMove * p.m_Inert;
- p.m_PrevPosition = p.m_Position + rmove;
- float damping = p.m_Damping;
- if (p.m_isCollide)
- {
- damping += p.m_Friction;
- if (damping > 1)
- {
- damping = 1;
- }
- p.m_isCollide = false;
- }
- p.m_Position += v * (1 - damping) + force + rmove;
- }
- else
- {
- p.m_PrevPosition = p.m_Position;
- p.m_Position = p.m_TransformPosition;
- }
- }
- }
- void UpdateParticles2(float timeVar)
- {
- for (int i = 0; i < m_ParticleTrees.Count; ++i)
- {
- UpdateParticles2(m_ParticleTrees[i], timeVar);
- }
- }
- void UpdateParticles2(ParticleTree pt, float timeVar)
- {
- var movePlane = new Plane();
- for (int i = 1; i < pt.m_Particles.Count; ++i)
- {
- Particle p = pt.m_Particles[i];
- Particle p0 = pt.m_Particles[p.m_ParentIndex];
- float restLen;
- if (p.m_TransformNotNull)
- {
- restLen = (p0.m_TransformPosition - p.m_TransformPosition).magnitude;
- }
- else
- {
- restLen = p0.m_TransformLocalToWorldMatrix.MultiplyVector(p.m_EndOffset).magnitude;
- }
- // keep shape
- float stiffness = Mathf.Lerp(1.0f, p.m_Stiffness, m_Weight);
- if (stiffness > 0 || p.m_Elasticity > 0)
- {
- Matrix4x4 m0 = p0.m_TransformLocalToWorldMatrix;
- m0.SetColumn(3, p0.m_Position);
- Vector3 restPos;
- if (p.m_TransformNotNull)
- {
- restPos = m0.MultiplyPoint3x4(p.m_TransformLocalPosition);
- }
- else
- {
- restPos = m0.MultiplyPoint3x4(p.m_EndOffset);
- }
- Vector3 d = restPos - p.m_Position;
- p.m_Position += d * (p.m_Elasticity * timeVar);
- if (stiffness > 0)
- {
- d = restPos - p.m_Position;
- float len = d.magnitude;
- float maxlen = restLen * (1 - stiffness) * 2;
- if (len > maxlen)
- {
- p.m_Position += d * ((len - maxlen) / len);
- }
- }
- }
- // collide
- if (m_EffectiveColliders != null)
- {
- float particleRadius = p.m_Radius * m_ObjectScale;
- for (int j = 0; j < m_EffectiveColliders.Count; ++j)
- {
- DynamicBoneColliderBase c = m_EffectiveColliders[j];
- p.m_isCollide |= c.Collide(ref p.m_Position, particleRadius);
- }
- }
- // freeze axis, project to plane
- if (m_FreezeAxis != FreezeAxis.None)
- {
- Vector3 planeNormal = p0.m_TransformLocalToWorldMatrix.GetColumn((int)m_FreezeAxis - 1).normalized;
- movePlane.SetNormalAndPosition(planeNormal, p0.m_Position);
- p.m_Position -= movePlane.normal * movePlane.GetDistanceToPoint(p.m_Position);
- }
- // keep length
- Vector3 dd = p0.m_Position - p.m_Position;
- float leng = dd.magnitude;
- if (leng > 0)
- {
- p.m_Position += dd * ((leng - restLen) / leng);
- }
- }
- }
- void SkipUpdateParticles()
- {
- for (int i = 0; i < m_ParticleTrees.Count; ++i)
- {
- SkipUpdateParticles(m_ParticleTrees[i]);
- }
- }
- // only update stiffness and keep bone length
- void SkipUpdateParticles(ParticleTree pt)
- {
- for (int i = 0; i < pt.m_Particles.Count; ++i)
- {
- Particle p = pt.m_Particles[i];
- if (p.m_ParentIndex >= 0)
- {
- p.m_PrevPosition += m_ObjectMove;
- p.m_Position += m_ObjectMove;
- Particle p0 = pt.m_Particles[p.m_ParentIndex];
- float restLen;
- if (p.m_TransformNotNull)
- {
- restLen = (p0.m_TransformPosition - p.m_TransformPosition).magnitude;
- }
- else
- {
- restLen = p0.m_TransformLocalToWorldMatrix.MultiplyVector(p.m_EndOffset).magnitude;
- }
- // keep shape
- float stiffness = Mathf.Lerp(1.0f, p.m_Stiffness, m_Weight);
- if (stiffness > 0)
- {
- Matrix4x4 m0 = p0.m_TransformLocalToWorldMatrix;
- m0.SetColumn(3, p0.m_Position);
- Vector3 restPos;
- if (p.m_TransformNotNull)
- {
- restPos = m0.MultiplyPoint3x4(p.m_TransformLocalPosition);
- }
- else
- {
- restPos = m0.MultiplyPoint3x4(p.m_EndOffset);
- }
- Vector3 d = restPos - p.m_Position;
- float len = d.magnitude;
- float maxlen = restLen * (1 - stiffness) * 2;
- if (len > maxlen)
- {
- p.m_Position += d * ((len - maxlen) / len);
- }
- }
- // keep length
- Vector3 dd = p0.m_Position - p.m_Position;
- float leng = dd.magnitude;
- if (leng > 0)
- {
- p.m_Position += dd * ((leng - restLen) / leng);
- }
- }
- else
- {
- p.m_PrevPosition = p.m_Position;
- p.m_Position = p.m_TransformPosition;
- }
- }
- }
- static Vector3 MirrorVector(Vector3 v, Vector3 axis)
- {
- return v - axis * (Vector3.Dot(v, axis) * 2);
- }
- void ApplyParticlesToTransforms()
- {
- Vector3 ax = Vector3.right;
- Vector3 ay = Vector3.up;
- Vector3 az = Vector3.forward;
- bool nx = false, ny = false, nz = false;
- #if !UNITY_5_4_OR_NEWER
- // detect negative scale
- Vector3 lossyScale = transform.lossyScale;
- if (lossyScale.x < 0 || lossyScale.y < 0 || lossyScale.z < 0)
- {
- Transform mirrorObject = transform;
- do
- {
- Vector3 ls = mirrorObject.localScale;
- nx = ls.x < 0;
- if (nx)
- ax = mirrorObject.right;
- ny = ls.y < 0;
- if (ny)
- ay = mirrorObject.up;
- nz = ls.z < 0;
- if (nz)
- az = mirrorObject.forward;
- if (nx || ny || nz)
- break;
- mirrorObject = mirrorObject.parent;
- }
- while (mirrorObject != null);
- }
- #endif
- for (int i = 0; i < m_ParticleTrees.Count; ++i)
- {
- ApplyParticlesToTransforms(m_ParticleTrees[i], ax, ay, az, nx, ny, nz);
- }
- }
- void ApplyParticlesToTransforms(ParticleTree pt, Vector3 ax, Vector3 ay, Vector3 az, bool nx, bool ny, bool nz)
- {
- for (int i = 1; i < pt.m_Particles.Count; ++i)
- {
- Particle p = pt.m_Particles[i];
- Particle p0 = pt.m_Particles[p.m_ParentIndex];
- if (p0.m_ChildCount <= 1) // do not modify bone orientation if has more then one child
- {
- Vector3 localPos;
- if (p.m_TransformNotNull)
- {
- localPos = p.m_Transform.localPosition;
- }
- else
- {
- localPos = p.m_EndOffset;
- }
- Vector3 v0 = p0.m_Transform.TransformDirection(localPos);
- Vector3 v1 = p.m_Position - p0.m_Position;
- #if !UNITY_5_4_OR_NEWER
- if (nx)
- v1 = MirrorVector(v1, ax);
- if (ny)
- v1 = MirrorVector(v1, ay);
- if (nz)
- v1 = MirrorVector(v1, az);
- #endif
- Quaternion rot = Quaternion.FromToRotation(v0, v1);
- p0.m_Transform.rotation = rot * p0.m_Transform.rotation;
- }
- if (p.m_TransformNotNull)
- {
- p.m_Transform.position = p.m_Position;
- }
- }
- }
- static void AddPendingWork(DynamicBone db)
- {
- s_PendingWorks.Add(db);
- }
- static void AddWorkToQueue(DynamicBone db)
- {
- s_WorkQueueSemaphore.Release();
- }
- static DynamicBone GetWorkFromQueue()
- {
- int idx = Interlocked.Increment(ref s_WorkQueueIndex);
- return s_EffectiveWorks[idx];
- }
- static void ThreadProc()
- {
- while (true)
- {
- s_WorkQueueSemaphore.WaitOne();
- DynamicBone db = GetWorkFromQueue();
- db.UpdateParticles();
- if (Interlocked.Decrement(ref s_RemainWorkCount) <= 0)
- {
- s_AllWorksDoneEvent.Set();
- }
- }
- }
- static void InitThreadPool()
- {
- s_AllWorksDoneEvent = new AutoResetEvent(false);
- s_WorkQueueSemaphore = new Semaphore(0, int.MaxValue);
- int threadCount = System.Environment.ProcessorCount;
- for (int i = 0; i < threadCount; ++i)
- {
- var t = new Thread(ThreadProc);
- t.IsBackground = true;
- t.Start();
- }
- }
- static void ExecuteWorks()
- {
- if (s_PendingWorks.Count <= 0)
- return;
- s_EffectiveWorks.Clear();
- for (int i = 0; i < s_PendingWorks.Count; ++i)
- {
- DynamicBone db = s_PendingWorks[i];
- if (db != null && db.enabled)
- {
- db.CheckDistance();
- if (db.IsNeedUpdate())
- {
- s_EffectiveWorks.Add(db);
- }
- }
- }
- s_PendingWorks.Clear();
- if (s_EffectiveWorks.Count <= 0)
- return;
- if (s_AllWorksDoneEvent == null)
- {
- InitThreadPool();
- }
- int workCount = s_RemainWorkCount = s_EffectiveWorks.Count;
- s_WorkQueueIndex = -1;
- for (int i = 0; i < workCount; ++i)
- {
- DynamicBone db = s_EffectiveWorks[i];
- db.Prepare();
- AddWorkToQueue(db);
- }
- s_AllWorksDoneEvent.WaitOne();
- for (int i = 0; i < workCount; ++i)
- {
- DynamicBone db = s_EffectiveWorks[i];
- db.ApplyParticlesToTransforms();
- }
- }
- }
|