123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235 |
- using UnityEngine;
- [AddComponentMenu("Dynamic Bone/Dynamic Bone Collider")]
- public class DynamicBoneCollider : DynamicBoneColliderBase
- {
- #if UNITY_5_3_OR_NEWER
- [Tooltip("The radius of the sphere or capsule.")]
- #endif
- public float m_Radius = 0.5f;
-
- #if UNITY_5_3_OR_NEWER
- [Tooltip("The height of the capsule.")]
- #endif
- public float m_Height = 0;
- void OnValidate()
- {
- m_Radius = Mathf.Max(m_Radius, 0);
- m_Height = Mathf.Max(m_Height, 0);
- }
- public override bool Collide(ref Vector3 particlePosition, float particleRadius)
- {
- float radius = m_Radius * Mathf.Abs(transform.lossyScale.x);
- float h = m_Height * 0.5f - m_Radius;
- if (h <= 0)
- {
- if (m_Bound == Bound.Outside)
- return OutsideSphere(ref particlePosition, particleRadius, transform.TransformPoint(m_Center), radius);
- else
- return InsideSphere(ref particlePosition, particleRadius, transform.TransformPoint(m_Center), radius);
- }
- else
- {
- Vector3 c0 = m_Center;
- Vector3 c1 = m_Center;
- switch (m_Direction)
- {
- case Direction.X:
- c0.x -= h;
- c1.x += h;
- break;
- case Direction.Y:
- c0.y -= h;
- c1.y += h;
- break;
- case Direction.Z:
- c0.z -= h;
- c1.z += h;
- break;
- }
- if (m_Bound == Bound.Outside)
- return OutsideCapsule(ref particlePosition, particleRadius, transform.TransformPoint(c0), transform.TransformPoint(c1), radius);
- else
- return InsideCapsule(ref particlePosition, particleRadius, transform.TransformPoint(c0), transform.TransformPoint(c1), radius);
- }
- }
- static bool OutsideSphere(ref Vector3 particlePosition, float particleRadius, Vector3 sphereCenter, float sphereRadius)
- {
- float r = sphereRadius + particleRadius;
- float r2 = r * r;
- Vector3 d = particlePosition - sphereCenter;
- float len2 = d.sqrMagnitude;
- // if is inside sphere, project onto sphere surface
- if (len2 > 0 && len2 < r2)
- {
- float len = Mathf.Sqrt(len2);
- particlePosition = sphereCenter + d * (r / len);
- return true;
- }
- return false;
- }
- static bool InsideSphere(ref Vector3 particlePosition, float particleRadius, Vector3 sphereCenter, float sphereRadius)
- {
- float r = sphereRadius - particleRadius;
- float r2 = r * r;
- Vector3 d = particlePosition - sphereCenter;
- float len2 = d.sqrMagnitude;
- // if is outside sphere, project onto sphere surface
- if (len2 > r2)
- {
- float len = Mathf.Sqrt(len2);
- particlePosition = sphereCenter + d * (r / len);
- return true;
- }
- return false;
- }
- static bool OutsideCapsule(ref Vector3 particlePosition, float particleRadius, Vector3 capsuleP0, Vector3 capsuleP1, float capsuleRadius)
- {
- float r = capsuleRadius + particleRadius;
- float r2 = r * r;
- Vector3 dir = capsuleP1 - capsuleP0;
- Vector3 d = particlePosition - capsuleP0;
- float t = Vector3.Dot(d, dir);
- if (t <= 0)
- {
- // check sphere1
- float len2 = d.sqrMagnitude;
- if (len2 > 0 && len2 < r2)
- {
- float len = Mathf.Sqrt(len2);
- particlePosition = capsuleP0 + d * (r / len);
- return true;
- }
- }
- else
- {
- float dl = dir.sqrMagnitude;
- if (t >= dl)
- {
- // check sphere2
- d = particlePosition - capsuleP1;
- float len2 = d.sqrMagnitude;
- if (len2 > 0 && len2 < r2)
- {
- float len = Mathf.Sqrt(len2);
- particlePosition = capsuleP1 + d * (r / len);
- return true;
- }
- }
- else if (dl > 0)
- {
- // check cylinder
- t /= dl;
- d -= dir * t;
- float len2 = d.sqrMagnitude;
- if (len2 > 0 && len2 < r2)
- {
- float len = Mathf.Sqrt(len2);
- particlePosition += d * ((r - len) / len);
- return true;
- }
- }
- }
- return false;
- }
- static bool InsideCapsule(ref Vector3 particlePosition, float particleRadius, Vector3 capsuleP0, Vector3 capsuleP1, float capsuleRadius)
- {
- float r = capsuleRadius - particleRadius;
- float r2 = r * r;
- Vector3 dir = capsuleP1 - capsuleP0;
- Vector3 d = particlePosition - capsuleP0;
- float t = Vector3.Dot(d, dir);
- if (t <= 0)
- {
- // check sphere1
- float len2 = d.sqrMagnitude;
- if (len2 > r2)
- {
- float len = Mathf.Sqrt(len2);
- particlePosition = capsuleP0 + d * (r / len);
- return true;
- }
- }
- else
- {
- float dl = dir.sqrMagnitude;
- if (t >= dl)
- {
- // check sphere2
- d = particlePosition - capsuleP1;
- float len2 = d.sqrMagnitude;
- if (len2 > r2)
- {
- float len = Mathf.Sqrt(len2);
- particlePosition = capsuleP1 + d * (r / len);
- return true;
- }
- }
- else if (dl > 0)
- {
- // check cylinder
- t /= dl;
- d -= dir * t;
- float len2 = d.sqrMagnitude;
- if (len2 > r2)
- {
- float len = Mathf.Sqrt(len2);
- particlePosition += d * ((r - len) / len);
- return true;
- }
- }
- }
- return false;
- }
- void OnDrawGizmosSelected()
- {
- if (!enabled)
- return;
- if (m_Bound == Bound.Outside)
- Gizmos.color = Color.yellow;
- else
- Gizmos.color = Color.magenta;
- float radius = m_Radius * Mathf.Abs(transform.lossyScale.x);
- float h = m_Height * 0.5f - m_Radius;
- if (h <= 0)
- {
- Gizmos.DrawWireSphere(transform.TransformPoint(m_Center), radius);
- }
- else
- {
- Vector3 c0 = m_Center;
- Vector3 c1 = m_Center;
- switch (m_Direction)
- {
- case Direction.X:
- c0.x -= h;
- c1.x += h;
- break;
- case Direction.Y:
- c0.y -= h;
- c1.y += h;
- break;
- case Direction.Z:
- c0.z -= h;
- c1.z += h;
- break;
- }
- Gizmos.DrawWireSphere(transform.TransformPoint(c0), radius);
- Gizmos.DrawWireSphere(transform.TransformPoint(c1), radius);
- }
- }
- }
|