Forum archive
Back-face Culling
- Hey Ken,
I've been working on a relatively simple software rendered 3D Engine as of late and I've been learning a good lot about 3D Math and the 3D Pipeline and man, it's so cool. I wish there would've been Math classes that dealt with Vectors and stuff when I was in High School. Anyway, I've gotten a good bit of progress I made a Matrix Math System and a Vector Math system and they work great. I've gotten a wireframe polygon renderer implemented and I have a nice cube rendering and rotating and all that fun stuff as well as a simple Eulerian Camera.
This last week I've been wanting to implement Back-face Culling so that I can start scan converting and filling my polys without any of my backfaces making the meshes look ugly. I've read up on it and I'm using a left handed system because well I'm left handed and because I like the +Z axis going into the screen seems more natural to me. Anyway, from what I've read which may or may not be accurate determining whether a face is backfacing or not you:
1. Find the Surface Normal of the Current Polygon You're Checking which would be the cross product of Vertex1 x Vertex2 or any two verticies on the Polygon Face using their World Coordinates as X,Y,Z.
2. Then from the Camera's Orientation (which for simplification purposes is {0, 0, 0}) calculate the Vector between that an any arbitrary Vertex in the Polygon Face. So Cam - Vertex would give us the vector.
3. Then you calculate the Dot Product of (Cam - Vertex) and Vertex1 x Vertex2.
According to the explanation on GameDev.net that is what is to be done. However, this may be due to my still being a little bit new at 3D Math but, my gut instinct tells me that shouldn't the surface normal itself be able to tell you whether or not it is a backface or not?
V1----------------- V2
\ /
\ --------------->Surface Normal
\ /
\ /
\ /
V3
I don't know if this perspective is right but bear with me. So say we get the V1 x V2 for our Surface Normal and since I'm using a Left Handed System I could just check the Z Value of N = V1 x V2 and if the Z value is a negative value then the surface is viewable. That makes sense to me whether it's mathematically true I'd have to get some paper out and check but it makes sense to me. I'll get some paper out and check my math in the mean time.
Anyway Ken, thanks in advance you're Awesoken.
EDIT <A LITTLE BIT LATER>:
The Surface Normal Seems like it could work -
V1 = {-10, -10, 10}
V2 = {10, -10, 10}
V1-------V2
\ |
\ |
\ |
For two parts of a back facing poly, which would be part of the left triangle of a cube's back.
So V1 x V2 =
(-10 * 10) - (-10 * 10) = -200 X Value
-(-10 * 10) + (10 * 10) = 200 Y Value
(-10 * -10) - (10 * -10) = 0 Z Value
Since the Z Value is 0 and not a value less than 0 it could be rejected.Edited by Jinroh at Re: Back-face Culling
Your math is fuzzy. You need 3 source vertices to calculate a normal vector. The proper equation is: Normal = (Vertex2 - Vertex1) x (Vertex3 - Vertex1). Just to be clear, the code would be:
Skipping the dot product and comparing the sign of the normal's Z is an interesting trick, but wrong. You will get unwanted artifacts in perspective projection, especially near the corners of the screen. Skipping the dot product will only work for orthographic projection.dx1 = vert[2].x - vert[1].x; dx2 = vert[3].x - vert[1].x;
dy1 = vert[2].y - vert[1].y; dy2 = vert[3].y - vert[1].y;
dz1 = vert[2].z - vert[1].z; dz2 = vert[3].z - vert[1].z;
norm.x = dy1*dz2 - dz1*dy2;
norm.y = dz1*dx2 - dx1*dz2;
norm.z = dx1*dy2 - dy1*dx2;- Hey Jinrod, good to see your still coding and stuff ;)
anyway, my 3D cube demo deals with backface culling too (http://hugo.duke4.net/demos/3Dcube-gba-c.zip)
/*
=================
= IsVisible
=================
*/
int IsVisible(int x1, int y1, int x2, int y2, int x3, int y3)
{
int dx1 = x3 - x1;
int dy1 = y3 - y1;
int dx2 = x3 - x2;
int dy2 = y3 - y2;
if ((dx1*(dy2-dy1) - (dx2-dx1)*dy1 ) > 0)
return 0;
else
return 1;
}
And it's used like this :
/*
=================
= drawFaces
=================
*/
void drawFaces()
{
int f;
int color;
int x1,y1,x2,y2,x3,y3;
for(f = 0; f <= 12; f++)
{
x1 = projected[ faces[f][0] ][0] >> 1; // I use >>1 because we plot 2 pixels...
y1 = projected[ faces[f][0] ][1];
x2 = projected[ faces[f][1] ][0] >> 1;
y2 = projected[ faces[f][1] ][1];
x3 = projected[ faces[f][2] ][0] >> 1;
y3 = projected[ faces[f][2] ][1];
color = f >> 1; // we want 2 polies to have the same color.
if(IsVisible(x1,y1,x2,y2,x3,y3) == 1)
DrawPolygon(x1,y1,x2,y2,x3,y3,1 + color);
}
}
But the most important part is that you need to sort your faces correctly in order for
it to work. You need to order them back to back (like tiles). Your math is fuzzy. You need 3 source vertices to calculate a normal vector. The proper equation is: Normal = (Vertex2 - Vertex1) x (Vertex3 - Vertex1).
It's as if my eyes have been opened and now I can see. Thanks Ken, the true surface normal equation makes a lot more sense than my version.Skipping the dot product and comparing the sign of the normal's Z is an interesting trick, but wrong. You will get unwanted artifacts in perspective projection, especially near the corners of the screen. Skipping the dot product will only work for orthographic projection.
Well if I ever want to make JinrohCAD I guess that would work. :D Thanks for setting me straight there Ken.Hey Jinrod, good to see your still coding and stuff
Yeah, Coding is one of the things that takes up most of my free time. You'll barely ever see me at home and not coding something.0XC0DE'S Code
Yeah, thanks for the illustration, my code is setup similarly to your code just a bit differently. The only problem I had was my blasted backface culling algorithm was inaccurate. I thank you for the posted code too that'll keep me from having to bother you guys again if I screw something up. Yeah as for ordering, my verticies are all Clockwise per my Left handed System so they should be good for Backface Culling.
I'd turn on backface culling (with my first algorithm) for an object and polys would just disappear and come to and fro. :P Now thanks to you and Ken I think I can manage now. Too bad we're Roleplaying tonight or I could get some stuff done. Oh well, I've only got one class tomorrow and nothing on the horizon so I can code it up. :'(
EDIT: A little later
Hey, 0XC0DE I just saw your Shadow Warrior Mobile screens on your site it looks pretty sweet. Good luck trying to beat the pants off Carmack. :D I see that we both have Starfield tutorials http://www.geocities.com/solarofficial/UpdatedStarfield.zip mine's in the Console Window so it's slightly less exotic than yours :PEdited by Jinroh at