# backface culling error (in world space)

I write simple software renderer. In my pipeline I have stage of backface culling.

But looks like it has some error.

I perform culling right after world transformation (is it correct?).

Vector3F view_dir(0.0f, 0.0f, 1.0f);

std::vector<Triangle> to_remove;

for (Triangle &t : m_triangles)
{
Vector4F e1 = t.v2 - t.v1;
Vector4F e2 = t.v3 - t.v1;
Vector3F normal(
e1.y * e2.z - e1.z * e2.y,
e1.z * e2.x - e1.x * e2.z,
e1.x * e2.y - e1.y * e2.x
);
normal.Normalize();

float dot = Dot(view_dir, normal);
if (dot <= 0)
to_remove.push_back(t);
}

for (Triangle& t : to_remove)
m_triangles.erase(std::remove(m_triangles.begin(), m_triangles.end(), t), m_triangles.end());


Camera sits in origin and points in screen (RH).

What is the reason?

UPDATED: The error occurs only when triangle has non-zero offset from origin

UPDATED 2: If i process backface culling in clip space (after transforming all vertices with view and projection matrix), and just check z coordinate of triangle normal - it works perfect... Can i perform culing RIGHT BEFORE view/proj transforms? In this case looks like culling will not depends of projection and it's not right?

• It could be winding order. Are you sure you wound all your triangles CCW (or CW, whatever your convention is?) – bobobobo Dec 2 '12 at 10:36
• yes, i tested it with render just single triangle (from this cube side) - they ccw – acrilige Dec 2 '12 at 12:49
• Also i updated post - upload pictures of cube in movement - to make problem clear – acrilige Dec 2 '12 at 12:54

I had the following error: The direction of the view was always taken constant, whereas it should be taken as the difference between the position of the camera and one of the points of the polygon (or its center). Otherwise it will not be perspective-correct. I don't get this error with zero offset from origin because in this case view direction correctly was (0, 0, 1).

So working code looks like this:

// Calculate view position from view matrix
Vector4F view_pos = m_view_transform * Vector4F(0.0f, 0.0f, 0.0f, 1.0f);
std::vector<Triangle> to_remove;

for (Triangle &t : m_triangles)
{
Vector4F e1 = t.v2 - t.v1;
Vector4F e2 = t.v3 - t.v1;
Vector4F normal(
e1.y * e2.z - e1.z * e2.y,
e1.z * e2.x - e1.x * e2.z,
e1.x * e2.y - e1.y * e2.x,
0.0f);

// Calculate actual direction
Vector4F view_dir = t.v1 - view_pos;
view_dir.Normalize();

float dot = Dot(view_dir, normal);
if (dot <= 0)
to_remove.push_back(t);
}

for (Triangle& t : to_remove)
m_triangles.erase(std::remove(m_triangles.begin(), m_triangles.end(), t), m_triangles.end());


Also, looks like there's no reason to do backface culling in world space - it can be done in object space and it can help to increase perfomance. More about front-end backface culling can be read at this page: http://www.gamasutra.com/view/feature/131773/a_compact_method_for_backface_.php?print=1

Hope this will help someone in future :)