源战役客户端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

682 lines
21 KiB

  1. using UnityEngine;
  2. using System.Collections.Generic;
  3. [AddComponentMenu("Dynamic Bone/Dynamic Bone")]
  4. public class DynamicBone : MonoBehaviour
  5. {
  6. #if UNITY_5
  7. [Tooltip("The root of the transform hierarchy to apply physics.")]
  8. #endif
  9. public Transform m_Root = null;
  10. #if UNITY_5
  11. [Tooltip("Internal physics simulation rate.")]
  12. #endif
  13. public float m_UpdateRate = 60.0f;
  14. public enum UpdateMode
  15. {
  16. Normal,
  17. AnimatePhysics,
  18. UnscaledTime
  19. }
  20. public UpdateMode m_UpdateMode = UpdateMode.Normal;
  21. #if UNITY_5
  22. [Tooltip("How much the bones slowed down.")]
  23. #endif
  24. [Range(0, 1)]
  25. public float m_Damping = 0.1f;
  26. public AnimationCurve m_DampingDistrib = null;
  27. #if UNITY_5
  28. [Tooltip("How much the force applied to return each bone to original orientation.")]
  29. #endif
  30. [Range(0, 1)]
  31. public float m_Elasticity = 0.1f;
  32. public AnimationCurve m_ElasticityDistrib = null;
  33. #if UNITY_5
  34. [Tooltip("How much bone's original orientation are preserved.")]
  35. #endif
  36. [Range(0, 1)]
  37. public float m_Stiffness = 0.1f;
  38. public AnimationCurve m_StiffnessDistrib = null;
  39. #if UNITY_5
  40. [Tooltip("How much character's position change is ignored in physics simulation.")]
  41. #endif
  42. [Range(0, 1)]
  43. public float m_Inert = 0;
  44. public AnimationCurve m_InertDistrib = null;
  45. #if UNITY_5
  46. [Tooltip("Each bone can be a sphere to collide with colliders. Radius describe sphere's size.")]
  47. #endif
  48. public float m_Radius = 0;
  49. public AnimationCurve m_RadiusDistrib = null;
  50. #if UNITY_5
  51. [Tooltip("If End Length is not zero, an extra bone is generated at the end of transform hierarchy.")]
  52. #endif
  53. public float m_EndLength = 0;
  54. #if UNITY_5
  55. [Tooltip("If End Offset is not zero, an extra bone is generated at the end of transform hierarchy.")]
  56. #endif
  57. public Vector3 m_EndOffset = Vector3.zero;
  58. #if UNITY_5
  59. [Tooltip("The force apply to bones. Partial force apply to character's initial pose is cancelled out.")]
  60. #endif
  61. public Vector3 m_Gravity = Vector3.zero;
  62. #if UNITY_5
  63. [Tooltip("The force apply to bones.")]
  64. #endif
  65. public Vector3 m_Force = Vector3.zero;
  66. #if UNITY_5
  67. [Tooltip("Collider objects interact with the bones.")]
  68. #endif
  69. public List<DynamicBoneColliderBase> m_Colliders = null;
  70. #if UNITY_5
  71. [Tooltip("Bones exclude from physics simulation.")]
  72. #endif
  73. public List<Transform> m_Exclusions = null;
  74. public enum FreezeAxis
  75. {
  76. None, X, Y, Z
  77. }
  78. #if UNITY_5
  79. [Tooltip("Constrain bones to move on specified plane.")]
  80. #endif
  81. public FreezeAxis m_FreezeAxis = FreezeAxis.None;
  82. #if UNITY_5
  83. [Tooltip("Disable physics simulation automatically if character is far from camera or player.")]
  84. #endif
  85. public bool m_DistantDisable = false;
  86. public Transform m_ReferenceObject = null;
  87. public float m_DistanceToObject = 20;
  88. Vector3 m_LocalGravity = Vector3.zero;
  89. Vector3 m_ObjectMove = Vector3.zero;
  90. Vector3 m_ObjectPrevPosition = Vector3.zero;
  91. float m_BoneTotalLength = 0;
  92. float m_ObjectScale = 1.0f;
  93. float m_Time = 0;
  94. float m_Weight = 1.0f;
  95. bool m_DistantDisabled = false;
  96. class Particle
  97. {
  98. public Transform m_Transform = null;
  99. public int m_ParentIndex = -1;
  100. public float m_Damping = 0;
  101. public float m_Elasticity = 0;
  102. public float m_Stiffness = 0;
  103. public float m_Inert = 0;
  104. public float m_Radius = 0;
  105. public float m_BoneLength = 0;
  106. public Vector3 m_Position = Vector3.zero;
  107. public Vector3 m_PrevPosition = Vector3.zero;
  108. public Vector3 m_EndOffset = Vector3.zero;
  109. public Vector3 m_InitLocalPosition = Vector3.zero;
  110. public Quaternion m_InitLocalRotation = Quaternion.identity;
  111. }
  112. List<Particle> m_Particles = new List<Particle>();
  113. void Start()
  114. {
  115. SetupParticles();
  116. }
  117. void FixedUpdate()
  118. {
  119. if (m_UpdateMode == UpdateMode.AnimatePhysics)
  120. PreUpdate();
  121. }
  122. void Update()
  123. {
  124. if (m_UpdateMode != UpdateMode.AnimatePhysics)
  125. PreUpdate();
  126. }
  127. void LateUpdate()
  128. {
  129. if (m_DistantDisable)
  130. CheckDistance();
  131. if (m_Weight > 0 && !(m_DistantDisable && m_DistantDisabled))
  132. {
  133. #if UNITY_5
  134. float dt = m_UpdateMode == UpdateMode.UnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime;
  135. #else
  136. float dt = Time.deltaTime;
  137. #endif
  138. UpdateDynamicBones(dt);
  139. }
  140. }
  141. void PreUpdate()
  142. {
  143. if (m_Weight > 0 && !(m_DistantDisable && m_DistantDisabled))
  144. InitTransforms();
  145. }
  146. void CheckDistance()
  147. {
  148. Transform rt = m_ReferenceObject;
  149. if (rt == null && Camera.main != null)
  150. rt = Camera.main.transform;
  151. if (rt != null)
  152. {
  153. float d = (rt.position - transform.position).sqrMagnitude;
  154. bool disable = d > m_DistanceToObject * m_DistanceToObject;
  155. if (disable != m_DistantDisabled)
  156. {
  157. if (!disable)
  158. ResetParticlesPosition();
  159. m_DistantDisabled = disable;
  160. }
  161. }
  162. }
  163. void OnEnable()
  164. {
  165. ResetParticlesPosition();
  166. }
  167. void OnDisable()
  168. {
  169. InitTransforms();
  170. }
  171. void OnValidate()
  172. {
  173. m_UpdateRate = Mathf.Max(m_UpdateRate, 0);
  174. m_Damping = Mathf.Clamp01(m_Damping);
  175. m_Elasticity = Mathf.Clamp01(m_Elasticity);
  176. m_Stiffness = Mathf.Clamp01(m_Stiffness);
  177. m_Inert = Mathf.Clamp01(m_Inert);
  178. m_Radius = Mathf.Max(m_Radius, 0);
  179. if (Application.isEditor && Application.isPlaying)
  180. {
  181. InitTransforms();
  182. SetupParticles();
  183. }
  184. }
  185. void OnDrawGizmosSelected()
  186. {
  187. if (!enabled || m_Root == null)
  188. return;
  189. if (Application.isEditor && !Application.isPlaying && transform.hasChanged)
  190. {
  191. InitTransforms();
  192. SetupParticles();
  193. }
  194. Gizmos.color = Color.white;
  195. for (int i = 0; i < m_Particles.Count; ++i)
  196. {
  197. Particle p = m_Particles[i];
  198. if (p.m_ParentIndex >= 0)
  199. {
  200. Particle p0 = m_Particles[p.m_ParentIndex];
  201. Gizmos.DrawLine(p.m_Position, p0.m_Position);
  202. }
  203. if (p.m_Radius > 0)
  204. Gizmos.DrawWireSphere(p.m_Position, p.m_Radius * m_ObjectScale);
  205. }
  206. }
  207. public void SetWeight(float w)
  208. {
  209. if (m_Weight != w)
  210. {
  211. if (w == 0)
  212. InitTransforms();
  213. else if (m_Weight == 0)
  214. ResetParticlesPosition();
  215. m_Weight = w;
  216. }
  217. }
  218. public float GetWeight()
  219. {
  220. return m_Weight;
  221. }
  222. void UpdateDynamicBones(float t)
  223. {
  224. if (m_Root == null)
  225. return;
  226. m_ObjectScale = Mathf.Abs(transform.lossyScale.x);
  227. m_ObjectMove = transform.position - m_ObjectPrevPosition;
  228. m_ObjectPrevPosition = transform.position;
  229. int loop = 1;
  230. if (m_UpdateRate > 0)
  231. {
  232. float dt = 1.0f / m_UpdateRate;
  233. m_Time += t;
  234. loop = 0;
  235. while (m_Time >= dt)
  236. {
  237. m_Time -= dt;
  238. if (++loop >= 3)
  239. {
  240. m_Time = 0;
  241. break;
  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. ApplyParticlesToTransforms();
  259. }
  260. void SetupParticles()
  261. {
  262. m_Particles.Clear();
  263. if (m_Root == null)
  264. return;
  265. m_LocalGravity = m_Root.InverseTransformDirection(m_Gravity);
  266. m_ObjectScale = Mathf.Abs(transform.lossyScale.x);
  267. m_ObjectPrevPosition = transform.position;
  268. m_ObjectMove = Vector3.zero;
  269. m_BoneTotalLength = 0;
  270. AppendParticles(m_Root, -1, 0);
  271. UpdateParameters();
  272. }
  273. void AppendParticles(Transform b, int parentIndex, float boneLength)
  274. {
  275. Particle p = new Particle();
  276. p.m_Transform = b;
  277. p.m_ParentIndex = parentIndex;
  278. if (b != null)
  279. {
  280. p.m_Position = p.m_PrevPosition = b.position;
  281. p.m_InitLocalPosition = b.localPosition;
  282. p.m_InitLocalRotation = b.localRotation;
  283. }
  284. else // end bone
  285. {
  286. Transform pb = m_Particles[parentIndex].m_Transform;
  287. if (m_EndLength > 0)
  288. {
  289. Transform ppb = pb.parent;
  290. if (ppb != null)
  291. p.m_EndOffset = pb.InverseTransformPoint((pb.position * 2 - ppb.position)) * m_EndLength;
  292. else
  293. p.m_EndOffset = new Vector3(m_EndLength, 0, 0);
  294. }
  295. else
  296. {
  297. p.m_EndOffset = pb.InverseTransformPoint(transform.TransformDirection(m_EndOffset) + pb.position);
  298. }
  299. p.m_Position = p.m_PrevPosition = pb.TransformPoint(p.m_EndOffset);
  300. }
  301. if (parentIndex >= 0)
  302. {
  303. boneLength += (m_Particles[parentIndex].m_Transform.position - p.m_Position).magnitude;
  304. p.m_BoneLength = boneLength;
  305. m_BoneTotalLength = Mathf.Max(m_BoneTotalLength, boneLength);
  306. }
  307. int index = m_Particles.Count;
  308. m_Particles.Add(p);
  309. if (b != null)
  310. {
  311. for (int i = 0; i < b.childCount; ++i)
  312. {
  313. bool exclude = false;
  314. if (m_Exclusions != null)
  315. {
  316. for (int j = 0; j < m_Exclusions.Count; ++j)
  317. {
  318. Transform e = m_Exclusions[j];
  319. if (e == b.GetChild(i))
  320. {
  321. exclude = true;
  322. break;
  323. }
  324. }
  325. }
  326. if (!exclude)
  327. AppendParticles(b.GetChild(i), index, boneLength);
  328. else if (m_EndLength > 0 || m_EndOffset != Vector3.zero)
  329. AppendParticles(null, index, boneLength);
  330. }
  331. if (b.childCount == 0 && (m_EndLength > 0 || m_EndOffset != Vector3.zero))
  332. AppendParticles(null, index, boneLength);
  333. }
  334. }
  335. public void UpdateParameters()
  336. {
  337. if (m_Root == null)
  338. return;
  339. m_LocalGravity = m_Root.InverseTransformDirection(m_Gravity);
  340. for (int i = 0; i < m_Particles.Count; ++i)
  341. {
  342. Particle p = m_Particles[i];
  343. p.m_Damping = m_Damping;
  344. p.m_Elasticity = m_Elasticity;
  345. p.m_Stiffness = m_Stiffness;
  346. p.m_Inert = m_Inert;
  347. p.m_Radius = m_Radius;
  348. if (m_BoneTotalLength > 0)
  349. {
  350. float a = p.m_BoneLength / m_BoneTotalLength;
  351. if (m_DampingDistrib != null && m_DampingDistrib.keys.Length > 0)
  352. p.m_Damping *= m_DampingDistrib.Evaluate(a);
  353. if (m_ElasticityDistrib != null && m_ElasticityDistrib.keys.Length > 0)
  354. p.m_Elasticity *= m_ElasticityDistrib.Evaluate(a);
  355. if (m_StiffnessDistrib != null && m_StiffnessDistrib.keys.Length > 0)
  356. p.m_Stiffness *= m_StiffnessDistrib.Evaluate(a);
  357. if (m_InertDistrib != null && m_InertDistrib.keys.Length > 0)
  358. p.m_Inert *= m_InertDistrib.Evaluate(a);
  359. if (m_RadiusDistrib != null && m_RadiusDistrib.keys.Length > 0)
  360. p.m_Radius *= m_RadiusDistrib.Evaluate(a);
  361. }
  362. p.m_Damping = Mathf.Clamp01(p.m_Damping);
  363. p.m_Elasticity = Mathf.Clamp01(p.m_Elasticity);
  364. p.m_Stiffness = Mathf.Clamp01(p.m_Stiffness);
  365. p.m_Inert = Mathf.Clamp01(p.m_Inert);
  366. p.m_Radius = Mathf.Max(p.m_Radius, 0);
  367. }
  368. }
  369. void InitTransforms()
  370. {
  371. for (int i = 0; i < m_Particles.Count; ++i)
  372. {
  373. Particle p = m_Particles[i];
  374. if (p.m_Transform != null)
  375. {
  376. p.m_Transform.localPosition = p.m_InitLocalPosition;
  377. p.m_Transform.localRotation = p.m_InitLocalRotation;
  378. }
  379. }
  380. }
  381. void ResetParticlesPosition()
  382. {
  383. for (int i = 0; i < m_Particles.Count; ++i)
  384. {
  385. Particle p = m_Particles[i];
  386. if (p.m_Transform != null)
  387. {
  388. p.m_Position = p.m_PrevPosition = p.m_Transform.position;
  389. }
  390. else // end bone
  391. {
  392. Transform pb = m_Particles[p.m_ParentIndex].m_Transform;
  393. p.m_Position = p.m_PrevPosition = pb.TransformPoint(p.m_EndOffset);
  394. }
  395. }
  396. m_ObjectPrevPosition = transform.position;
  397. }
  398. void UpdateParticles1()
  399. {
  400. Vector3 force = m_Gravity;
  401. Vector3 fdir = m_Gravity.normalized;
  402. Vector3 rf = m_Root.TransformDirection(m_LocalGravity);
  403. Vector3 pf = fdir * Mathf.Max(Vector3.Dot(rf, fdir), 0); // project current gravity to rest gravity
  404. force -= pf; // remove projected gravity
  405. force = (force + m_Force) * m_ObjectScale;
  406. for (int i = 0; i < m_Particles.Count; ++i)
  407. {
  408. Particle p = m_Particles[i];
  409. if (p.m_ParentIndex >= 0)
  410. {
  411. // verlet integration
  412. Vector3 v = p.m_Position - p.m_PrevPosition;
  413. Vector3 rmove = m_ObjectMove * p.m_Inert;
  414. p.m_PrevPosition = p.m_Position + rmove;
  415. p.m_Position += v * (1 - p.m_Damping) + force + rmove;
  416. }
  417. else
  418. {
  419. p.m_PrevPosition = p.m_Position;
  420. p.m_Position = p.m_Transform.position;
  421. }
  422. }
  423. }
  424. void UpdateParticles2()
  425. {
  426. Plane movePlane = new Plane();
  427. for (int i = 1; i < m_Particles.Count; ++i)
  428. {
  429. Particle p = m_Particles[i];
  430. Particle p0 = m_Particles[p.m_ParentIndex];
  431. float restLen;
  432. if (p.m_Transform != null)
  433. restLen = (p0.m_Transform.position - p.m_Transform.position).magnitude;
  434. else
  435. restLen = p0.m_Transform.localToWorldMatrix.MultiplyVector(p.m_EndOffset).magnitude;
  436. // keep shape
  437. float stiffness = Mathf.Lerp(1.0f, p.m_Stiffness, m_Weight);
  438. if (stiffness > 0 || p.m_Elasticity > 0)
  439. {
  440. Matrix4x4 m0 = p0.m_Transform.localToWorldMatrix;
  441. m0.SetColumn(3, p0.m_Position);
  442. Vector3 restPos;
  443. if (p.m_Transform != null)
  444. restPos = m0.MultiplyPoint3x4(p.m_Transform.localPosition);
  445. else
  446. restPos = m0.MultiplyPoint3x4(p.m_EndOffset);
  447. Vector3 d = restPos - p.m_Position;
  448. p.m_Position += d * p.m_Elasticity;
  449. if (stiffness > 0)
  450. {
  451. d = restPos - p.m_Position;
  452. float len = d.magnitude;
  453. float maxlen = restLen * (1 - stiffness) * 2;
  454. if (len > maxlen)
  455. p.m_Position += d * ((len - maxlen) / len);
  456. }
  457. }
  458. // collide
  459. if (m_Colliders != null)
  460. {
  461. float particleRadius = p.m_Radius * m_ObjectScale;
  462. for (int j = 0; j < m_Colliders.Count; ++j)
  463. {
  464. DynamicBoneColliderBase c = m_Colliders[j];
  465. if (c != null && c.enabled)
  466. c.Collide(ref p.m_Position, particleRadius);
  467. }
  468. }
  469. // freeze axis, project to plane
  470. if (m_FreezeAxis != FreezeAxis.None)
  471. {
  472. switch (m_FreezeAxis)
  473. {
  474. case FreezeAxis.X:
  475. movePlane.SetNormalAndPosition(p0.m_Transform.right, p0.m_Position);
  476. break;
  477. case FreezeAxis.Y:
  478. movePlane.SetNormalAndPosition(p0.m_Transform.up, p0.m_Position);
  479. break;
  480. case FreezeAxis.Z:
  481. movePlane.SetNormalAndPosition(p0.m_Transform.forward, p0.m_Position);
  482. break;
  483. }
  484. p.m_Position -= movePlane.normal * movePlane.GetDistanceToPoint(p.m_Position);
  485. }
  486. // keep length
  487. Vector3 dd = p0.m_Position - p.m_Position;
  488. float leng = dd.magnitude;
  489. if (leng > 0)
  490. p.m_Position += dd * ((leng - restLen) / leng);
  491. }
  492. }
  493. // only update stiffness and keep bone length
  494. void SkipUpdateParticles()
  495. {
  496. for (int i = 0; i < m_Particles.Count; ++i)
  497. {
  498. Particle p = m_Particles[i];
  499. if (p.m_ParentIndex >= 0)
  500. {
  501. p.m_PrevPosition += m_ObjectMove;
  502. p.m_Position += m_ObjectMove;
  503. Particle p0 = m_Particles[p.m_ParentIndex];
  504. float restLen;
  505. if (p.m_Transform != null)
  506. restLen = (p0.m_Transform.position - p.m_Transform.position).magnitude;
  507. else
  508. restLen = p0.m_Transform.localToWorldMatrix.MultiplyVector(p.m_EndOffset).magnitude;
  509. // keep shape
  510. float stiffness = Mathf.Lerp(1.0f, p.m_Stiffness, m_Weight);
  511. if (stiffness > 0)
  512. {
  513. Matrix4x4 m0 = p0.m_Transform.localToWorldMatrix;
  514. m0.SetColumn(3, p0.m_Position);
  515. Vector3 restPos;
  516. if (p.m_Transform != null)
  517. restPos = m0.MultiplyPoint3x4(p.m_Transform.localPosition);
  518. else
  519. restPos = m0.MultiplyPoint3x4(p.m_EndOffset);
  520. Vector3 d = restPos - p.m_Position;
  521. float len = d.magnitude;
  522. float maxlen = restLen * (1 - stiffness) * 2;
  523. if (len > maxlen)
  524. p.m_Position += d * ((len - maxlen) / len);
  525. }
  526. // keep length
  527. Vector3 dd = p0.m_Position - p.m_Position;
  528. float leng = dd.magnitude;
  529. if (leng > 0)
  530. p.m_Position += dd * ((leng - restLen) / leng);
  531. }
  532. else
  533. {
  534. p.m_PrevPosition = p.m_Position;
  535. p.m_Position = p.m_Transform.position;
  536. }
  537. }
  538. }
  539. static Vector3 MirrorVector(Vector3 v, Vector3 axis)
  540. {
  541. return v - axis * (Vector3.Dot(v, axis) * 2);
  542. }
  543. void ApplyParticlesToTransforms()
  544. {
  545. #if !UNITY_5_4_OR_NEWER
  546. // detect negative scale
  547. Vector3 ax = Vector3.right;
  548. Vector3 ay = Vector3.up;
  549. Vector3 az = Vector3.forward;
  550. bool nx = false, ny = false, nz = false;
  551. Vector3 loosyScale = transform.lossyScale;
  552. if (loosyScale.x < 0 || loosyScale.y < 0 || loosyScale.z < 0)
  553. {
  554. Transform mirrorObject = transform;
  555. do
  556. {
  557. Vector3 ls = mirrorObject.localScale;
  558. nx = ls.x < 0;
  559. if (nx)
  560. ax = mirrorObject.right;
  561. ny = ls.y < 0;
  562. if (ny)
  563. ay = mirrorObject.up;
  564. nz = ls.z < 0;
  565. if (nz)
  566. az = mirrorObject.forward;
  567. if (nx || ny || nz)
  568. break;
  569. mirrorObject = mirrorObject.parent;
  570. }
  571. while (mirrorObject != null);
  572. }
  573. #endif
  574. for (int i = 1; i < m_Particles.Count; ++i)
  575. {
  576. Particle p = m_Particles[i];
  577. Particle p0 = m_Particles[p.m_ParentIndex];
  578. if (p0.m_Transform.childCount <= 1) // do not modify bone orientation if has more then one child
  579. {
  580. Vector3 v;
  581. if (p.m_Transform != null)
  582. v = p.m_Transform.localPosition;
  583. else
  584. v = p.m_EndOffset;
  585. Vector3 v2 = p.m_Position - p0.m_Position;
  586. #if !UNITY_5_4_OR_NEWER
  587. if (nx)
  588. v2 = MirrorVector(v2, ax);
  589. if (ny)
  590. v2 = MirrorVector(v2, ay);
  591. if (nz)
  592. v2 = MirrorVector(v2, az);
  593. #endif
  594. Quaternion rot = Quaternion.FromToRotation(p0.m_Transform.TransformDirection(v), v2);
  595. p0.m_Transform.rotation = rot * p0.m_Transform.rotation;
  596. }
  597. if (p.m_Transform != null)
  598. p.m_Transform.position = p.m_Position;
  599. }
  600. }
  601. }