 # Face culling and dot product

Hello, I seem to be getting something wrong, or I’m missing some detail on calculating the angle to the camera to skip drawing faces. But only when the camera DOES NOT look at the models directly. And I’m not being able to determine if it’s something wrong in the way I use nalgebra, or the way I understood the algorithm

I have this algorithm to perform culling before projecting the points:

for each mesh…

``````let world_isometry : Isometry3<f32> =
Translation3::new(mesh.position.x,mesh.position.y,mesh.position.z) *
UnitQuaternion::from_euler_angles(mesh.rotation.x, mesh.rotation.y, mesh.rotation.z);
``````

for each face on the mesh

``````if !self.is_backface_b(&mesh.vertices[face.a], &camera, &face, &world_isometry) {
// draw face
}
``````

This is the culling algorithm:

``````    fn is_backface_b(&self,face_vertex : &Vertex, camera : &Camera, face:&Face, world_mat : &Isometry3<f32>) -> bool {
let cam_pos : Point3<f32> = &camera.position;
let view_vector : Point3<f32> = cam_pos - face_vertex.coordinates;
let normal : Point3<f32> = world_mat.transform_point(&face.normal);
let result : f32 = view_vector.dot(&normal.coords);
result < 0.0
}
``````

This seems to work OK when the camera is looking directly at the meshes, but draws extra triangles (and hides others) if the camera actually looks at the center of the screen. I’m pretty sure I’m missing something.

Any help is greatly appreciated.

Hi!

I edited your message to make the code blocks more readable. It is best to use code blocks (with three backticks) instead of inline code (with one backtick) for large chunks of code.

It appears that you are confusing points and vectors here. A point identifies a location in space. A normal does not have a location in space as it is just a direction; so it should be a vector, not a point.

For example the `view_vector` is a vector so its type should be `Vector3<f32>` instead of `Point3<f32>`. Similarly, a normal should be a vector too, so `face.normal` should have the type `Vector3<f32>`, and it should be transformed with: `let normal = world_mat.transform_vector(&face.normal);`. So your code should look like this:

``````    fn is_backface_b(&self,face_vertex : &Vertex, camera : &Camera, face:&Face, world_mat : &Isometry3<f32>) -> bool {
let cam_pos : Point3<f32> = &camera.position;
let view_vector = cam_pos - face_vertex; // Will have the type Vector3<f32>
let normal  = world_mat.transform_vector(&face.normal); // Will have the type Vector3<f32>.
let result : f32 = view_vector.dot(&normal);
result < 0.0
}
``````

The type of `face.normal` is very important. By doing `world_mat.transform_point(&face.normal)`, you are applying both the rotation and the translation transformation to the normal, which is wrong because a normal (i.e. a direction) does not have a location in space, it cannot be translated. By applying `world_mat.transform_vector(&face.normal)` with `face.normal` a `Vector3<f32>`, only the rotation part of the isometry will be applied.

1 Like

Thank you very much. Effectively, that was the issue. I was mixing Point3 and Vector3. And actually, I thought Vector3 was Point3 and vice versa, so I failed to detect the problem when i tried playing around that subject.