5

I'm trying to use ray-sphere intersections to perform mouse picking in OpenGL. I found a few formulae online, and the last one I tried was one suggested by a user on Stack Exchange:

Ray-Sphere intersection

From what I've understood of this answer, I'm checking if the quadratic equation has positive roots. I don't really care where the intersection takes place, just if the ray intersects the sphere at all. My code is as follows, but doesn't seem to work.

bool Mesh::useObject(vec3 camera, vec3 direction) {

    // a = (xB-xA)²+(yB-yA)²+(zB-zA)²
    float a = ((direction.v[0] - camera.v[0])*(direction.v[0] - camera.v[0])
        + (direction.v[1] - camera.v[1])*(direction.v[1] - camera.v[1])
        + (direction.v[2] - camera.v[2])*(direction.v[2] - camera.v[2]));

    // b = 2*((xB-xA)(xA-xC)+(yB-yA)(yA-yC)+(zB-zA)(zA-zC))
    float b = 2 * ((direction.v[0] - camera.v[0])*(camera.v[0] - mOrigin.v[0])
        + (direction.v[1] - camera.v[1])*(camera.v[1] - mOrigin.v[1])
        + (direction.v[2] - camera.v[2])*(camera.v[2] - mOrigin.v[2]));

    // c = (xA-xC)²+(yA-yC)²+(zA-zC)²-r²
    float c = ((camera.v[0] - mOrigin.v[0])*(camera.v[0] - mOrigin.v[0])
        + (camera.v[1] - mOrigin.v[1])*(camera.v[1] - mOrigin.v[1])
        + (camera.v[2] - mOrigin.v[2])*(camera.v[2] - mOrigin.v[2])
        - (mRadius)*(mRadius));

    float delta = (b*b) - (4 * a*c);

    if (delta < 0)
        return false;

    else {
        std::cout << "Object " << mMesh << " is at postion (" <<
            mOrigin.v[0] << ", " <<
            mOrigin.v[1] << ", " <<
            mOrigin.v[2] << ")\n" <<
            "Size: " << mRadius << std::endl;
        return true;
    }
}

My C++ skills are pretty rusty, so I apologise if this is a horrible way of doing this. This method takes two vectors of three floats, the position of the camera, and the coordinates of a point in my scene 1 unit in front of the camera (I've called this direction).

I want to get the position of the object and it's radius when I face an object and press a key, but instead I get output only when I'm standing on one of the objects in my scene, or if I stand close to another large object. Clearly there's something wrong with my calculations (or worse, my code) but I cannot figure out what that is. :(

Let me know if you need any more code, or if anything is unclear. This is my first question with SO, so if this question is badly phrased, I'm sorry.

EDIT: I shouldn't have been using mouse coordinates as a point on my ray. Edited my question slightly.

Community
  • 1
  • 1
eihe
  • 51
  • 6
  • Your fromulas are totally neglecting your projection matrix (and potentially also the model and also view matrices). Just using `(mouse_x, mouse_y,cam_z+1)` as a direction vector will a) asumme a very weid field of view, and b) also totally ignore the camera location in x and y, as well as the camera orientation. – derhass Dec 13 '15 at 13:55
  • Yes, you're right, that was my bad. I used to use a physical point which was just the camera's x and y position, and its z position + 1, but this didn't work, and in desperation I tried using the mouse coordinates to see if that would change anything. Assuming I revert to the other method, should this code work? – eihe Dec 13 '15 at 14:29
  • Sorry, that's incorrect. Camera's x and y position and +1 whatever direction it's facing. – eihe Dec 13 '15 at 14:36
  • That doesn't really matter. You still totally ignore the projection parameters. And you also ignore the model transformation of the object (if any). You need to _unproject_ the 2D mouse coordinates using the same projection parameters as you use for rendering to get a meaningful 3D direction vector. – derhass Dec 13 '15 at 15:43
  • Why would I need the projection parameters when calculating a ray in world space? (Assuming I'm not using mouse coordinates for now). Also, the origin point of my objects have been transformed along with the object. – eihe Dec 13 '15 at 23:41
  • related [ray and ellipsoid intersection accuracy improvement](http://stackoverflow.com/q/25470493/2521214) – Spektre Mar 16 '16 at 17:44

1 Answers1

1

That code looks pretty messy. The general formula for checking the intersection of a line (direction, origin) with a sphere (center, radius) should be:

length(cross(direction, center-origin)) / length(direction) < radius

Check if you implemented that correctly, maybe factor out some operations into seperate functions.

Tau
  • 496
  • 4
  • 22