# How to script a gizmo that would be transformable(move, rotate, scale) independantly from the object it would originate at?

I am looking at the documentation and the gizmo samples that come with Blender(Text Editor's Templates>Python>Gizmo...)

but I am currently struggling a bit trying to understand how this new gizmo concept works.

I would like to make an operator that would make a custom shaped(doesn't matter much - could be other types) gizmo appear at the orgin of the active object and could be moved, rotated and scaled independantly of the object so that I could get it's transformed matrix and do other stuff with it during(or at the end of) the operation. I am sure I will figure it out sooner or later, but I could use some help to make it sooner rather then later and would be very greatfull for it. If somebody could point me to some more examples of gizmos used that would also be awesome.

• Hi I noticed you mentioned this is relatively new, I have Blender 2.78, is it only available in 2.8? regardless, if I understand what you're asking and I'm not sure I do you don't need a gizmo for that the bpy already provides a means of doing this. .BLEND I hope if it's not what you're looking for it at least gives you a decent alternative. – Frederick Aug 9 '19 at 20:01
• I want to have a gizmo that would move independently from the object, not to transform an object. By the way, you can just do this instead of so much typing. Anyway, the new gizmos are only available in 2.80. I thought I made it pretty clear by providing a link to the documentation and mentioning how one can see the gizmos working with examples from Text Editor's Templates menu, but I will try to update the question so it is formed clearer and it is easier to understand what I am talking about. – Martynas Žiemys Aug 9 '19 at 22:12
• Are you maybe looking for something like this? imgur.com/a/jIA7llU The myLocRotScale matrix allows you to edit the location rotation and scale of the gizmo (in World space). In the shown example the gizmo is translated by 3 in the y-Direction. The default value for myLocRotScale could be set to ob.matrix_world.normalized() which is the object location, so that the gizmo appears there until you change it. BTW here is a nice collection of Gizmos: blender.stackexchange.com/questions/131685/… – Robert Roth Aug 11 '19 at 10:02
• Having had a rake through the commit history, it looks like gizmo is just a rename of manipulator. I'm guessing these weren't exposed through the API before. – Moog Aug 11 '19 at 19:34

## 4 Answers

Based on my comment:

Are you maybe looking for something like this? In this way it is possible to set the Gizmo loc,rot,scale in the global coordinate system. You simply store the location, rotation and scale in a 4x4 matrix and set that to be the matrix_basis of the gizmo. Due to the self-updating nature of the gizmo this can be set at any time, even at the end (see example).

Here is the code: (Mostly the template with added Matrix myLocRotScale)

import bpy
from bpy.types import (
GizmoGroup,
)

class MyLightWidgetGroup(GizmoGroup):
bl_idname = "OBJECT_GGT_light_test"
bl_label = "Test Light Widget"
bl_space_type = 'VIEW_3D'
bl_region_type = 'WINDOW'
bl_options = {'3D', 'PERSISTENT'}
########### Modified here
myLocRotScale = ((1.0, 0.0, 0.0, 0.0), (0.0, 1.0, 0.0, 0.0), (0.0, 0.0, 1.0, 0.0), (0.0, 0.0, 0.0, 1.0))
@classmethod
def poll(cls, context):
ob = context.object
return (ob and ob.type == 'LIGHT')

def setup(self, context):
# Arrow gizmo has one 'offset' property we can assign to the light energy.
ob = context.object
mpr = self.gizmos.new("GIZMO_GT_arrow_3d")
mpr.target_set_prop("offset", ob.data, "energy")
mpr.matrix_basis = self.myLocRotScale ########### Modified here
mpr.draw_style = 'BOX'

mpr.color = 1.0, 0.5, 0.0
mpr.alpha = 0.5

mpr.color_highlight = 1.0, 0.5, 1.0
mpr.alpha_highlight = 0.5

self.energy_widget = mpr

def refresh(self, context):
ob = context.object
mpr = self.energy_widget
mpr.matrix_basis = self.myLocRotScale ########### Modified here

bpy.utils.register_class(MyLightWidgetGroup)

########### Modified here
MyLightWidgetGroup.myLocRotScale = ((1.0, 0.0, 0.0, 0.0), (1.0, 0.0, 0.0, 0.0), (0.0, 0.0, 1.0, 0.0), (0.0, 3.0, 0.0, 1.0))


Here the myLocRotScale matrix allows you to edit the location rotation and scale of the gizmo (in World space). In the shown example the gizmo is translated by 3 in the y-Direction (see the 4x4 matrix in the last line). The default value for myLocRotScale could be set to ob.matrix_world.normalized() which is the object location, so that the gizmo appears there until you change it.

BTW here is a nice collection of Gizmos: Gizmo types in blender 2.8

• Thank you for you answer. I am really sorry about not foreseeing this misunderstanding, but I thought it would be possible to transform the gizmo by user interaction, not programmatically. I should have been more specific. – Martynas Žiemys Aug 11 '19 at 18:20
• @MartinZ Thank you for clarifying! So if i understand correctly you want to make it possible to move the gizmo around by simple user interaction, which is achieved by enabling this gizmo interaction by programming in python? – Robert Roth Aug 11 '19 at 19:06
• @MartinZ I think the easiest solution to achieve what you describe would be to use an empty with the gizmo you want and then add a line of code in python which sets the transforms of the gizmo (similar to my answer above) to the transform matrix of that empty. Then you can manually scale move and rotate the gizmo indirectly while still having the gizmo functionality. – Robert Roth Aug 11 '19 at 21:01
• I don't need a gizmo for that. The empty itself is enough then. I could have any geometry instead of the empty as well so it can look any way I want as well without a gizmo. I use an empty for this here . I was hoping it can be done with a gizmo instead of creating another object - I mean what's the point of gizmos if you need to create another object anyway?.. It might be possible with target_set_handler though, but I haven't figured out how that could work. – Martynas Žiemys Aug 11 '19 at 21:22
• @MartinZ While an empty might be enough here, the method i described would still be needed if you want to use the gizmo visual appearance and also want the slider and mouse-clickable behaviour of the gizmo. But if you do not need the actual gizmo but only want something to keep track of transforms, then an empty will do just fine. (BTW concerning the project you linked: Even if you would find a way to do what you want without adding another object such as an empty, probably then the "snap to vertex" would stop working) – Robert Roth Aug 11 '19 at 22:43

Playing with Simple Gizmo Template.

Most likely each of the templates other than the simple gizmo, have more of the functionality desired in question. Binding to targets, operators, rotation, using custom shapes.

Since the question gif is the simple template, and since you can work it out yourself "sooner or later" here be a hack around with the simple template, to translate a single arrow and keep that transform in a matrix.

• In original the gizmo mapped its "offset" to the energy property of a lamp. target_set_prop Instead I have given it two callbacks to get and set the property. target_set_handler Just like with binding to an operator target_set_operator it allows for changing object properties during gizmo transform.
• A dummy 4x4 matrix is set up on the window manager. The arrow widget sets its z location in position 2, 3.
• If there is an object named "Cube" in the scene it assigns its local matrix to the dummy matrix
• A class variable is added to keep track of the context object, so the widget has starting point at the active object.

import bpy
from mathutils import Matrix

from bpy.types import (
GizmoGroup,
)

class MyLightWidgetGroup(GizmoGroup):
'''Tool Tip'''
bl_idname = "OBJECT_GGT_light_test"
bl_label = "Test Light Widget"
bl_space_type = 'VIEW_3D'
bl_region_type = 'WINDOW'
bl_options = {'3D', 'PERSISTENT'}
obj = None

@classmethod
def poll(cls, context):
ob = context.object
wm = context.window_manager
return (ob)

def setup(self, context):
wm = context.window_manager
def move_get_cb():
print(wm.xxxx)
return wm.xxxx[2][3]
def move_set_cb(value):
wm.xxxx[2][3] = value

cube = context.scene.objects.get("Cube")
if cube:
cube.matrix_local = wm.xxxx

ob = context.object
mpr = self.gizmos.new("GIZMO_GT_arrow_3d")

mpr.target_set_handler("offset", get=move_get_cb, set=move_set_cb)
mpr.color = 1.0, 0.5, 0.0
mpr.alpha = 0.5

mpr.color_highlight = 0, 0, 1.0
mpr.alpha_highlight = 1

self.energy_widget = mpr

def refresh(self, context):
ob = context.object

wm = context.window_manager

mpr = self.energy_widget
if self.obj is not ob:
mpr.matrix_basis =  (ob.matrix_world).normalized()
wm.xxxx = [c for row in Matrix().transposed() for c in row]

self.obj = context.object

bpy.types.WindowManager.xxxx = bpy.props.FloatVectorProperty(size=16, subtype='MATRIX')

bpy.utils.register_class(MyLightWidgetGroup)

• It seems it's going to be later in that 'sooner or later'. Seems too complicated for what I wanted to do, I'll stick with temporarily creating another object for now. But I i'll also keep trying to figure this out slowly and this is really helpful so I appreciate the answer - thank you. – Martynas Žiemys Aug 12 '19 at 20:04

Gizmos require a target to act upon.

Manipulating the gizmo will act upon either:

• Property
• Operator
• Callback

These are set by calling one of the following methods:

target_set_prop(target, data, property, index=-1)

target_set_operator(operator, index=0)

target_set_handler(target, get, set, range=None)

The second of these return an Operator Properties object which you can then set. Still researching this and need to run some tests but I believe that the second one is what you are looking for. Please see the documentation for these methods

See the gizmo_operator_target.py template for an example using the transform operator.

See the gizmo_operator.py template for an example that performs a more complex operation using the callback method.

Callbacks made easy

It's quite difficult to see what's going on in the template example so I have prepared a simpler version:

def setup(self, context):

arrow = self.gizmos.new("GIZMO_GT_arrow_3d")

def move_get_x():
return context.object.location.x

def move_set_x(value):
context.object.location.x = value

arrow.target_set_handler("offset", get=move_get_x, set=move_set_x)

arrow.matrix_basis = context.object.matrix_world.normalized()

self.x_gizmo = arrow

def refresh(self, context):
self.x_gizmo.matrix_basis = context.object.matrix_world.normalized()


In order to manipulate a gizmo independently you will have to look at the matrix_basis property.

Simply commenting out the last line in the refresh method will leave the gizmo where it first instantiated:

#self.x_gizmo.matrix_basis = context.object.matrix_world.normalized()

If you want to keep the gizmo with the object then you need to update matrix_basis accordingly.

Subclass Gizmo

Another option is to subclass gizmo, unfortunately I haven't had time to write up an example of this but it is another avenue to explore.

You might also want to look at using the matrix_offset to retrieve information about the change.

If this still isn't quite what you're looking for then you can consider using an empty and attach the gizmp to that instead.

You might also want to look at this question.

• Thanks for the answer. I know I can use an empty for this in a modal operator, but then I can also use any temporarily created geometry instead of it that can look like a gizmo... I thought gizmos would be easier to understand when I first heard of them... :/ I still have no clue how to make a gizmo that one could just grab and move or rotate or scale... – Martynas Žiemys Aug 11 '19 at 18:42
• You can't do regular ops on a gizmo from what I understand, they have 3D representation defined by their draw method, but they don't really maintain their own state, this appears to be done by the GizmoGroup which they're declared in. This is why you need an empty (or some other object), something that can be scaled etc. , gizmos only act on events through their invoke and modal methods – Moog Aug 11 '19 at 19:10
• There is always this creative method, not quite what you're lookiing for but could be adapted – Moog Aug 11 '19 at 19:23
• @MartinZ I've added an example using the callback method – Moog Aug 14 '19 at 7:03

I'm a novice in Blender, but as I know, in common - gizmo is a "read-only" property, that represents hidden parallelepiped with sides: MinX(Object)-MaxX(Object), MinY(Object)-MaxY(Object), MinZ(Object)-MaxZ(Object).

So You probably can create standard box, make it hidden and push your object inside.

• Hi, I appreciate you trying to help, however as far as this answer goes I am afraid this not helpful at all. It does not convey any information regarding the matter the way I see it. I'll down-vote the answer as this is definitely not something I would like to award with 500 point bounty and I am afraid I do not see it as useful. I am talking specifically about these gizmos. You can see them working if you try the examples in the Text Editor Template menu. – Martynas Žiemys Aug 4 '19 at 21:15