I work on addon for UV box mapping. In my addon I need to check face normal to sort X,Y or Z oriented faces. By following this topic I found how to compensate object rotation by multiplying object matrix to face normal vector.

Now issue with object scale. On image - object scaled by Z to 0.1, face normal look almost straight to up to Z but mesh data still return normal as if object not scaled.

Question is - how to compensate object scale to get "true" face normals? Blender do it somehow under the hood when showing Normal Gizmo for selected face so how can I get same result.


1 Answer 1


Thanks batFINGER for help.

import bpy, bmesh, mathutils

bmd = bmesh.from_edit_mesh(bpy.context.edit_object.data)

nrm = bmd.select_history.active.normal      #Pick normal for active element.
obm = bpy.context.object.matrix_world       #Get object world matrix.

nrm_fixed = (obm.inverted_safe().transposed().to_3x3() @ nrm).normalized()
  • 1
    $\begingroup$ I take it the quest here is to find the global space normal. See blender.stackexchange.com/questions/27491/… Edited a test script into my answer to add an empty as a "global normal" display. Couldn't get a result using nrm_fixed as above. $\endgroup$
    – batFINGER
    Jul 29, 2021 at 19:18
  • $\begingroup$ Formula I have posted only compensate object scale. If object has also rotation u need first compensate scale then rotation by multiply result with matrix_world.to_3x3().normalized() ( .to_3x3() - removed location .normalized() - removed scale) Not sure I get it right "I take it the quest here is to find the global space normal." I have checked your link... so u propose just use mw.inverted_safe().transposed().to_3x3()? Check this screenshot - my final vector look at (1.0000, 0.0009, 0.0006), your one at (0.8581, -0.3095, -0.4098) what looks wrong. $\endgroup$
    Jul 31, 2021 at 5:57
  • $\begingroup$ Now it become interesting for me - on your GIF empties looks placed perfectly correct along the normals. I not sure but it looks like because you don't use .normalized() (so you get actually scaled normal vector) this n.to_track_quat().to_euler() you use to set empties rotation take in to account that normal scale and set correct euler rotation. Interestingly... But still not work for me - I need clear normalized and correct face normal vector for my addon purpose. $\endgroup$
    Jul 31, 2021 at 6:20
  • $\begingroup$ OMG - I just realized that (object.matrix_world.inverted_safe().transposed().to_3x3() @ normal).normalized() return same (1.0000, 0.0009, 0.0006) normal vector. Thank you kindly for your help )) $\endgroup$
    Jul 31, 2021 at 7:16

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .