123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461 |
- 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;
- #if UNITY_5_3_OR_NEWER
- [Tooltip("The other radius of the capsule.")]
- #endif
- public float m_Radius2 = 0;
- // prepare data
- float m_ScaledRadius;
- float m_ScaledRadius2;
- Vector3 m_C0;
- Vector3 m_C1;
- float m_C01Distance;
- int m_CollideType;
- void OnValidate()
- {
- m_Radius = Mathf.Max(m_Radius, 0);
- m_Height = Mathf.Max(m_Height, 0);
- m_Radius2 = Mathf.Max(m_Radius2, 0);
- }
- public override void Prepare()
- {
- float scale = Mathf.Abs(transform.lossyScale.x);
- float halfHeight = m_Height * 0.5f;
- if (m_Radius2 <= 0 || Mathf.Abs(m_Radius - m_Radius2) < 0.01f)
- {
- m_ScaledRadius = m_Radius * scale;
- float h = halfHeight - m_Radius;
- if (h <= 0)
- {
- m_C0 = transform.TransformPoint(m_Center);
- if (m_Bound == Bound.Outside)
- {
- m_CollideType = 0;
- }
- else
- {
- m_CollideType = 1;
- }
- }
- 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;
- }
- m_C0 = transform.TransformPoint(c0);
- m_C1 = transform.TransformPoint(c1);
- m_C01Distance = (m_C1 - m_C0).magnitude;
- if (m_Bound == Bound.Outside)
- {
- m_CollideType = 2;
- }
- else
- {
- m_CollideType = 3;
- }
- }
- }
- else
- {
- float r = Mathf.Max(m_Radius, m_Radius2);
- if (halfHeight - r <= 0)
- {
- m_ScaledRadius = r * scale;
- m_C0 = transform.TransformPoint(m_Center);
- if (m_Bound == Bound.Outside)
- {
- m_CollideType = 0;
- }
- else
- {
- m_CollideType = 1;
- }
- }
- else
- {
- m_ScaledRadius = m_Radius * scale;
- m_ScaledRadius2 = m_Radius2 * scale;
- float h0 = halfHeight - m_Radius;
- float h1 = halfHeight - m_Radius2;
- Vector3 c0 = m_Center;
- Vector3 c1 = m_Center;
- switch (m_Direction)
- {
- case Direction.X:
- c0.x += h0;
- c1.x -= h1;
- break;
- case Direction.Y:
- c0.y += h0;
- c1.y -= h1;
- break;
- case Direction.Z:
- c0.z += h0;
- c1.z -= h1;
- break;
- }
- m_C0 = transform.TransformPoint(c0);
- m_C1 = transform.TransformPoint(c1);
- m_C01Distance = (m_C1 - m_C0).magnitude;
- if (m_Bound == Bound.Outside)
- {
- m_CollideType = 4;
- }
- else
- {
- m_CollideType = 5;
- }
- }
- }
- }
- public override bool Collide(ref Vector3 particlePosition, float particleRadius)
- {
- switch (m_CollideType)
- {
- case 0:
- return OutsideSphere(ref particlePosition, particleRadius, m_C0, m_ScaledRadius);
- case 1:
- return InsideSphere(ref particlePosition, particleRadius, m_C0, m_ScaledRadius);
- case 2:
- return OutsideCapsule(ref particlePosition, particleRadius, m_C0, m_C1, m_ScaledRadius, m_C01Distance);
- case 3:
- return InsideCapsule(ref particlePosition, particleRadius, m_C0, m_C1, m_ScaledRadius, m_C01Distance);
- case 4:
- return OutsideCapsule2(ref particlePosition, particleRadius, m_C0, m_C1, m_ScaledRadius, m_ScaledRadius2, m_C01Distance);
- case 5:
- return InsideCapsule2(ref particlePosition, particleRadius, m_C0, m_C1, m_ScaledRadius, m_ScaledRadius2, m_C01Distance);
- }
- return false;
- }
- 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 dlen2 = d.sqrMagnitude;
- // if is inside sphere, project onto sphere surface
- if (dlen2 > 0 && dlen2 < r2)
- {
- float dlen = Mathf.Sqrt(dlen2);
- particlePosition = sphereCenter + d * (r / dlen);
- 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 dlen2 = d.sqrMagnitude;
- // if is outside sphere, project onto sphere surface
- if (dlen2 > r2)
- {
- float dlen = Mathf.Sqrt(dlen2);
- particlePosition = sphereCenter + d * (r / dlen);
- return true;
- }
- return false;
- }
- static bool OutsideCapsule(ref Vector3 particlePosition, float particleRadius, Vector3 capsuleP0, Vector3 capsuleP1, float capsuleRadius, float dirlen)
- {
- 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 dlen2 = d.sqrMagnitude;
- if (dlen2 > 0 && dlen2 < r2)
- {
- float dlen = Mathf.Sqrt(dlen2);
- particlePosition = capsuleP0 + d * (r / dlen);
- return true;
- }
- }
- else
- {
- float dirlen2 = dirlen * dirlen;
- if (t >= dirlen2)
- {
- // check sphere2
- d = particlePosition - capsuleP1;
- float dlen2 = d.sqrMagnitude;
- if (dlen2 > 0 && dlen2 < r2)
- {
- float dlen = Mathf.Sqrt(dlen2);
- particlePosition = capsuleP1 + d * (r / dlen);
- return true;
- }
- }
- else
- {
- // check cylinder
- Vector3 q = d - dir * (t / dirlen2);
- float qlen2 = q.sqrMagnitude;
- if (qlen2 > 0 && qlen2 < r2)
- {
- float qlen = Mathf.Sqrt(qlen2);
- particlePosition += q * ((r - qlen) / qlen);
- return true;
- }
- }
- }
- return false;
- }
- static bool InsideCapsule(ref Vector3 particlePosition, float particleRadius, Vector3 capsuleP0, Vector3 capsuleP1, float capsuleRadius, float dirlen)
- {
- 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 dlen2 = d.sqrMagnitude;
- if (dlen2 > r2)
- {
- float dlen = Mathf.Sqrt(dlen2);
- particlePosition = capsuleP0 + d * (r / dlen);
- return true;
- }
- }
- else
- {
- float dirlen2 = dirlen * dirlen;
- if (t >= dirlen2)
- {
- // check sphere2
- d = particlePosition - capsuleP1;
- float dlen2 = d.sqrMagnitude;
- if (dlen2 > r2)
- {
- float dlen = Mathf.Sqrt(dlen2);
- particlePosition = capsuleP1 + d * (r / dlen);
- return true;
- }
- }
- else
- {
- // check cylinder
- Vector3 q = d - dir * (t / dirlen2);
- float qlen2 = q.sqrMagnitude;
- if (qlen2 > r2)
- {
- float qlen = Mathf.Sqrt(qlen2);
- particlePosition += q * ((r - qlen) / qlen);
- return true;
- }
- }
- }
- return false;
- }
- static bool OutsideCapsule2(ref Vector3 particlePosition, float particleRadius, Vector3 capsuleP0, Vector3 capsuleP1, float capsuleRadius0, float capsuleRadius1, float dirlen)
- {
- Vector3 dir = capsuleP1 - capsuleP0;
- Vector3 d = particlePosition - capsuleP0;
- float t = Vector3.Dot(d, dir);
- if (t <= 0)
- {
- // check sphere1
- float r = capsuleRadius0 + particleRadius;
- float r2 = r * r;
- float dlen2 = d.sqrMagnitude;
- if (dlen2 > 0 && dlen2 < r2)
- {
- float dlen = Mathf.Sqrt(dlen2);
- particlePosition = capsuleP0 + d * (r / dlen);
- return true;
- }
- }
- else
- {
- float dirlen2 = dirlen * dirlen;
- if (t >= dirlen2)
- {
- // check sphere2
- float r = capsuleRadius1 + particleRadius;
- float r2 = r * r;
- d = particlePosition - capsuleP1;
- float dlen2 = d.sqrMagnitude;
- if (dlen2 > 0 && dlen2 < r2)
- {
- float dlen = Mathf.Sqrt(dlen2);
- particlePosition = capsuleP1 + d * (r / dlen);
- return true;
- }
- }
- else
- {
- // check cylinder
- Vector3 q = d - dir * (t / dirlen2);
- float qlen2 = q.sqrMagnitude;
- float klen = Vector3.Dot(d, dir / dirlen);
- float r = Mathf.Lerp(capsuleRadius0, capsuleRadius1, klen / dirlen) + particleRadius;
- float r2 = r * r;
- if (qlen2 > 0 && qlen2 < r2)
- {
- float qlen = Mathf.Sqrt(qlen2);
- particlePosition += q * ((r - qlen) / qlen);
- return true;
- }
- }
- }
- return false;
- }
- static bool InsideCapsule2(ref Vector3 particlePosition, float particleRadius, Vector3 capsuleP0, Vector3 capsuleP1, float capsuleRadius0, float capsuleRadius1, float dirlen)
- {
- Vector3 dir = capsuleP1 - capsuleP0;
- Vector3 d = particlePosition - capsuleP0;
- float t = Vector3.Dot(d, dir);
- if (t <= 0)
- {
- // check sphere1
- float r = capsuleRadius0 - particleRadius;
- float r2 = r * r;
- float dlen2 = d.sqrMagnitude;
- if (dlen2 > r2)
- {
- float dlen = Mathf.Sqrt(dlen2);
- particlePosition = capsuleP0 + d * (r / dlen);
- return true;
- }
- }
- else
- {
- float dirlen2 = dirlen * dirlen;
- if (t >= dirlen2)
- {
- // check sphere2
- float r = capsuleRadius1 - particleRadius;
- float r2 = r * r;
- d = particlePosition - capsuleP1;
- float dlen2 = d.sqrMagnitude;
- if (dlen2 > r2)
- {
- float dlen = Mathf.Sqrt(dlen2);
- particlePosition = capsuleP1 + d * (r / dlen);
- return true;
- }
- }
- else
- {
- // check cylinder
- Vector3 q = d - dir * (t / dirlen2);
- float qlen2 = q.sqrMagnitude;
- float klen = Vector3.Dot(d, dir / dirlen);
- float r = Mathf.Lerp(capsuleRadius0, capsuleRadius1, klen / dirlen) - particleRadius;
- float r2 = r * r;
- if (qlen2 > r2)
- {
- float qlen = Mathf.Sqrt(qlen2);
- particlePosition += q * ((r - qlen) / qlen);
- return true;
- }
- }
- }
- return false;
- }
- void OnDrawGizmosSelected()
- {
- if (!enabled)
- return;
- Prepare();
- if (m_Bound == Bound.Outside)
- {
- Gizmos.color = Color.yellow;
- }
- else
- {
- Gizmos.color = Color.magenta;
- }
- switch (m_CollideType)
- {
- case 0:
- case 1:
- Gizmos.DrawWireSphere(m_C0, m_ScaledRadius);
- break;
- case 2:
- case 3:
- DrawCapsule(m_C0, m_C1, m_ScaledRadius, m_ScaledRadius);
- break;
- case 4:
- case 5:
- DrawCapsule(m_C0, m_C1, m_ScaledRadius, m_ScaledRadius2);
- break;
- }
- }
- static void DrawCapsule(Vector3 c0, Vector3 c1, float radius0, float radius1)
- {
- Gizmos.DrawLine(c0, c1);
- Gizmos.DrawWireSphere(c0, radius0);
- Gizmos.DrawWireSphere(c1, radius1);
- }
- }
|