# Python: fix normal of a new polygon

I've been working on retopo tools. I have created polygon loops with "bmesh.faces.new()". But i get a problem with face normal orientation. Some faces get inverted direction.

Here is my test: http://youtu.be/AfsMQRLa7Zo

Here is the code where i create faces: https://github.com/mifth/mifthtools/blob/4f3fec160c820dc66516a94ffa070261bafb9962/blender/addons/mira_tools/mi_curve_surfaces.py#L489-L501

Also, i added recalculation of normals "bmesh.ops.recalc_face_normals()" but it did not help me.

It would be great if you have some ideas how to fix it. Thanks.

• You will probably need to keep track of the view matrix 'eye position' and let that decide whether you index a face CW or CCW from that perspective, as it will decide the orientation of the Face Normal. May 30 '15 at 21:42
• or .. make the face, check if it is back or front facing from current viewing position and reverse the indices if it is back facing. Depending on your algorithm you could then automatically draw subsequent faces in the same orientation.. May 30 '15 at 22:00

something like this would let you determine if the polygon is back or front facing in the current view context, given a bm and a polygon to check:

def is_front_facing(context, bm, polygon):
"""
When deciding if a polygon is facing the camera, you need
only calculate the dot product of the normal vector of
that polygon, with a vector from the camera to one of the
polygon's vertices.

- If the dot product is less than zero, the polygon is facing the camera.
- If the value is greater than zero, it is facing away from the camera.
"""

region = context.region
rv3d = context.space_data.region_3d

# neat eye location code with the help of paleajed
eye = Vector(rv3d.view_matrix[2][:3])
eye.length = rv3d.view_distance
eye_location = rv3d.view_location + eye

pnormal = obj.matrix_world.to_3x3() * polygon.normal
world_coordinate = obj.matrix_world * polygon.verts[0].co

result_vector = eye_location - world_coordinate
dot_value = pnormal.dot(result_vector)

return not (dot_value < 0.0)


I ripped this out of some old code, it might help to see it in context if it doesn't work. It will be important to establish which rv3d to use, because a polygon that is back-facing if viewed from the top, will be reversed if viewed from the bottom.

• Should be pnormal = obj.matrix_world.to_3x3() * polygon.normal also, normalizing wont change the dot sign (so isn't needed). May 31 '15 at 9:03
• "pnormal = obj.matrix_world.to_3x3() * polygon.normal" will not be correct if the object has unproportional scale or rotation. The normal formula will be correct only for non scaled and non rotate objects. Is it posible to fix? May 31 '15 at 19:46
• "pnormal = obj.matrix_world.to_3x3() * polygon.normal" will not be correct if the object has unproportional scale. For rotation it's ok. But for scale - it will be incorrect. For example if an object has "scale = 0.2, 1.0, 1.0" - normal will be distorted and incorrect with matrix_world.to_3x3() . May 31 '15 at 20:10
• obj.matrix_world also produces unexpected results with sheer matrices - but i don't know if that's a bug or intended limited behaviour of matrix_world @ideasman42 Jun 1 '15 at 5:34
• You can normalize the matrix, but it may be less trouble to project all points onto screen-space, then get the sign of the 2d polygons cross product. Jun 1 '15 at 10:33