2
\$\begingroup\$

I'm worried about my own attempt at a solution for a Sphere-Plane collision testing. I originally implemented a solution I found on a mix of Game Development websites around the place, which was similar enough to the following:

bool intersecting(BoundingSphere const& s, Vector3 const& s_origin, BoundingPlane const& p, float const p_distance) {
    Vector3 const p_origin = p.normal * p_distance;
    Vector3 const cp = s_origin + p.normal * dot((p_origin - s_origin), p.normal);

    return (distance2(s_origin, cp) < s.radius * s.radius);
}

But I have recently spent a bit more time doing linear algebra since and basic geometry, and decided upon revising the above solution (to see if I understood the problem space better).

In thinking about it as a simple check: distance of a point from a line being less than the radius. I came up with the following:

bool intersecting2(BoundingSphere const& s, Vector3 const& s_origin, BoundingPlane const& p, float const p_distance) {
    return abs<float>(dot(p.normal, s_origin) - p_distance) < s.radius;
}

It has so far passed all my tests practically, but I still worry about my mathematical ability and I don't want an edge case to bite me in the ass that I might have missed. One thing I have definitely noticed is the solution is highly sensitive to the normalised form of the plane normal. If it is simply a rough estimation, ie not truly normalised, it will fail completely (exponential error).

The fact I never saw a solution that short worries me haha.

edit: My testbed: http://pastie.org/3512889

proposed tags: collision-detection && math

\$\endgroup\$
2

1 Answer 1

4
\$\begingroup\$

I'm not sure what kind of error your getting but here is a very simple collision test:

#include <cmath>
#include <iostream>

class float3 {
        public:
                float x,y,z;
};

class float4 {
        public:
                float a,b,c,d;
                float norm() const{
                        return sqrt(a*a+b*b+c*c);
                }
};

typedef float4 plane;

class sphere {
        public:
                float3 position;
                float radius;
};

float project( const float3 & spherePos, const plane & p){
        return std::abs( spherePos.x*p.a + spherePos.y*p.b + spherePos.z*p.c + p.d );
}

bool const collision( const sphere & s, const plane & p){
        return project(s.position,p)/p.norm() < s.radius;
}

int main( int argc, char * argv[]){

        plane p = {0.0,-1.0,0.0, 2.0 };
        sphere s = { {0.0,1.5,0.0}, 1.0 };

        if ( collision(s,p) )
                std::cout << "Collision detected" << std::endl;

}

The advantage here is that you don't need a normalized plane. The line that bothers me is this:

return abs<float>(dot(p.normal, s_origin) - p_distance) < s.radius;

Just write your solution such that it can handle un-normalized planes. If you're working with normalized planes (which may be what is contained in "p.normal"?) I believe you need :

return abs<float>(dot(p.normal, s_origin) + p_distance) < s.radius;

See the wolfram page on this topic - it is straight forward. It is not clear how you have implemented BoundingPlane - but if you are getting errors, that would be the first place to look.

\$\endgroup\$
5
  • \$\begingroup\$ BoundingPlane is just a container for Vector3 normal, a normalised vector for the normal of the plane. Distance from the origin is a variable which is passed p_distance. I originally came up with what you have in the second statement, but it only gave the correct results when I did the - p_distance, which I don't understand. \$\endgroup\$ Commented Mar 4, 2012 at 0:58
  • 1
    \$\begingroup\$ " but it only gave the correct results when I did the - p_distance " . I'm not sure what you 'expect' the results to be - I think your error lies in your interpretation of the representation of a plane. See mathworld.wolfram.com/Plane.html for more info about the formal definition of a plane. What you have is very close though! \$\endgroup\$
    – Marm0t
    Commented Mar 4, 2012 at 2:21
  • \$\begingroup\$ I'm pretty sure I have the right understanding. The normal of the plane is obvious enough (the vector perpendicular to the plane), and that is normalised. Then p_distance is the distance of that normal from the origin (0,0,0). Therefore a Plane with a normal of (0, 1, 0) would be flat, and a p_distance of 5 would put the plane at y = 5. \$\endgroup\$ Commented Mar 4, 2012 at 3:55
  • \$\begingroup\$ traditionally, if you have a plane defined by ax + by + cz + d = 0, if you specified the normal to be (0,1,0) you would have the equation y = -d/b = -d, where in this case the intercept is y = - d. So if you set d=5, the y intercept is at -5 (y = - d, y = -5 ). Make sure you are being consistent with the math - I don't believe what you have done is what you expected you did - thus the errors. Simple things like this that 'work' in one case will cause huge headaches down the road one you attempt more complicated operations \$\endgroup\$
    – Marm0t
    Commented Mar 4, 2012 at 6:15
  • \$\begingroup\$ Its taken me this long (24 days?), just reading a paragraph on building planes made me realise you were right. I had a fundamental problem with my understand of distance to the origin. I didn't realise distance could be negative OR positive, based on the normal of the plane. I thought it was simply absolute. Which makes perfect sense now. Hence. Thanks for your answer. \$\endgroup\$ Commented Mar 28, 2012 at 9:55

Not the answer you're looking for? Browse other questions tagged or ask your own question.