Face culling
This works only for single convex strict winding rule mesh without holes!
The idea is that sign of dot product of 2 vectors will tell you if the vectors are opposite or not. So if we have a normal pointing out and view direction their dot should be negative for faces turned towards camera/viewer.
As you do not want to render just select visible planar faces/edges you can do this on CPU side entirely. What you need is to have your mesh in form of planar faces (does not matter if triangles,quads or whatever) so let assume triangles (for more points you just add them to _face
but for computation still use only v0,v1,v2
) … Each face should have the vertexes and normal.
struct _face
{
double v0[3],v1[3],v2[3],n[3];
};
List<_face> mesh;
Now the vertexes v0,v1,v2
you already have. All of them should be ordered in strict winding rule. That means if you look at any face from outside the points should form only CW (clockwise) loop (or only CCW (counter-clockwise) loop). To compute normal you simply exploit cross product which returns vector perpendicular to both operands:
n = cross(v1-v0,v2-v1) // cross product
n = n / |n| // optional normalize to unit vector
If you need the vector math see
- Understanding 4×4 homogenous transform matrices
On the bottom is how to compute this… Also the whole answer you will need for the camera direction so read it…
Now if your mesh has strict winding rule than all the computed normals are pointing out of mesh (or inwards depends on your coordinate system, CW/CCW and order of operands in cross product). Let assume they all pointing out (if not just negate normal).
In case you do not have strict winding rule compute avg point of your mesh (sum all vertexes and divide by their count) this will be the center c
of your object. Now just compute
dot(n,(v0+v1+v2)/3 - c)
and if not positive negate the n
. This will repair your normals (you can also reverse the v0,v1,v2
to repair the mesh.
Now the camera and mesh usually has its own 4×4 transform matrix. one transfroms from mesh LCS (local coordinate system) to GCS (“world” global coordinate system) and the other from GCS to camera LCS (screen). We do not need projections for this as we do not render … So what we need to do for each face is:
-
convert
n
to GCS -
compute
dot(n,camera_view_direction)
where
camera_view_direction
is GCS vector pointing in view direction. You can take it from direct camera matrix directly. It is usually theZ
axis vector (in OpenGL Perspective view it is-Z
). Beware camera matrix used for rendering is inverse matrix so if the case either compute inverse first or transpose it as we do not need the offset anyway … -
decide if face visible from the sign of #2
Again all the math is explained in the link above…
In case you do not have mesh matrix (does not have changing position or orientation) you can assume its matrix is unit one which means GCS = mesh LCS
so no need for transformations.
In some cases there is no camera and only mesh matrix (I suspect your case) then it is similar you just ignore the camera transforms and use (0,0,-1)
or (0,0,+1)
as view direction.
Also see this:
- Understanding lighting in OpenGL
It should shine some light on the normals topic.
solved How to get a list the visible vertices and segments of a mesh