4
$\begingroup$

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

enter image description here

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.

$\endgroup$
  • $\begingroup$ 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. $\endgroup$ – Frederick Aug 9 at 20:01
  • $\begingroup$ 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. $\endgroup$ – Martin Z Aug 9 at 22:12
  • $\begingroup$ 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/… $\endgroup$ – Robert Roth Aug 11 at 10:02
  • $\begingroup$ 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. $\endgroup$ – Merlin Aug 11 at 19:34
2
$\begingroup$

Based on my comment:

Are you maybe looking for something like this? enter image description here 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

$\endgroup$
  • $\begingroup$ 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. $\endgroup$ – Martin Z Aug 11 at 18:20
  • $\begingroup$ @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? $\endgroup$ – Robert Roth Aug 11 at 19:06
  • $\begingroup$ @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. $\endgroup$ – Robert Roth Aug 11 at 21:01
  • $\begingroup$ 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. $\endgroup$ – Martin Z Aug 11 at 21:22
  • $\begingroup$ @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) $\endgroup$ – Robert Roth Aug 11 at 22:43
2
$\begingroup$

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.

enter image description here

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)
$\endgroup$
  • $\begingroup$ 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. $\endgroup$ – Martin Z Aug 12 at 20:04
2
$\begingroup$

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.

$\endgroup$
  • $\begingroup$ 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... $\endgroup$ – Martin Z Aug 11 at 18:42
  • $\begingroup$ 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 $\endgroup$ – Merlin Aug 11 at 19:10
  • $\begingroup$ There is always this creative method, not quite what you're lookiing for but could be adapted $\endgroup$ – Merlin Aug 11 at 19:23
  • $\begingroup$ @MartinZ I've added an example using the callback method $\endgroup$ – Merlin Aug 14 at 7:03
-2
$\begingroup$

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.

$\endgroup$
  • 5
    $\begingroup$ 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. $\endgroup$ – Martin Z Aug 4 at 21:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.