- Home /
What's the best/easiest way to do something like Bounds.Intersects but accounting for rotation?
I need to compare two cuboid volumes to see if they will overlap, but I need to take rotation into consideration. I also need to do this immediately, so I can't just use OnTriggerEnter or OnCollisionEnter, which would require waiting for a physics update. I was using Bounds.Intersect for this, and it worked great, but it can't handle rotation.
Is there a way to do this without having to do a lot of math by hand? And if not, can anyone recommend a particular approach?
Thank you.
I can't think of an out of the box solution. Consider looking for a third party library to avoid reinventing the whell. This should be a recurring pattern for developers to solve so I would be surprised if a little searching wouldn't find you a usable .NET implementation.
(Out of curiosity, to add a little meat to the question; what specific scenario do you have right now, where you must control the ti$$anonymous$$g of collision detection?)
I'm trying to find a free space for an object that is entering the world. I don't want the complexity of maintaining a state to span a physics update, as well as the fact that dozens, possibly hundreds, of objects could be blocking the way. So relying on the collision events might mean my object doesn't get spawned for a second or two.
Answer by Jessy · Dec 21, 2013 at 09:39 PM
This is easy to use if you use mesh.bounds (on a cube), because that's in local space.
Please let me know if you profile, and obtain a performance comparison with and without the "ContainsAny" line.
namespace UnityEngine
{
using System;
using System.Collections.Generic;
using System.Linq;
public static class BoundsExtensions
{
/// <param name="transform1">Transform of the Game Object associated with bounds1</param>
/// <param name="transform2">Transform of the Game Object associated with bounds12</param>
public static bool Intersects(this Bounds bounds1, Bounds bounds2, Transform transform1, Transform transform2)
{
Vector3[] bounds1Points = transform2.InverseTransformPoints(bounds1.EnumeratePoints(), transform1).ToArray();
Vector3[] bounds2Points = transform1.InverseTransformPoints(bounds2.EnumeratePoints(), transform2).ToArray();
// This is redundant, because this will return true in a subset of cases
// with edge intersections, but Unity's methods are not in C# and might be faster.
// Requires profiling.
if ( bounds1.ContainsAny(bounds2Points) || bounds2.ContainsAny(bounds1Points) )
return true;
Func<Vector3, Vector3, Bounds, bool> edgeIntersectsBounds = (point1, point2, bounds) =>
{
Ray ray = new Ray(point1, point2 - point1);
if ( !bounds.IntersectRay(ray) )
return false;
ray.origin = point2;
ray.direction = -ray.direction;
return bounds.IntersectRay(ray);
};
Func<Vector3[], Bounds, bool> pointsContainIntersectingEdge = (points, bounds) =>
{
for (int i = 0; i < points.Length - 1; i++)
if ( points.Skip(i + 1).Any( p => edgeIntersectsBounds(points[i], p, bounds) ) )
return true;
return false;
};
return pointsContainIntersectingEdge(bounds2Points, bounds1) || pointsContainIntersectingEdge(bounds1Points, bounds2);
}
public static bool ContainsAny(this Bounds bounds, IEnumerable<Vector3> points)
{
return points.Any( p => bounds.Contains(p) );
}
public static IEnumerable<Vector3> EnumeratePoints(this Bounds bounds)
{
yield return bounds.min;
yield return bounds.max;
for (int axis = 0; axis < 3; axis++)
{
Vector3 point = bounds.min;
point[axis] += bounds.size[axis];
yield return point;
point = bounds.max;
point[axis] -= bounds.size[axis];
yield return point;
}
}
}
}
namespace UnityEngine
{
using System.Collections.Generic;
using System.Linq;
public static class TransformExtensions
{
/// <summary>
/// from local to world space
/// </summary>
public static IEnumerable<Vector3> TransformPoints(this Transform transform, IEnumerable<Vector3> points)
{
return points.Select( p => transform.TransformPoint(p) );
}
/// <summary>
/// from world to local space
/// </summary>
public static IEnumerable<Vector3> InverseTransformPoints(this Transform transform, IEnumerable<Vector3> points)
{
return points.Select( p => transform.InverseTransformPoint(p) );
}
/// <summary>
/// Puts points from another Transform's local space into this one's.
/// </summary>
public static IEnumerable<Vector3> InverseTransformPoints(this Transform transform, IEnumerable<Vector3> points, Transform otherTransform)
{
return transform.InverseTransformPoints( otherTransform.TransformPoints(points) );
}
}
}