Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- public struct EntityCollider
- {
- public enum Type
- {
- box,
- capsule,
- sphere,
- }
- public Type type;
- public float3 size; //use xy to store radius / height for capsule
- public Pose localTransform;
- public EntityCollider(BoxCollider b, EntityTransform localTransform)
- {
- type = EntityCollider.Type.box,
- size = b.size * localTransform.scale,
- this.localTransform = (Pose)localTransform,
- }
- public EntityCollider(CapsuleCollider c, EntityTransform localTransform)
- {
- type = EntityCollider.Type.capsule,
- size = new float3(c.radius, c.height, 0) * localTransform.scale,
- this.localTransform = (Pose)localTransform,
- }
- public EntityCollider(SphereCollider s, EntityTransform localTransform)
- {
- type = EntityCollider.Type.sphere,
- size = new float3(s.radius, 0, 0) * localTransform.scale,
- this.localTransform = (Pose)localTransform,
- }
- }
- public static class EntityCollisionUtility
- {
- public class Loader : ILoader
- {
- public bool IsComplete => true;
- public int progress => 1;
- public int totalCount => 1;
- public void Load()
- {
- EntityCollisionUtility.Initialize();
- }
- }
- public static NativeParallelMultiHashMap<PrefabReference, EntityCollider> entityColliders;
- public static void Initialize()
- {
- entityColliders = new(PrefabList.prefabs.Count, Allocator.Persistent);
- Lifecycle.onShutDown += Dispose;
- foreach (var prefab in PrefabList.prefabs)
- {
- var rootTx = new EntityTransform(prefab.transform);
- var colliders = prefab.GetComponentsInChildren<Collider>();
- foreach (var collider in colliders)
- {
- if (collider.IsTrigger)
- continue;
- var localTx = rootTx / new EntityTransform(collider.transform);
- switch (collider)
- {
- case BoxCollider b:
- entityColliders.Add(prefab, new(b));
- break;
- case CapsuleCollider c:
- entityColliders.Add(prefab, new(c));
- break;
- case SphereCollider s:
- entityColliders.Add(prefab, new(s));
- break;
- default: // fail silently on mesh colliders, not supported
- break;
- }
- }
- }
- }
- public static void Dispose()
- {
- entityColliders.Dispose();
- }
- public static bool CalculateCollision(EntityCollider a, EntityTransform aTransform, EntityCollider b, EntityTransform bTransform, out float penetrationDepth, out float3 penetrationNormal)
- {
- switch (a.type)
- {
- case EntityCollider.Type.box:
- var aBox = a.AsBox(aTransform);
- switch (b.type)
- {
- case EntityCollider.Type.box:
- break;
- case EntityCollider.Type.capsule:
- return CollisionUtils.CapsuleBoxIntersection(b.AsCapsule(bTransform), aBox, out penetrationDepth, out penetrationNormal);
- case EntityCollider.Type.sphere:
- return CollisionUtils.SphereBoxIntersection(b.AsSphere(bTransform), aBox, out penetrationDepth, out penetrationNormal);
- }
- break;
- case EntityCollider.Type.capsule:
- switch (b.type)
- {
- case EntityCollider.Type.box:
- break;
- case EntityCollider.Type.capsule:
- break:
- case EntityCollider.Type.sphere:
- break:
- }
- break;
- case EntityCollider.Type.sphere:
- switch (b.type)
- {
- case EntityCollider.Type.box:
- break;
- case EntityCollider.Type.capsule:
- break:
- case EntityCollider.Type.sphere:
- break:
- }
- break;
- }
- }
- }
- public static bool SphereBoxIntersection(float3 sphereCenter, float radius, box box, out float3 penetrationNormal, out float penetrationDepth)
- {
- penetrationNormal = default;
- penetrationDepth = default;
- var localCenter = sphereCenter / box.localTransform;
- var aabb = new AABB(0, box.halfExtents);
- var cp = ClosestPointOnOrInAABB(localCenter, aabb);
- var dist = mafs.distance(localCenter, cp);
- if (dist > radius)
- return false;
- if (cp == localCenter) // center of sphere is inside the box
- {
- var edgePt = ClosestPointOnAABB(localCenter, aabb);
- penetrationNormal = mafs.normalize(localCenter - edgePt);
- penetrationDepth = mafs.distance(localCenter, edgePt) + radius;
- }
- else // center of sphere is outside the box
- {
- penetrationNormal = mafs.normalize(cp - localCenter);
- penetrationDepth = dist;
- }
- return true;
- }
- public static bool CapsuleBoxIntersection(capsule cap, box box, out float3 penetrationNormal, out float penetrationDepth)
- {
- penetrationNormal = default;
- penetrationDepth = default;
- // transform the capsule into box space so the box becomes an AABB
- var localCapTx = box.transform / cap.transform;
- AABB aabb = new AABB(0, box.halfExtents);
- var localCap = new capsule(localCapTx, cap.height, cap.radius);
- // Expand the AABB by the radius. This will give false positives on the corners which we will find later.
- var expandedAABB = new AABB(0, box.halfExtents + cap.radius);
- // Check if the ray intersects the box
- var rayHit = RayBoxIntersection(
- in localCap.baseCenter,
- in localCap.normal * localCap.height,
- in expandedAABB.halfExtents,
- out float2 hits,
- out float3 normal);
- // return early if there is no chance of intersection
- if (!rayHit)
- return false;
- hits = mafs.clamp01(hits);
- var pointA = localCap.baseCenter + localCap.normal * hits.x;
- var cpA = ClosestPointOnOrInAABB(pointA, aabb);
- var distA = mafs.distance(pointA, cpA);
- if (distA < cap.radius)
- {
- penetrationDepth = distA;
- penetrationNormal = normal;
- return true;
- }
- var pointB = localCap.baseCenter + localCap.normal * hits.y;
- var cpB = ClosestPointOnOrInAABB(pointB, aabb);
- var distB = mafs.distance(pointA, cpA);
- if (distB < cap.radius)
- {
- penetrationDepth = distB;
- penetrationNormal = normal;
- return true;
- }
- return false;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement