- Home /
Even-odd test with raycasting
An easy way to determine if a point is inside a finite, closed shape is to cast a ray and count how many times it intersects the surface. If it's odd, the point is inside. If it's even, the point was outside.
The proof is trivial. If a point in a finite closed shape moves along a ray, any time it passes through the surface it switches between being inside or outside the object.
A naive approach to solving this would be to run a ray from a point outward, store the point, and continue - toggling an odd/even Boolean each time. The problem is that rays in Unity can't intersect a Collider when coming from the inside. According to the Physics.Raycast() documentation.
Notes: Raycasts will not detect Colliders for which the Raycast origin is inside the Collider.
Well, that's fun. So what now?
EDIT
Based off Bunny83's helpful insights, I was able to solve the problem. Here is the code for anyone in the future who comes across this question:
private bool HasOddParity(Collider collider, Vector3 point)
{
float magnitude = collider.bounds.size.magnitude * 2;
bool odd = false;
Vector3 outward = new Vector3 (1, 0, 0);
Vector3 inward = new Vector3(-1, 0, 0);
Ray currentRay = new Ray(point, outward);
RaycastHit hit;
//Near cast
while (collider.Raycast(currentRay, out hit, magnitude))
{
odd = !odd;
currentRay = new Ray(hit.point, outward);
}
Vector3 farPoint = Vector3.MoveTowards(currentRay.origin, currentRay.origin + (outward * magnitude), magnitude);
currentRay = new Ray(farPoint, inward);
//Far cast
while (collider.Raycast(currentRay, out hit, magnitude))
{
if (hit.point.x > point.x)
{
odd = !odd;
currentRay = new Ray(hit.point, inward);
}
else break;
}
return odd;
}
Answer by Bunny83 · Oct 29, 2017 at 01:38 AM
You can simply use a linecast from outside to test the other sides of the collider.
Note that if you want to test a single collider, keep in mind that the Collider class has it's own Raycast method which will only raycast against this single collider. So nothing else can block the ray.
So start a line or raycast from your point inside and continue outwards until you don't hit anything. Then pick a far point outside and do a line cast from that far point to the point you want to test and go the route in reverse.
Of course ins$$anonymous$$d of a line cast you can use a raycast as well, you just have to choose your ray length carefully to end at your point.