DynamicBone.cs 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138
  1. using UnityEngine;
  2. using System.Collections.Generic;
  3. using System.Threading;
  4. [AddComponentMenu("Dynamic Bone/Dynamic Bone")]
  5. public class DynamicBone : MonoBehaviour
  6. {
  7. #if UNITY_5_3_OR_NEWER
  8. [Tooltip("The roots of the transform hierarchy to apply physics.")]
  9. #endif
  10. public Transform m_Root = null;
  11. public List<Transform> m_Roots = null;
  12. #if UNITY_5_3_OR_NEWER
  13. [Tooltip("Internal physics simulation rate.")]
  14. #endif
  15. public float m_UpdateRate = 60.0f;
  16. public enum UpdateMode
  17. {
  18. Normal,
  19. AnimatePhysics,
  20. UnscaledTime,
  21. Default
  22. }
  23. public UpdateMode m_UpdateMode = UpdateMode.Default;
  24. #if UNITY_5_3_OR_NEWER
  25. [Tooltip("How much the bones slowed down.")]
  26. #endif
  27. [Range(0, 1)]
  28. public float m_Damping = 0.1f;
  29. public AnimationCurve m_DampingDistrib = null;
  30. #if UNITY_5_3_OR_NEWER
  31. [Tooltip("How much the force applied to return each bone to original orientation.")]
  32. #endif
  33. [Range(0, 1)]
  34. public float m_Elasticity = 0.1f;
  35. public AnimationCurve m_ElasticityDistrib = null;
  36. #if UNITY_5_3_OR_NEWER
  37. [Tooltip("How much bone's original orientation are preserved.")]
  38. #endif
  39. [Range(0, 1)]
  40. public float m_Stiffness = 0.1f;
  41. public AnimationCurve m_StiffnessDistrib = null;
  42. #if UNITY_5_3_OR_NEWER
  43. [Tooltip("How much character's position change is ignored in physics simulation.")]
  44. #endif
  45. [Range(0, 1)]
  46. public float m_Inert = 0;
  47. public AnimationCurve m_InertDistrib = null;
  48. #if UNITY_5_3_OR_NEWER
  49. [Tooltip("How much the bones slowed down when collide.")]
  50. #endif
  51. public float m_Friction = 0;
  52. public AnimationCurve m_FrictionDistrib = null;
  53. #if UNITY_5_3_OR_NEWER
  54. [Tooltip("Each bone can be a sphere to collide with colliders. Radius describe sphere's size.")]
  55. #endif
  56. public float m_Radius = 0;
  57. public AnimationCurve m_RadiusDistrib = null;
  58. #if UNITY_5_3_OR_NEWER
  59. [Tooltip("If End Length is not zero, an extra bone is generated at the end of transform hierarchy.")]
  60. #endif
  61. public float m_EndLength = 0;
  62. #if UNITY_5_3_OR_NEWER
  63. [Tooltip("If End Offset is not zero, an extra bone is generated at the end of transform hierarchy.")]
  64. #endif
  65. public Vector3 m_EndOffset = Vector3.zero;
  66. #if UNITY_5_3_OR_NEWER
  67. [Tooltip("The force apply to bones. Partial force apply to character's initial pose is cancelled out.")]
  68. #endif
  69. public Vector3 m_Gravity = Vector3.zero;
  70. #if UNITY_5_3_OR_NEWER
  71. [Tooltip("The force apply to bones.")]
  72. #endif
  73. public Vector3 m_Force = Vector3.zero;
  74. #if UNITY_5_3_OR_NEWER
  75. [Tooltip("Control how physics blends with existing animation.")]
  76. #endif
  77. [Range(0, 1)]
  78. public float m_BlendWeight = 1.0f;
  79. #if UNITY_5_3_OR_NEWER
  80. [Tooltip("Collider objects interact with the bones.")]
  81. #endif
  82. public List<DynamicBoneColliderBase> m_Colliders = null;
  83. #if UNITY_5_3_OR_NEWER
  84. [Tooltip("Bones exclude from physics simulation.")]
  85. #endif
  86. public List<Transform> m_Exclusions = null;
  87. public enum FreezeAxis
  88. {
  89. None, X, Y, Z
  90. }
  91. #if UNITY_5_3_OR_NEWER
  92. [Tooltip("Constrain bones to move on specified plane.")]
  93. #endif
  94. public FreezeAxis m_FreezeAxis = FreezeAxis.None;
  95. #if UNITY_5_3_OR_NEWER
  96. [Tooltip("Disable physics simulation automatically if character is far from camera or player.")]
  97. #endif
  98. public bool m_DistantDisable = false;
  99. public Transform m_ReferenceObject = null;
  100. public float m_DistanceToObject = 20;
  101. [HideInInspector]
  102. public bool m_Multithread = true;
  103. Vector3 m_ObjectMove;
  104. Vector3 m_ObjectPrevPosition;
  105. float m_ObjectScale;
  106. float m_Time = 0;
  107. float m_Weight = 1.0f;
  108. bool m_DistantDisabled = false;
  109. bool m_WorkAdded = false;
  110. int m_PreUpdateCount = 0;
  111. class Particle
  112. {
  113. public Transform m_Transform;
  114. public int m_ParentIndex;
  115. public int m_ChildCount;
  116. public float m_Damping;
  117. public float m_Elasticity;
  118. public float m_Stiffness;
  119. public float m_Inert;
  120. public float m_Friction;
  121. public float m_Radius;
  122. public float m_BoneLength;
  123. public bool m_isCollide;
  124. public bool m_TransformNotNull;
  125. public Vector3 m_Position;
  126. public Vector3 m_PrevPosition;
  127. public Vector3 m_EndOffset;
  128. public Vector3 m_InitLocalPosition;
  129. public Quaternion m_InitLocalRotation;
  130. // prepare data
  131. public Vector3 m_TransformPosition;
  132. public Vector3 m_TransformLocalPosition;
  133. public Matrix4x4 m_TransformLocalToWorldMatrix;
  134. }
  135. class ParticleTree
  136. {
  137. public Transform m_Root;
  138. public Vector3 m_LocalGravity;
  139. public Matrix4x4 m_RootWorldToLocalMatrix;
  140. public float m_BoneTotalLength;
  141. public List<Particle> m_Particles = new List<Particle>();
  142. // prepare data
  143. public Vector3 m_RestGravity;
  144. }
  145. List<ParticleTree> m_ParticleTrees = new List<ParticleTree>();
  146. // prepare data
  147. float m_DeltaTime;
  148. List<DynamicBoneColliderBase> m_EffectiveColliders;
  149. // multithread
  150. static List<DynamicBone> s_PendingWorks = new List<DynamicBone>();
  151. static List<DynamicBone> s_EffectiveWorks = new List<DynamicBone>();
  152. static AutoResetEvent s_AllWorksDoneEvent;
  153. static int s_RemainWorkCount;
  154. static Semaphore s_WorkQueueSemaphore;
  155. static int s_WorkQueueIndex;
  156. static int s_UpdateCount;
  157. static int s_PrepareFrame;
  158. void Start()
  159. {
  160. SetupParticles();
  161. }
  162. void FixedUpdate()
  163. {
  164. if (m_UpdateMode == UpdateMode.AnimatePhysics)
  165. {
  166. PreUpdate();
  167. }
  168. }
  169. void Update()
  170. {
  171. if (m_UpdateMode != UpdateMode.AnimatePhysics)
  172. {
  173. PreUpdate();
  174. }
  175. if (m_PreUpdateCount > 0 && m_Multithread)
  176. {
  177. AddPendingWork(this);
  178. m_WorkAdded = true;
  179. }
  180. ++s_UpdateCount;
  181. }
  182. void LateUpdate()
  183. {
  184. if (m_PreUpdateCount == 0)
  185. return;
  186. if (s_UpdateCount > 0)
  187. {
  188. s_UpdateCount = 0;
  189. ++s_PrepareFrame;
  190. }
  191. SetWeight(m_BlendWeight);
  192. if (m_WorkAdded)
  193. {
  194. m_WorkAdded = false;
  195. ExecuteWorks();
  196. }
  197. else
  198. {
  199. CheckDistance();
  200. if (IsNeedUpdate())
  201. {
  202. Prepare();
  203. UpdateParticles();
  204. ApplyParticlesToTransforms();
  205. }
  206. }
  207. m_PreUpdateCount = 0;
  208. }
  209. void Prepare()
  210. {
  211. m_DeltaTime = Time.deltaTime;
  212. #if UNITY_5_3_OR_NEWER
  213. if (m_UpdateMode == UpdateMode.UnscaledTime)
  214. {
  215. m_DeltaTime = Time.unscaledDeltaTime;
  216. }
  217. else if (m_UpdateMode == UpdateMode.AnimatePhysics)
  218. {
  219. m_DeltaTime = Time.fixedDeltaTime * m_PreUpdateCount;
  220. }
  221. #endif
  222. m_ObjectScale = Mathf.Abs(transform.lossyScale.x);
  223. m_ObjectMove = transform.position - m_ObjectPrevPosition;
  224. m_ObjectPrevPosition = transform.position;
  225. for (int i = 0; i < m_ParticleTrees.Count; ++i)
  226. {
  227. ParticleTree pt = m_ParticleTrees[i];
  228. pt.m_RestGravity = pt.m_Root.TransformDirection(pt.m_LocalGravity);
  229. for (int j = 0; j < pt.m_Particles.Count; ++j)
  230. {
  231. Particle p = pt.m_Particles[j];
  232. if (p.m_TransformNotNull)
  233. {
  234. p.m_TransformPosition = p.m_Transform.position;
  235. p.m_TransformLocalPosition = p.m_Transform.localPosition;
  236. p.m_TransformLocalToWorldMatrix = p.m_Transform.localToWorldMatrix;
  237. }
  238. }
  239. }
  240. if (m_EffectiveColliders != null)
  241. {
  242. m_EffectiveColliders.Clear();
  243. }
  244. if (m_Colliders != null)
  245. {
  246. for (int i = 0; i < m_Colliders.Count; ++i)
  247. {
  248. DynamicBoneColliderBase c = m_Colliders[i];
  249. if (c != null && c.enabled)
  250. {
  251. if (m_EffectiveColliders == null)
  252. {
  253. m_EffectiveColliders = new List<DynamicBoneColliderBase>();
  254. }
  255. m_EffectiveColliders.Add(c);
  256. if (c.PrepareFrame != s_PrepareFrame) // colliders used by many dynamic bones only prepares once
  257. {
  258. c.Prepare();
  259. c.PrepareFrame = s_PrepareFrame;
  260. }
  261. }
  262. }
  263. }
  264. }
  265. bool IsNeedUpdate()
  266. {
  267. return m_Weight > 0 && !(m_DistantDisable && m_DistantDisabled);
  268. }
  269. void PreUpdate()
  270. {
  271. if (IsNeedUpdate())
  272. {
  273. InitTransforms();
  274. }
  275. ++m_PreUpdateCount;
  276. }
  277. void CheckDistance()
  278. {
  279. if (!m_DistantDisable)
  280. return;
  281. Transform rt = m_ReferenceObject;
  282. if (rt == null && Camera.main != null)
  283. {
  284. rt = Camera.main.transform;
  285. }
  286. if (rt != null)
  287. {
  288. float d2 = (rt.position - transform.position).sqrMagnitude;
  289. bool disable = d2 > m_DistanceToObject * m_DistanceToObject;
  290. if (disable != m_DistantDisabled)
  291. {
  292. if (!disable)
  293. {
  294. ResetParticlesPosition();
  295. }
  296. m_DistantDisabled = disable;
  297. }
  298. }
  299. }
  300. void OnEnable()
  301. {
  302. ResetParticlesPosition();
  303. }
  304. void OnDisable()
  305. {
  306. InitTransforms();
  307. }
  308. void OnValidate()
  309. {
  310. m_UpdateRate = Mathf.Max(m_UpdateRate, 0);
  311. m_Damping = Mathf.Clamp01(m_Damping);
  312. m_Elasticity = Mathf.Clamp01(m_Elasticity);
  313. m_Stiffness = Mathf.Clamp01(m_Stiffness);
  314. m_Inert = Mathf.Clamp01(m_Inert);
  315. m_Friction = Mathf.Clamp01(m_Friction);
  316. m_Radius = Mathf.Max(m_Radius, 0);
  317. if (Application.isEditor && Application.isPlaying)
  318. {
  319. if (IsRootChanged())
  320. {
  321. InitTransforms();
  322. SetupParticles();
  323. }
  324. else
  325. {
  326. UpdateParameters();
  327. }
  328. }
  329. }
  330. bool IsRootChanged()
  331. {
  332. var roots = new List<Transform>();
  333. if (m_Root != null)
  334. {
  335. roots.Add(m_Root);
  336. }
  337. if (m_Roots != null)
  338. {
  339. foreach (var root in m_Roots)
  340. {
  341. if (root != null && !roots.Contains(root))
  342. {
  343. roots.Add(root);
  344. }
  345. }
  346. }
  347. if (roots.Count != m_ParticleTrees.Count)
  348. return true;
  349. for (int i = 0; i < roots.Count; ++i)
  350. {
  351. if (roots[i] != m_ParticleTrees[i].m_Root)
  352. return true;
  353. }
  354. return false;
  355. }
  356. void OnDidApplyAnimationProperties()
  357. {
  358. UpdateParameters();
  359. }
  360. void OnDrawGizmosSelected()
  361. {
  362. if (!enabled)
  363. return;
  364. if (Application.isEditor && !Application.isPlaying && transform.hasChanged)
  365. {
  366. InitTransforms();
  367. SetupParticles();
  368. }
  369. Gizmos.color = Color.white;
  370. for (int i = 0; i < m_ParticleTrees.Count; ++i)
  371. {
  372. DrawGizmos(m_ParticleTrees[i]);
  373. }
  374. }
  375. void DrawGizmos(ParticleTree pt)
  376. {
  377. for (int i = 0; i < pt.m_Particles.Count; ++i)
  378. {
  379. Particle p = pt.m_Particles[i];
  380. if (p.m_ParentIndex >= 0)
  381. {
  382. Particle p0 = pt.m_Particles[p.m_ParentIndex];
  383. Gizmos.DrawLine(p.m_Position, p0.m_Position);
  384. }
  385. if (p.m_Radius > 0)
  386. {
  387. Gizmos.DrawWireSphere(p.m_Position, p.m_Radius * m_ObjectScale);
  388. }
  389. }
  390. }
  391. public void SetWeight(float w)
  392. {
  393. if (m_Weight != w)
  394. {
  395. if (w == 0)
  396. {
  397. InitTransforms();
  398. }
  399. else if (m_Weight == 0)
  400. {
  401. ResetParticlesPosition();
  402. }
  403. m_Weight = m_BlendWeight = w;
  404. }
  405. }
  406. public float GetWeight()
  407. {
  408. return m_Weight;
  409. }
  410. void UpdateParticles()
  411. {
  412. if (m_ParticleTrees.Count <= 0)
  413. return;
  414. int loop = 1;
  415. float timeVar = 1;
  416. float dt = m_DeltaTime;
  417. if (m_UpdateMode == UpdateMode.Default)
  418. {
  419. if (m_UpdateRate > 0)
  420. {
  421. timeVar = dt * m_UpdateRate;
  422. }
  423. }
  424. else
  425. {
  426. if (m_UpdateRate > 0)
  427. {
  428. float frameTime = 1.0f / m_UpdateRate;
  429. m_Time += dt;
  430. loop = 0;
  431. while (m_Time >= frameTime)
  432. {
  433. m_Time -= frameTime;
  434. if (++loop >= 3)
  435. {
  436. m_Time = 0;
  437. break;
  438. }
  439. }
  440. }
  441. }
  442. if (loop > 0)
  443. {
  444. for (int i = 0; i < loop; ++i)
  445. {
  446. UpdateParticles1(timeVar, i);
  447. UpdateParticles2(timeVar);
  448. }
  449. }
  450. else
  451. {
  452. SkipUpdateParticles();
  453. }
  454. }
  455. public void SetupParticles()
  456. {
  457. m_ParticleTrees.Clear();
  458. if (m_Root != null)
  459. {
  460. AppendParticleTree(m_Root);
  461. }
  462. if (m_Roots != null)
  463. {
  464. for (int i = 0; i < m_Roots.Count; ++i)
  465. {
  466. Transform root = m_Roots[i];
  467. if (root == null)
  468. continue;
  469. if (m_ParticleTrees.Exists(x => x.m_Root == root))
  470. continue;
  471. AppendParticleTree(root);
  472. }
  473. }
  474. m_ObjectScale = Mathf.Abs(transform.lossyScale.x);
  475. m_ObjectPrevPosition = transform.position;
  476. m_ObjectMove = Vector3.zero;
  477. for (int i = 0; i < m_ParticleTrees.Count; ++i)
  478. {
  479. ParticleTree pt = m_ParticleTrees[i];
  480. AppendParticles(pt, pt.m_Root, -1, 0);
  481. }
  482. UpdateParameters();
  483. }
  484. void AppendParticleTree(Transform root)
  485. {
  486. if (root == null)
  487. return;
  488. var pt = new ParticleTree();
  489. pt.m_Root = root;
  490. pt.m_RootWorldToLocalMatrix = root.worldToLocalMatrix;
  491. m_ParticleTrees.Add(pt);
  492. }
  493. void AppendParticles(ParticleTree pt, Transform b, int parentIndex, float boneLength)
  494. {
  495. var p = new Particle();
  496. p.m_Transform = b;
  497. p.m_TransformNotNull = b != null;
  498. p.m_ParentIndex = parentIndex;
  499. if (b != null)
  500. {
  501. p.m_Position = p.m_PrevPosition = b.position;
  502. p.m_InitLocalPosition = b.localPosition;
  503. p.m_InitLocalRotation = b.localRotation;
  504. }
  505. else // end bone
  506. {
  507. Transform pb = pt.m_Particles[parentIndex].m_Transform;
  508. if (m_EndLength > 0)
  509. {
  510. Transform ppb = pb.parent;
  511. if (ppb != null)
  512. {
  513. p.m_EndOffset = pb.InverseTransformPoint((pb.position * 2 - ppb.position)) * m_EndLength;
  514. }
  515. else
  516. {
  517. p.m_EndOffset = new Vector3(m_EndLength, 0, 0);
  518. }
  519. }
  520. else
  521. {
  522. p.m_EndOffset = pb.InverseTransformPoint(transform.TransformDirection(m_EndOffset) + pb.position);
  523. }
  524. p.m_Position = p.m_PrevPosition = pb.TransformPoint(p.m_EndOffset);
  525. p.m_InitLocalPosition = Vector3.zero;
  526. p.m_InitLocalRotation = Quaternion.identity;
  527. }
  528. if (parentIndex >= 0)
  529. {
  530. boneLength += (pt.m_Particles[parentIndex].m_Transform.position - p.m_Position).magnitude;
  531. p.m_BoneLength = boneLength;
  532. pt.m_BoneTotalLength = Mathf.Max(pt.m_BoneTotalLength, boneLength);
  533. ++pt.m_Particles[parentIndex].m_ChildCount;
  534. }
  535. int index = pt.m_Particles.Count;
  536. pt.m_Particles.Add(p);
  537. if (b != null)
  538. {
  539. for (int i = 0; i < b.childCount; ++i)
  540. {
  541. Transform child = b.GetChild(i);
  542. bool exclude = false;
  543. if (m_Exclusions != null)
  544. {
  545. exclude = m_Exclusions.Contains(child);
  546. }
  547. if (!exclude)
  548. {
  549. AppendParticles(pt, child, index, boneLength);
  550. }
  551. else if (m_EndLength > 0 || m_EndOffset != Vector3.zero)
  552. {
  553. AppendParticles(pt, null, index, boneLength);
  554. }
  555. }
  556. if (b.childCount == 0 && (m_EndLength > 0 || m_EndOffset != Vector3.zero))
  557. {
  558. AppendParticles(pt, null, index, boneLength);
  559. }
  560. }
  561. }
  562. public void UpdateParameters()
  563. {
  564. SetWeight(m_BlendWeight);
  565. for (int i = 0; i < m_ParticleTrees.Count; ++i)
  566. {
  567. UpdateParameters(m_ParticleTrees[i]);
  568. }
  569. }
  570. void UpdateParameters(ParticleTree pt)
  571. {
  572. // m_LocalGravity = m_Root.InverseTransformDirection(m_Gravity);
  573. pt.m_LocalGravity = pt.m_RootWorldToLocalMatrix.MultiplyVector(m_Gravity).normalized * m_Gravity.magnitude;
  574. for (int i = 0; i < pt.m_Particles.Count; ++i)
  575. {
  576. Particle p = pt.m_Particles[i];
  577. p.m_Damping = m_Damping;
  578. p.m_Elasticity = m_Elasticity;
  579. p.m_Stiffness = m_Stiffness;
  580. p.m_Inert = m_Inert;
  581. p.m_Friction = m_Friction;
  582. p.m_Radius = m_Radius;
  583. if (pt.m_BoneTotalLength > 0)
  584. {
  585. float a = p.m_BoneLength / pt.m_BoneTotalLength;
  586. if (m_DampingDistrib != null && m_DampingDistrib.keys.Length > 0)
  587. p.m_Damping *= m_DampingDistrib.Evaluate(a);
  588. if (m_ElasticityDistrib != null && m_ElasticityDistrib.keys.Length > 0)
  589. p.m_Elasticity *= m_ElasticityDistrib.Evaluate(a);
  590. if (m_StiffnessDistrib != null && m_StiffnessDistrib.keys.Length > 0)
  591. p.m_Stiffness *= m_StiffnessDistrib.Evaluate(a);
  592. if (m_InertDistrib != null && m_InertDistrib.keys.Length > 0)
  593. p.m_Inert *= m_InertDistrib.Evaluate(a);
  594. if (m_FrictionDistrib != null && m_FrictionDistrib.keys.Length > 0)
  595. p.m_Friction *= m_FrictionDistrib.Evaluate(a);
  596. if (m_RadiusDistrib != null && m_RadiusDistrib.keys.Length > 0)
  597. p.m_Radius *= m_RadiusDistrib.Evaluate(a);
  598. }
  599. p.m_Damping = Mathf.Clamp01(p.m_Damping);
  600. p.m_Elasticity = Mathf.Clamp01(p.m_Elasticity);
  601. p.m_Stiffness = Mathf.Clamp01(p.m_Stiffness);
  602. p.m_Inert = Mathf.Clamp01(p.m_Inert);
  603. p.m_Friction = Mathf.Clamp01(p.m_Friction);
  604. p.m_Radius = Mathf.Max(p.m_Radius, 0);
  605. }
  606. }
  607. void InitTransforms()
  608. {
  609. for (int i = 0; i < m_ParticleTrees.Count; ++i)
  610. {
  611. InitTransforms(m_ParticleTrees[i]);
  612. }
  613. }
  614. void InitTransforms(ParticleTree pt)
  615. {
  616. for (int i = 0; i < pt.m_Particles.Count; ++i)
  617. {
  618. Particle p = pt.m_Particles[i];
  619. if (p.m_TransformNotNull)
  620. {
  621. p.m_Transform.localPosition = p.m_InitLocalPosition;
  622. p.m_Transform.localRotation = p.m_InitLocalRotation;
  623. }
  624. }
  625. }
  626. void ResetParticlesPosition()
  627. {
  628. for (int i = 0; i < m_ParticleTrees.Count; ++i)
  629. {
  630. ResetParticlesPosition(m_ParticleTrees[i]);
  631. }
  632. m_ObjectPrevPosition = transform.position;
  633. }
  634. void ResetParticlesPosition(ParticleTree pt)
  635. {
  636. for (int i = 0; i < pt.m_Particles.Count; ++i)
  637. {
  638. Particle p = pt.m_Particles[i];
  639. if (p.m_TransformNotNull)
  640. {
  641. p.m_Position = p.m_PrevPosition = p.m_Transform.position;
  642. }
  643. else // end bone
  644. {
  645. Transform pb = pt.m_Particles[p.m_ParentIndex].m_Transform;
  646. p.m_Position = p.m_PrevPosition = pb.TransformPoint(p.m_EndOffset);
  647. }
  648. p.m_isCollide = false;
  649. }
  650. }
  651. void UpdateParticles1(float timeVar, int loopIndex)
  652. {
  653. for (int i = 0; i < m_ParticleTrees.Count; ++i)
  654. {
  655. UpdateParticles1(m_ParticleTrees[i], timeVar, loopIndex);
  656. }
  657. }
  658. void UpdateParticles1(ParticleTree pt, float timeVar, int loopIndex)
  659. {
  660. Vector3 force = m_Gravity;
  661. Vector3 fdir = m_Gravity.normalized;
  662. Vector3 pf = fdir * Mathf.Max(Vector3.Dot(pt.m_RestGravity, fdir), 0); // project current gravity to rest gravity
  663. force -= pf; // remove projected gravity
  664. force = (force + m_Force) * (m_ObjectScale * timeVar);
  665. Vector3 objectMove = loopIndex == 0 ? m_ObjectMove : Vector3.zero; // only first loop consider object move
  666. for (int i = 0; i < pt.m_Particles.Count; ++i)
  667. {
  668. Particle p = pt.m_Particles[i];
  669. if (p.m_ParentIndex >= 0)
  670. {
  671. // verlet integration
  672. Vector3 v = p.m_Position - p.m_PrevPosition;
  673. Vector3 rmove = objectMove * p.m_Inert;
  674. p.m_PrevPosition = p.m_Position + rmove;
  675. float damping = p.m_Damping;
  676. if (p.m_isCollide)
  677. {
  678. damping += p.m_Friction;
  679. if (damping > 1)
  680. {
  681. damping = 1;
  682. }
  683. p.m_isCollide = false;
  684. }
  685. p.m_Position += v * (1 - damping) + force + rmove;
  686. }
  687. else
  688. {
  689. p.m_PrevPosition = p.m_Position;
  690. p.m_Position = p.m_TransformPosition;
  691. }
  692. }
  693. }
  694. void UpdateParticles2(float timeVar)
  695. {
  696. for (int i = 0; i < m_ParticleTrees.Count; ++i)
  697. {
  698. UpdateParticles2(m_ParticleTrees[i], timeVar);
  699. }
  700. }
  701. void UpdateParticles2(ParticleTree pt, float timeVar)
  702. {
  703. var movePlane = new Plane();
  704. for (int i = 1; i < pt.m_Particles.Count; ++i)
  705. {
  706. Particle p = pt.m_Particles[i];
  707. Particle p0 = pt.m_Particles[p.m_ParentIndex];
  708. float restLen;
  709. if (p.m_TransformNotNull)
  710. {
  711. restLen = (p0.m_TransformPosition - p.m_TransformPosition).magnitude;
  712. }
  713. else
  714. {
  715. restLen = p0.m_TransformLocalToWorldMatrix.MultiplyVector(p.m_EndOffset).magnitude;
  716. }
  717. // keep shape
  718. float stiffness = Mathf.Lerp(1.0f, p.m_Stiffness, m_Weight);
  719. if (stiffness > 0 || p.m_Elasticity > 0)
  720. {
  721. Matrix4x4 m0 = p0.m_TransformLocalToWorldMatrix;
  722. m0.SetColumn(3, p0.m_Position);
  723. Vector3 restPos;
  724. if (p.m_TransformNotNull)
  725. {
  726. restPos = m0.MultiplyPoint3x4(p.m_TransformLocalPosition);
  727. }
  728. else
  729. {
  730. restPos = m0.MultiplyPoint3x4(p.m_EndOffset);
  731. }
  732. Vector3 d = restPos - p.m_Position;
  733. p.m_Position += d * (p.m_Elasticity * timeVar);
  734. if (stiffness > 0)
  735. {
  736. d = restPos - p.m_Position;
  737. float len = d.magnitude;
  738. float maxlen = restLen * (1 - stiffness) * 2;
  739. if (len > maxlen)
  740. {
  741. p.m_Position += d * ((len - maxlen) / len);
  742. }
  743. }
  744. }
  745. // collide
  746. if (m_EffectiveColliders != null)
  747. {
  748. float particleRadius = p.m_Radius * m_ObjectScale;
  749. for (int j = 0; j < m_EffectiveColliders.Count; ++j)
  750. {
  751. DynamicBoneColliderBase c = m_EffectiveColliders[j];
  752. p.m_isCollide |= c.Collide(ref p.m_Position, particleRadius);
  753. }
  754. }
  755. // freeze axis, project to plane
  756. if (m_FreezeAxis != FreezeAxis.None)
  757. {
  758. Vector3 planeNormal = p0.m_TransformLocalToWorldMatrix.GetColumn((int)m_FreezeAxis - 1).normalized;
  759. movePlane.SetNormalAndPosition(planeNormal, p0.m_Position);
  760. p.m_Position -= movePlane.normal * movePlane.GetDistanceToPoint(p.m_Position);
  761. }
  762. // keep length
  763. Vector3 dd = p0.m_Position - p.m_Position;
  764. float leng = dd.magnitude;
  765. if (leng > 0)
  766. {
  767. p.m_Position += dd * ((leng - restLen) / leng);
  768. }
  769. }
  770. }
  771. void SkipUpdateParticles()
  772. {
  773. for (int i = 0; i < m_ParticleTrees.Count; ++i)
  774. {
  775. SkipUpdateParticles(m_ParticleTrees[i]);
  776. }
  777. }
  778. // only update stiffness and keep bone length
  779. void SkipUpdateParticles(ParticleTree pt)
  780. {
  781. for (int i = 0; i < pt.m_Particles.Count; ++i)
  782. {
  783. Particle p = pt.m_Particles[i];
  784. if (p.m_ParentIndex >= 0)
  785. {
  786. p.m_PrevPosition += m_ObjectMove;
  787. p.m_Position += m_ObjectMove;
  788. Particle p0 = pt.m_Particles[p.m_ParentIndex];
  789. float restLen;
  790. if (p.m_TransformNotNull)
  791. {
  792. restLen = (p0.m_TransformPosition - p.m_TransformPosition).magnitude;
  793. }
  794. else
  795. {
  796. restLen = p0.m_TransformLocalToWorldMatrix.MultiplyVector(p.m_EndOffset).magnitude;
  797. }
  798. // keep shape
  799. float stiffness = Mathf.Lerp(1.0f, p.m_Stiffness, m_Weight);
  800. if (stiffness > 0)
  801. {
  802. Matrix4x4 m0 = p0.m_TransformLocalToWorldMatrix;
  803. m0.SetColumn(3, p0.m_Position);
  804. Vector3 restPos;
  805. if (p.m_TransformNotNull)
  806. {
  807. restPos = m0.MultiplyPoint3x4(p.m_TransformLocalPosition);
  808. }
  809. else
  810. {
  811. restPos = m0.MultiplyPoint3x4(p.m_EndOffset);
  812. }
  813. Vector3 d = restPos - p.m_Position;
  814. float len = d.magnitude;
  815. float maxlen = restLen * (1 - stiffness) * 2;
  816. if (len > maxlen)
  817. {
  818. p.m_Position += d * ((len - maxlen) / len);
  819. }
  820. }
  821. // keep length
  822. Vector3 dd = p0.m_Position - p.m_Position;
  823. float leng = dd.magnitude;
  824. if (leng > 0)
  825. {
  826. p.m_Position += dd * ((leng - restLen) / leng);
  827. }
  828. }
  829. else
  830. {
  831. p.m_PrevPosition = p.m_Position;
  832. p.m_Position = p.m_TransformPosition;
  833. }
  834. }
  835. }
  836. static Vector3 MirrorVector(Vector3 v, Vector3 axis)
  837. {
  838. return v - axis * (Vector3.Dot(v, axis) * 2);
  839. }
  840. void ApplyParticlesToTransforms()
  841. {
  842. Vector3 ax = Vector3.right;
  843. Vector3 ay = Vector3.up;
  844. Vector3 az = Vector3.forward;
  845. bool nx = false, ny = false, nz = false;
  846. #if !UNITY_5_4_OR_NEWER
  847. // detect negative scale
  848. Vector3 lossyScale = transform.lossyScale;
  849. if (lossyScale.x < 0 || lossyScale.y < 0 || lossyScale.z < 0)
  850. {
  851. Transform mirrorObject = transform;
  852. do
  853. {
  854. Vector3 ls = mirrorObject.localScale;
  855. nx = ls.x < 0;
  856. if (nx)
  857. ax = mirrorObject.right;
  858. ny = ls.y < 0;
  859. if (ny)
  860. ay = mirrorObject.up;
  861. nz = ls.z < 0;
  862. if (nz)
  863. az = mirrorObject.forward;
  864. if (nx || ny || nz)
  865. break;
  866. mirrorObject = mirrorObject.parent;
  867. }
  868. while (mirrorObject != null);
  869. }
  870. #endif
  871. for (int i = 0; i < m_ParticleTrees.Count; ++i)
  872. {
  873. ApplyParticlesToTransforms(m_ParticleTrees[i], ax, ay, az, nx, ny, nz);
  874. }
  875. }
  876. void ApplyParticlesToTransforms(ParticleTree pt, Vector3 ax, Vector3 ay, Vector3 az, bool nx, bool ny, bool nz)
  877. {
  878. for (int i = 1; i < pt.m_Particles.Count; ++i)
  879. {
  880. Particle p = pt.m_Particles[i];
  881. Particle p0 = pt.m_Particles[p.m_ParentIndex];
  882. if (p0.m_ChildCount <= 1) // do not modify bone orientation if has more then one child
  883. {
  884. Vector3 localPos;
  885. if (p.m_TransformNotNull)
  886. {
  887. localPos = p.m_Transform.localPosition;
  888. }
  889. else
  890. {
  891. localPos = p.m_EndOffset;
  892. }
  893. Vector3 v0 = p0.m_Transform.TransformDirection(localPos);
  894. Vector3 v1 = p.m_Position - p0.m_Position;
  895. #if !UNITY_5_4_OR_NEWER
  896. if (nx)
  897. v1 = MirrorVector(v1, ax);
  898. if (ny)
  899. v1 = MirrorVector(v1, ay);
  900. if (nz)
  901. v1 = MirrorVector(v1, az);
  902. #endif
  903. Quaternion rot = Quaternion.FromToRotation(v0, v1);
  904. p0.m_Transform.rotation = rot * p0.m_Transform.rotation;
  905. }
  906. if (p.m_TransformNotNull)
  907. {
  908. p.m_Transform.position = p.m_Position;
  909. }
  910. }
  911. }
  912. static void AddPendingWork(DynamicBone db)
  913. {
  914. s_PendingWorks.Add(db);
  915. }
  916. static void AddWorkToQueue(DynamicBone db)
  917. {
  918. s_WorkQueueSemaphore.Release();
  919. }
  920. static DynamicBone GetWorkFromQueue()
  921. {
  922. int idx = Interlocked.Increment(ref s_WorkQueueIndex);
  923. return s_EffectiveWorks[idx];
  924. }
  925. static void ThreadProc()
  926. {
  927. while (true)
  928. {
  929. s_WorkQueueSemaphore.WaitOne();
  930. DynamicBone db = GetWorkFromQueue();
  931. db.UpdateParticles();
  932. if (Interlocked.Decrement(ref s_RemainWorkCount) <= 0)
  933. {
  934. s_AllWorksDoneEvent.Set();
  935. }
  936. }
  937. }
  938. static void InitThreadPool()
  939. {
  940. s_AllWorksDoneEvent = new AutoResetEvent(false);
  941. s_WorkQueueSemaphore = new Semaphore(0, int.MaxValue);
  942. int threadCount = System.Environment.ProcessorCount;
  943. for (int i = 0; i < threadCount; ++i)
  944. {
  945. var t = new Thread(ThreadProc);
  946. t.IsBackground = true;
  947. t.Start();
  948. }
  949. }
  950. static void ExecuteWorks()
  951. {
  952. if (s_PendingWorks.Count <= 0)
  953. return;
  954. s_EffectiveWorks.Clear();
  955. for (int i = 0; i < s_PendingWorks.Count; ++i)
  956. {
  957. DynamicBone db = s_PendingWorks[i];
  958. if (db != null && db.enabled)
  959. {
  960. db.CheckDistance();
  961. if (db.IsNeedUpdate())
  962. {
  963. s_EffectiveWorks.Add(db);
  964. }
  965. }
  966. }
  967. s_PendingWorks.Clear();
  968. if (s_EffectiveWorks.Count <= 0)
  969. return;
  970. if (s_AllWorksDoneEvent == null)
  971. {
  972. InitThreadPool();
  973. }
  974. int workCount = s_RemainWorkCount = s_EffectiveWorks.Count;
  975. s_WorkQueueIndex = -1;
  976. for (int i = 0; i < workCount; ++i)
  977. {
  978. DynamicBone db = s_EffectiveWorks[i];
  979. db.Prepare();
  980. AddWorkToQueue(db);
  981. }
  982. s_AllWorksDoneEvent.WaitOne();
  983. for (int i = 0; i < workCount; ++i)
  984. {
  985. DynamicBone db = s_EffectiveWorks[i];
  986. db.ApplyParticlesToTransforms();
  987. }
  988. }
  989. }