Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I've set up a demo with simple first-person controls using C++ and OpenGL, and it seems to work reasonably well. My goal is this: when the player looks at a plane and clicks the left mouse button, draw the intersection of a ray pointing in the direction the player is facing from the player's position with the plane.

So, I start off with two Vectors, Vector position and Vector rotation, where Vector is a pretty standard three-dimensional vector class:

class Vector
{
  public:
    GLfloat x, y, z;

    Vector() {};

    Vector(GLfloat x, GLfloat y, GLfloat z)
    {
      this->x = x;
      this->y = y;
      this->z = z;
    }

    GLfloat dot(const Vector &vector) const
    {
      return x * vector.x + y * vector.y + z * vector.z;
    }

    ... etc ...

And Plane p, with Plane being a simple struct storing the normal of the plane and d. I copied this struct directly from the book "Real-Time Collision Detection," by Christer Ericson:

struct Plane 
{
  Vector n; // Plane normal. Points x on the plane satisfy Dot(n,x) = d
  float d; // d = dot(n,p) for a given point p on the plane
};

To start, I take position as the start of the ray, which I call a. I use that point and rotation to find the end of the ray, b. Then I use an algorithm for finding the intersection of a ray and a plane from that same book. I've actually implemented the same method myself, but I'm using the code from the book directly here just to make sure I didn't mess anything up:

void pickPoint()
{
    const float length = 100.0f;

    // Points a and b
    Vector a = State::position;
    Vector b = a;

    // Find point b of directed line ab
    Vector radians(Math::rad(State::rotation.x), Math::rad(State::rotation.y), 0);
    const float lengthYZ = Math::cos(radians.x) * length;

    b.y -= Math::sin(radians.x) * length;
    b.x += Math::sin(radians.y) * lengthYZ;
    b.z -= Math::cos(radians.y) * lengthYZ;

    // Compute the t value for the directed line ab intersecting the plane
    Vector ab = b - a;

    GLfloat t = (p.d - p.n.dot(a)) / p.n.dot(ab);

    printf("Plane normal: %f, %f, %f\n", p.n.x, p.n.y, p.n.z);
    printf("Plane value d: %f\n", p.d);
    printf("Rotation (degrees): %f, %f, %f\n", State::rotation.x, State::rotation.y, State::rotation.z);
    printf("Rotation (radians): %f, %f, %f\n", radians.x, radians.y, radians.z);
    printf("Point a: %f, %f, %f\n", a.x, a.y, a.z);
    printf("Point b: %f, %f, %f\n", b.x, b.y, b.z);
    printf("Expected length of ray: %f\n", length);
    printf("Actual length of ray: %f\n", ab.length());
    printf("Value t: %f\n", t);

    // If t in [0..1] compute and return intersection point
    if(t >= 0.0f && t <= 1.0f) 
    {
        point = a + t * ab;
        printf("Intersection: %f, %f, %f\n", point.x, point.y, point.z);
    }
    // Else no intersection
    else
    {
        printf("No intersection found\n");
    }

    printf("\n\n");
}

When I render this point with OpenGL, it looks to be pretty close to the where the intersection of the ray and the plane would be. But from printing out the actual values, I discovered that for specific positions and rotations, the intersection point can be off by up to 0.000004. Here's an example of where the intersection is inaccurate - I know the intersection point is NOT on the plane because its Y value should be 0, not 0.000002. I could also sub it back into the plane equation and get an inequality:

Plane normal: 0.000000, 1.000000, 0.000000
Plane value d: 0.000000
Rotation (degrees): 70.100044, 1.899823, 0.000000
Rotation (radians): 1.223477, 0.033158, 0.000000
Point a: 20.818802, 27.240383, 15.124892
Point b: 21.947229, -66.788452, -18.894285
Expected length of ray: 100.000000
Actual length of ray: 100.000000
Value t: 0.289702
Intersection: 21.145710, 0.000002, 5.269455

Now, I know floating-point numbers are just approximations of real numbers, so I'm guessing this inaccuracy is just the effect of floating-point rounding, though it's possible I made a mistake somewhere else in the code. I know the intersection is off only by an extremely small amount, but I still care about it because I'm planning to use these points to define vertices of a model or level by snapping them to an arbitrarily-oriented grid, so I actually want those points to be ON that grid, even if they're slightly inaccurate. This might be a misguided approach - I don't really know.

So my question is: is this inaccuracy just floating-point rounding at work, or am I just dumb?

If it is just floating-point rounding, is there any way to deal with it? I've tried rounding the values of the rotation and position vectors in various ways, which obviously results in a less accurate intersection point, but I still sometimes get intersections that aren't on the plane.

Any other solutions or insights to what I'm trying to do are appreciated - I don't mind being told that I'm wrong.

Sorry if this is a silly question, or if it's too complicated. Thanks!

share|improve this question
    
Well, you could try to use doubles instead of floats and see if that changes the accuracy of your results –  melak47 Feb 28 '13 at 2:38
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.