Question

I am implementing a Z-buffer to determine which pixels should be drawn in a simple scene filled with triangles. I have structural representations of a triangle, a vertex, a vector (the mathematical (x, y, z) kind, of course), as well as a function that draws an individual pixel to the screen. Here are the structures I have:

struct vertex{
  float x, y, z; 
  ... //other members for lighting, etc. that will be used later and are not relevant here 
}; 

struct myVector{
  float x, y, z; 
}; 

struct triangle{
  ... //other stuff 
  vertex v[3]; 
}; 

Unfortunately, as I scan convert my triangles to the screen, which relies on calculating depths to determine what is visible and gets to be drawn, I am getting incorrect/unrealistic Z values (e.g., the depth at a point in the triangle is out of bounds of the depths of all 3 of its vertices)! I have been looking through my code over and over and cannot figure out whether my math is off or I have a careless mistake somewhere, so I will try to present exactly what I am trying to do in the hopes that someone else can see something that I don't. (And I have looked carefully at making sure that floating point values remain floating point values, that I am passing in arguments correctly, etc., so this is really baffling!)

Overall, my scan conversion algorithm fills pixels across a scan line like this (pseudocode):

for all triangles{  
  ... //Do edge-related sorting stuff, etc...get ready to fill pixels 

  float zInit;      //the very first z-value, with a longer calculation 
  float zPrev;      //the "zk" needed when interpolating "zk+1" across a scan line 

  for(xPos = currentX at left side edge; xPos != currentX at right side edge; currentX++){

    *if this is first pixel acorss scan line, calculate zInit and draw pixel/store z if depth is less   
     than current zBuffer value at this point. Then set zPrev = zInit. 

    *otherwise, interpolate zNext using zPrev. Draw pixel/store z if depth < current zBuffer value at 
     this point. Then set zPrev = zNext. 

  }
... //other scan conversion stuff...update x values, etc. 
}

To get the value of zInit for each scan line, I consider the plane equation Ax + By + Cz + D = 0 and rearrange it to get z = -1*(Ax + By + D)/C, where x and y are plugged in as the current x value across a scan line and the current scan line value itself, respectively.

For subsequent z values across a scan line, I interpolate as zk+1 = zk - A/C, where A and C come from the plane equation.

To get the A, B and C for these z calculations, I need the normal vector of the plane defined by the 3 vertices (the array vertex v[3]) of the current triangle. To get this normal (which I named planeNormal in the code), I defined a cross product function:

 myVector cross(float x1, float y1, float z1, float x2, float y2, float z2)
 {
   float crX = (y1*z2) - (z1*y2);
   float crY = (z1*x2) - (x1*z2);
   float crZ = (x1*y2) - (y1*x2);

   myVector res;
   res.x = crX;
   res.y = crY;
   res.z = crZ;
   return res;   
 }

To get the D value for the plane equation/my z calculations, I use the plane equation A(x-x1) + B(y-y1) + C(z-z1) = 0, where (x1, y1, z1) is just a reference point in the plane. I just chose the triangle vertex v[0] for the reference point and rearranged:

Ax + By + Cz = Ax1 + By1 + Cz1 Thus, D = Ax1 + By1 + Cz1

So, finally, to get the A, B, C, and D for the z calculations, I did this for each triangle, where trianglelist[nt] is the triangle at current index nt in the overall triangle array for the scene:

float pA = planeNormal.x;
float pB = planeNormal.y;
float pC = planeNormal.z;
float pD = (pA*trianglelist[nt].v[0].x)+(pB*trianglelist[nt].v[0].y)+(pC*trianglelist[nt].v[0].z);

From here, within the scan conversion algorithm I described, I calculated the zs:

zInit = -1*((pA*cx)+(pB*scanLine)+(pD))/(pC);  //cx is current x value; scanLine is current y value
...
...
float zNext = zPrev - (pA/pC);

Alas, after all that careful work, something is off! In some triangles, the depth values come out realistic (except for the sign). With triangle given by the vertices (200, 10, 75), (75, 200, 75) and (15, 60, 75), all depths come out as -75. The same happened for other triangles with all vertices at the same depth. But with the vertices (390, 300, 105), (170, 360, 80), (190, 240, 25), all of the z values are over 300! The very first one comes out as 310.5, and the rest just get bigger, with a max around 365. This should not happen when the deepest vertex is at z = 105!!! So, after all of the rambling, can anyone see what might have caused this? I wouldn't be surprised if it's a sign-related thing, but where (after all, the absolute values are right in the constant depth cases)?

Was it helpful?

Solution

The correct equations are:

n = cross (v[2] - v[0], v[1] - v[0]);
D = - dot (n, v[0]);

Note the minus sign.

OTHER TIPS

you should have a look at www.scratchapixel.com, particularly this lesson:

http://scratchapixel.com/lessons/3d-advanced-lessons/perspective-and-orthographic-projection-matrix/

It contains a self-contained program that shows you how to project vertices.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top