point outside of a brush problem

Started by
15 comments, last by LabRat404 19 years, 4 months ago
I've got a pretty decent .Map file parser, but theres just one little bug that is keeping me from making shapes other than cubes... I need to be able to test whether or not a vertice is outside of a given brush, and I've got this fucntion to do just that:


typedef enum pointPos {PLANE_FRONT, PLANE_BACK, PLANE_COINCIDE} pointPos;

pointPos classifyPoint(FACE *face, Vector3 *point)
{
  float p = scalarProduct(&face->normal, point) + face->distance;
 
  if( p > 0.0f ) return PLANE_FRONT;
  if( p < 0.0f ) return PLANE_BACK;
 
  return PLANE_COINCIDE;
}

but the problem is, it thinks that 4 of the vertices of my actual cube (and these are correct vertices that should coincide) are outside of it...but they are not. is there something wrong with my code or is there an error in my math?
0x52 0x65 0x61 0x6C 0x69 0x74 0x79 0x43 0x72 0x61 0x73 0x68
Advertisement
You have to add an epsilon value.

if(p > -MY_EPSILON && p < MY_EPSILON)
return COINCIDE;

if(p < 0.0f)
return BACK;
else
return FRONT;

your presision is to narrow.


what is epsilon? (besides the letter E)
0x52 0x65 0x61 0x6C 0x69 0x74 0x79 0x43 0x72 0x61 0x73 0x68
Epsilon can be thought of as the smallest delta that wouldn't affect the outcome of some process.

Choosing a good epsilon can be done using careful floating-point precision analysis, or it can be done by just throwing values at the wall and seeing what sticks. Needless to say, most code-and-burn game programmers choose the second method.

If your values are in the "1.0" range (i e, measured in meters) then 1e-5 is a good value for epsilon, because it's about one bit's worth of the mantissa at scale 1.0 (very loosely). If you're working with inches instead of meters, you might want 1e-4 instead -- or, if you're really sloppy, 1e-3.

Burn, baby, burn!
enum Bool { True, False, FileNotFound };
alright, I'm still getting the same problem. this time I've got this code:

#define EPSILON (1e-5)typedef enum pointPos {PLANE_FRONT, PLANE_BACK, PLANE_COINCIDE} pointPos;/** test whether or not a point is in front, behind, or coincides with a plane **/pointPos classifyPoint(FACE *face, Vertex3 *point){  float p = scalarProduct(&face->normal, point) + face->distance;  if((p > -EPSILON) && (p < EPSILON)) return PLANE_COINCIDE;  if( p < 0.0f ) return PLANE_BACK;  if( p > 0.0f ) return PLANE_FRONT;}



the first vertex that it thinks is wrong (which is right) is this, along with the face normal and distance:

point checking for: (2,2,-2)
face distance: 2
face normal: (0, 1, 0)

my epsilon not sufficient? I've tried 1e-5, 1e-4, and 1e-3.

(1e-5 == 0.00001), correct?
0x52 0x65 0x61 0x6C 0x69 0x74 0x79 0x43 0x72 0x61 0x73 0x68
Usually, if I don't understand what happens, I add more printf():s to see what's happening. You could print the values of your variables out before comparing them. Then, if you are lucky, you could see something that starts to make sense.

For example there you have:

point checking for: (2,2,-2)
face distance: 2
face normal: (0, 1, 0)

If I'm not calculating wrong, your p is going to be
p = 4;
not p = 0;

So it's not even close to zero in that case.
alright, all the math is correct, at least for the classifyPoint() Fucntion. I'm assuming my functions for getting the normaland distance of a plane are correct, because if I just skip trying to determine if all the vertices are not outside the plane, I can successfully draw a cube (or many) on the screen and have it completely put together after fidning all the missing vertices and then putting them in the correct order. what could be wrong here? I'm stumped.

I'm pretty sure all these functions are correct:

/** return the normal of a face **/Vertex3 getNormal(FACE *face){  Vertex3 U, V, normal;  // subtractVV subtracts two vertexes (arg2 from arg1)  U = subtractVV(&face->vertex[1], &face->vertex[0]);  V = subtractVV(&face->vertex[2], &face->vertex[1]);  normal = vectorialProduct(&U, &V);  return normal;}/** normalize a vector **/int normalize(Vertex3 *normal){  double length;  length = (float)sqrt(pwr(normal->x, 2) +                       pwr(normal->y, 2) +                       pwr(normal->z, 2));  if (length != 0)  {    normal->x = (float)(normal->x / length);    normal->y = (float)(normal->y / length);    normal->z = (float)(normal->z / length);  }  return 0;}/** return the distance of a plane **/float getDistance(FACE *face){  return (float)scalarProduct(&face->normal, &face->vertex[0]);}
0x52 0x65 0x61 0x6C 0x69 0x74 0x79 0x43 0x72 0x61 0x73 0x68
I think this is the problem: are there two different distance formulas? as in, theres a distance between a plane and its origin, and isn't there a separate distance required for this such as the distance bewteen a given vertex and the origin? ...


Edit:

distance between a plane and the origin, and length of a vector.

perhaps length of a vector is what I'm supposd to use here...

Edit: nope. thats not it. all my calculations seem to work just fine until I try to classifyPoint();

any input on this would be great.

[Edited by - LabRat404 on November 29, 2004 9:58:08 PM]
0x52 0x65 0x61 0x6C 0x69 0x74 0x79 0x43 0x72 0x61 0x73 0x68
You're not actually normalizing the face normal when you calculate it. You have to do that before you return it.

Also, sometimes a plane equation is written as Ax+By+Cz+D = 0, sometimes it's Ax+By+Cz = D -- note the difference in sign. Make sure you use the same convention throughout your code.

If you step through the entire function, and look at all the values that come out, you should easily be able to tell what is going wrong.
enum Bool { True, False, FileNotFound };
all the normals I calculate get normalized right after they are calculated. is that what you mean? that a normalized normal is not always what I need?

Edit: as soon as I get the normal, it gets normalized directly afterward, as shown:
...world->brush[g].face.normal = getNormal(&world->brush[g].face); /* get the plane's normal */      normalize(&world->brush[g].face.normal); /* normalize the normal */...


my normalize function is this:

/** normalize a normal **/int normalize(Vertex3 *normal){  double length=getLength(normal);  if (length != 0)  {    normal->x = (float)(normal->x / length);    normal->y = (float)(normal->y / length);    normal->z = (float)(normal->z / length);  }  return 0;}/** return the length of a vector **/double getLength(Vertex3 *vector){  return (double)sqrt(pwr(vector->x, 2) +                      pwr(vector->y, 2) +                      pwr(vector->z, 2));}
0x52 0x65 0x61 0x6C 0x69 0x74 0x79 0x43 0x72 0x61 0x73 0x68

This topic is closed to new replies.

Advertisement