Getting Vertex Normals direction

Hi,
I struggle finding any way to show Normal’s directions on selected vectors.

I am thinking maybe I can get this value from the existing function that is copying selected vector’s direction:

Select vertex -> Alt+N -> Copy Vectors

This will show command in Blender console: bpy.ops.mesh.normals_tools(mode=‘COPY’)

Obviously this value was just saved somewhere in the buffer, but how can I access this saved value using Python command?

I expect it to be saved as Quaternion or something similar.

The whole idea is to create Addon that will rotate selected vertices’s normals and align them to be perpendicular to global grid. So I need to know the previous rotation first before rotating them.

How to access this copied value, or perhaps you know where the function “mesh.normals_tools()” source code is saved?

Any way of pointing me to the right direction will be highly appreciated.
Thanks a lot

You can get it from bpy.context.scene.tool_settings.normal_vector

The source code is in source/blender/editors/mesh/editmesh_tools.c.

Be aware that the ‘Copy Vectors’ command only works if exactly one loop and one vertex is selected. In the UI you have to put selection into both vertex and face mode (shift click on the second mode to add it). Then you have to first select a vertex, and then add (shift-click) a face selection.

You can also write that buffer and then use Paste Normals to directly set normals of selected things. So maybe you can accomplish what you need without knowing the previous value.

1 Like

Thanks for the answer!

The bpy.context.scene.tool_settings.normal_vector works somehow, but I am afraid I can’t use it because it needs also those faces to be selected together with it.

The whole purpose of the addon is to make it easier: select group of vertices (with only one normal direction, because they are “marked Sharp”), click button X for example and all verticie’s normals will become parallel with X axis. Manually selecting faces for it would be too complicated I am afraid. Only if the script could somehow select the faces itself (?).

Thanks for the hint about ‘Copy Vectors’, I actually didn’t know about that.

I am attaching a screenshot of what I am trying to achieve.

I need to correct those normals on 100 ramps like this one, so they seamlessly fit next to each other in square grid generated in my game. So addon that would make those verticies normals parallel with grid axis would make a lot of sense here.

…Can I perhaps paste copied direction from the buffer into some console print instead of executing it in the scene?

The problem is that custom normals are “per loop” – meaning, they are associated with a vertex AND a face. If you only specify a vertex, then which face’s custom normal do you intend to change? That’s why the awkward UI method requires selecting first a vertex then a face. In your diagram on the left, it looks like you only want to change the normals that are sort-of pointing in the x direction, not the ones on the side faces pointing in the y direction. I’d have to experiment to see how to get that selection history to happen via the API, and I don’t have time to do that right now, sorry. If you could figure out how to do that, and figure out how to select the face that goes along with a user-selected vertex, then you could problem do what you want in two stages: first, store all the selected vertices; then unselect them and, one at a time, set their custom normal.

1 Like

I am sorry for late answer.
I see. The vertex itself isn’t enough because it needs a face to relate to…so what if I would programmatically select also the faces that are touching the vertex and also have the same smoothing group (to avoid selecting the ones that are behind sharp edge), do you know how would that be possible to select these?

You wrote: “In your diagram on the left, it looks like you only want to change the normals that are sort-of pointing in the x direction, not the ones on the side faces pointing in the y direction.” - This actually shouldn’t be a problem in my solution, since these faces are separated using the “sharp edge”…and further I can even separate these completely (using Y shortcut), because it doesn’t matter in Unity engine. So they can be totally separate faces and the side ones do not matter.

To make it easier, lets consider we have just one vertex normal direction that is same for all connected faces (I guess that is called “average normal”) and lets consider we are only working with ONE vertex, because I can easily automate this in for each selected vertex in for() loop.

here is my whole code, maybe it will help somehow:

import bpy, bmesh

class NormalsX_OT_Operator(bpy.types.Operator):
    bl_idname = "objx.alignx"
    bl_label = "Align Normals"        
    bl_description = "Align Normals to Grid XYZ axis"

    def execute(self, context):    
        
        obj = context.active_object
        current_obj = bpy.context.active_object


        # Getting index of currently selected vertices

        def get_vertex_data(current_obj):
            bm = bmesh.from_edit_mesh(current_obj.data)
            selected_verts = [vert for vert in bm.verts if vert.select]
            print_vert_details(selected_verts)

        def print_vert_details(selected_verts):
            num_verts = len(selected_verts)                     # how many verts are selected?
            print("number of verts: {}".format(num_verts))  
            
            vert_indices = [id.index for id in selected_verts]  # list of indices for every selected vertex
            print("vert indices: {}".format(vert_indices))


            # for every selected vertex, execute this
            for item in vert_indices:

######## This is where I need help #########

                # Finding vertex's coord Vector

                # n = bpy.ops.transform.rotation_normal()
                # bpy.ops.mesh.normals_tools(mode='COPY')
                # print(bpy.ops.mesh.normals_tools())

######################################

                print("Vector Normal: ")
                print(n)


                v = obj.data.vertices[item]                    # which vertex? Using index nr
                co_final = obj.matrix_world @ v.co      # co_final is the global location of the vertex
                print("Vector: ")
                print(co_final)
                x_offset = co_final.x      # taking only X value from vector
                print(x_offset)

                # AIM THE NORMAL TO PROPER DIRECTION ON THE AXIS
                # bpy.ops.mesh.point_normals(target_location=(X, Yoffset, Zoffset))  #input previous values


            # Finding vertex's coord Vector

            #v = obj.data.vertices[vert_indices]    # which vertex? Using index nr

            # co_final is the global location of the vertex
            #co_final = obj.matrix_world @ v.co

            #print(co_final)

        
        
        
        
        # checking if user is in the edit mode

        if obj.mode == 'EDIT':
            print("EditMode!")
            bpy.ops.object.editmode_toggle()    # reloading edit mode to update location
            bpy.ops.object.editmode_toggle()    # in case vertices were moved
            get_vertex_data(current_obj)

        else:
            print("This only works in Edit Mode")

        return{'FINISHED'}

solution in this thread: Vertex normal direction not updating after setting manually?