• Please review our updated Terms and Rules here

Simplifying Backface Culling

neilobremski

Experienced Member
Joined
Oct 9, 2016
Messages
55
Location
Seattle, USA
The process of culling backfaces is simply checking the visibility of one-sided polygons based on whether they are facing towards the camera / player or away. If they are facing away then it is a back-facing side, rather than front-facing, and must be skipped during rendering. To determine this, I must calculate a normal vector. Every 3D triangle has two of these normals: one points outward from it and one points inward. The one you get depends on whether the calculation is made from vertices going clockwise or counter-clockwise. [SUP][1][/SUP]

One way to think of a normal would be if you had a triangular pancake lying flat on your plate and you stuck a fork straight down into it. That forks is a normal vector. The cross product of two angles on a 3D triangle provides a normal vector. Hence, for me to calculate the normal I use the following: [SUP][2][/SUP]

Nx = (y3-y1)*(z2-z1) - (z3-z1)*(y2-y1)
Ny = -( (x3-x1)*(z2-z1) - (z3-z1)*(x2-x1) )
Nz = (x3-x1)*(y2-y1) - (y3-y1)*(x2-x1)​

This must be calculated whenever the angles change such as when the polygon is rotated. In the current Magenta's Maze this is normalized to fit within 8 bytes per coordinate. When working on modern hardware, I would probably normalize this to a unit vector which means the maximum magnitude along any axis is -1 to 1 inclusive. But actually for my current purposes, I don't care about the magnitude of this vector, I just care which way it's pointing!

Now there is one more calculation usually made to determine if the polygon is front or back-facing and that's the dot product. This calculation is done between the normal and a viewing vector. Since all of the polygons are rendered "head on", the viewing vector can simply be any point (usually one of the three vertices) on the polygon. The dot product then comes from this equation:

dp = (Nx * Vx) + (Ny * Vy) + (Nz * Vz)​

Finally, if the dot product is positive then the polygon is front-facing, otherwise it is back-facing and therefore not to be shown. [SUP][3][/SUP]

However, I noticed some things while testing this in my new FlexPoly engine where I do backface culling in object space prior to translation: the first two terms will be zero if the polygons only exist at Z=0. I also noticed that it's perfectly valid in object space for a point to be at (0,0,0) but using that vertex as the viewing vector causes the dot product to always be zero! The avatar location is (0,0,128) which means I could make the viewing vector (0+x1,0+y1,128+z1) but then the first two terms are still unnecessary and the last one might as well be a result of 1.

This has got me thinking that perhaps all I need to really calculate is Nz.

Obviously, I haven't fully testing this yet otherwise I'd be more certain. However, if this works then it would greatly simplify and speed-up this particular process ...

Footnotes:

[SUP][1][/SUP]. My vertices are clockwise ordered, meaning that if I look at a polygon's front face dead-on then tracing the vertices from 1 to 3 is always clockwise.

[SUP][2][/SUP]. Ny is negated because in screen space a negative Y goes up but in 3D space a negative Y goes down.

[SUP][3][/SUP]. What about zero? In the current Magenta's Maze, zero meant invisible but I do believe it's perfectly valid to say this means "visible" as well since it probably means the polygon is perfectly sideways and maybe you want to see a 1-pixel line.
 
Back
Top