How do I get the transform manipulator's vector values?


#1

HI

I would like to get the vector or matrix values of the enabled transform gizmo, be it rotation, translate or scale in edit mode, occasionally in object mode, given that the gizmo might not always be aligned with the selected object(s)

For instance lets say the gizmo is aligned to some selection in edit mode, and I would like to get its world matrix if not, the the direction vector corresponding to the transform manipulator. The location is trivial in some sense, but the rotation is the main thing I am after.

thanks


#2

I would really like to know if this is possible too.
I posted a simillar question about a week ago.
I thought it won’t be so hard to get the orientation manually, but things get tricky especially Normal orientation in Edit Mode.

Blender docs say:

The Z axis of the manipulator will match the Normal of the selected element. If multiple elements are selected, it will orient towards the average of those normals.

It seems like it doesn’t actually orient towards the average of the normals. Maybe it depends on how many elements are selected, if they lie on a plane, share edges or faces.
I think the code about how the gizmo orientations are set is here in transform_orientations.c, but it’s too much for my modest skills to understand.


#3

Well Blender sets the thing so it knows what that is. I guess it is a matter of exposing it. Is it exposed?

There is another trick, that I did not try it yet which is to align the viewport to the selection, which aligns it to manipulator’s Z when you do top view I believe. Then there could be a way to get that viewports values in the context.

If anyone tried the viewport trick successfully I would be happy use that solution as well.


#4

Just to share how I do it for Local and Global transform orientations in Edit Mode. (In case the pivot point settings are set to “Median Point” or “Individual Origins”)

import bpy
from mathutils import Vector, Matrix
import bmesh
from bpy.types import Operator

class GizmoMatrixTest(Operator):
    """Test Operator"""
    
    bl_idname = "os.gizmo_matrix_test"
    bl_label = "Os: Gizmo Matrix Test"
    
    @classmethod
    def poll(cls, context):
        # Check if the current view is a 3D View
        return bpy.context.area.type == "VIEW_3D"
    
    def execute(self, context):
        
        # Get the current object data
        object = bpy.context.object
        object_data = bpy.context.object.data
        object_bmesh = bmesh.from_edit_mesh(object_data)
        
        # Declare some variables
        verts_list = []
        verts_co_sum = Vector()
        
        # Get selected vertices in a list
        for vert in object_bmesh.verts:
            if vert.select == True:
                verts_list.append(vert)
        
        if len(verts_list) < 1:
            print ("Nothing is selected")
            
        else:
            # Get a sum of vertices location vectors
            for vert in verts_list:
                verts_co_sum += vert.co
            
            # Get an average location of the selected vertices
            verts_co_average = verts_co_sum / len(verts_list)
            
            # Get the transform orientation in the current view. GLOBAL, LOCAL, NORMAL etc.
            t_orientation = bpy.context.scene.transform_orientation_slots[0].type
            
            # Create an empty, link it to the scene and show its axis
            if bpy.data.objects.get("ManipulatorEmtpy"):
                bpy.data.objects.remove(bpy.data.objects["ManipulatorEmtpy"], do_unlink = True)
                
            manipulator_empty = bpy.data.objects.new("ManipulatorEmtpy", None)
            scene_collection = context.layer_collection.collection
            scene_collection.objects.link(manipulator_empty)
            manipulator_empty.show_axis = True
            
            # Set the location of the ManipulatorEmpty to the average vertex location
            # and orient it using the object orientation. Works for LOCAL and GLOBAL transform orientations
            # when pivot point settings are set to "Median Point" or "Individual Origins"
            
            if t_orientation == "LOCAL":
                new_matrix = object.matrix_world @ Matrix.Translation(verts_co_average)
                manipulator_empty.matrix_world = new_matrix
                
            elif t_orientation == "GLOBAL":
                new_matrix = object.matrix_world @ Matrix.Translation(verts_co_average)
                manipulator_empty.matrix_world = new_matrix
                manipulator_empty.rotation_euler = ( 0, 0, 0 )
            
        
        return {'FINISHED'}
    
classes = (
    GizmoMatrixTest,
    )

register, unregister = bpy.utils.register_classes_factory(classes)

if __name__ == "__main__":
    register()

It creates an Empty where it thinks the gizmo is.
You can paste it in the Blender script editor and run it. Then just select some elements in edit mode, press F3 (search menu), type “gizmo” and run “Os: Gizmo Matrix Test”.


#5

Thanks I will take a look at it.