Get elrment normal in scaled object

As far as I had some issues with guessing how to get this and I had found no solutions in google search results - I just leave it here (it may help someone).

Issue - getting normal via existing API functionality return normal without taking in to account object scale.

On image example - originally norlmal look at 45°, after scaling object by Z to 0.1 Blender still return same vector 0.0, -0,707, 0.707. Bmesh .normal return same and samely has no option to return “true” normal.

Solution - it need to multuply normal vector values by scale vector values (next code work for 2.93)

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.
print('Normal' + str(nrm))

obm = bpy.context.object.matrix_world 		#Get object world matrix.
obm_s = obm.decompose()[2]			        #Get object scale from matrix.

# Multiply each of normal vector values by two others from object scale vector (normal X * scale Y * scale Z) + normalize result.
nrm_fixed = mathutils.Vector((nrm[0]*obm_s[1]*obm_s[2], nrm[1]*obm_s[0]*obm_s[2], nrm[2]*obm_s[0]*obm_s[1])).normalized()
print('Normal fixed' + str(nrm_fixed))

If someone from devs staff or close to them read this - it would be nice to implement on API level some .normal_scaled parameter to return this true normal vector without such cumbersome formulas.
Maybe even .normal_world to return normal already adjusted by object rotation and object scale. It could be really handy for addon developers to just return normal vectors without necessity to multiply them first by ton of cumbersome stuff.

That’s not going to happen because it would make no sense. A mesh, as data, has nothing to do with the object it’s assigned to so the world transform is irrelevant.

If you want a vector in world space, it’s just matrix @ vector. It’s only cumbersome because you’re not using matrices.

This is 100% true. and keep in mind that matrix mulitplication is already the simple way of doing things. I remember in college when we had to multiply matrices by hand… talk about cumbersome :stuck_out_tongue:

But yeah, you won’t get far doing computational geometry if you don’t understand how to use matrices, I would definitely recommend brushing up on them. They are really unavoidable, no matter how many helper functions devs add to the API eventually you’ll hit a wall where you have to go learn how to use them. Better to start now and get ahead :slight_smile: I promise they are not as complex as you might think

Well that’s only partially true. You need the right matrix for normal vector transformation. The one that’s correct is not the world matrix itself, but transpose of the inverse of that matrix.
For a mathematical reasoning, have a look here:
https://www.scratchapixel.com/lessons/mathematics-physics-for-computer-graphics/geometry/transforming-normals

1 Like

But matrix @ vector not give correct normal.Probably you are not as smart as you think you are…


If it were so easy peasy like matrix @ vecrtor I would not post it here.

well to be fair, it’s math. You can’t just plug in arbitrary values and expect the correct result to come out the other end. The transpose inverse of a matrix is still a matrix. I think the spirit of the post is correct (eg: matrix math is not hard in Blender if you take some time to understand the concepts).

Sure, it’s math. I just added this information to your post, because I was thinking that |||FG||| could read it like the matrix is just the local-to-world matrix itself (and he really did in the post directly after my first answer :frowning:). I tried to show that I’m not correcting the statement, but only adding to it, by not calling init pixel’s answer wrong and instead saying it’s not the full story. Sorry if this lead to confusion.

1 Like

I’m always happy to be proved wrong :stuck_out_tongue: . And my answer was certainly vague.

I love that you had to edit a typo out of your thinly veiled insult :smiley:

Not what u think - english is not my native language, so I do speling mistakes pretty commonly, all the time use google translate and spell check website. I still have no ideas why and where to use a/an/the… yeah, even like that and I’m not ashamed to talk about it. But still I trying to keep what I wrote in +/- correct spelling. Almost everywhere I write something and then read again and do few editing.

I was poking fun at the fact you made sure your attempted insult was correct instead of fixing other mistakes or removing the unnecessary vitriol. You could have simply asked for clarification, then I’d have given you a full solution rather than just a push in the right direction like my original post.

Edit

Thanks to user batFINGER for help in my Blender Stack Exchange topic.

Better/simpler to get normal in this way:

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()