Spatial gizmo plugins

    This tutorial will show you the two main approaches to defining your own custom gizmos. The first option works well for simple gizmos and creates less clutter in your plugin structure, while the second one will let you store some per-gizmo data.

    Note

    This tutorial assumes you already know how to make generic plugins. If in doubt, refer to the page.

    Regardless of the approach we choose, we will need to create a new EditorSpatialGizmoPlugin. This will allow us to set a name for the new gizmo type and define other behaviors such as whether the gizmo can be hidden or not.

    1. tool
    2. extends EditorPlugin
    3. const MyCustomGizmoPlugin = preload("res://addons/my-addon/MyCustomGizmoPlugin.gd")
    4. var gizmo_plugin = MyCustomGizmoPlugin.new()
    5. func _enter_tree():
    6. add_spatial_gizmo_plugin(gizmo_plugin)
    7. func _exit_tree():
    8. remove_spatial_gizmo_plugin(gizmo_plugin)

    For simple gizmos, just inheriting is enough. If you want to store some per-gizmo data or you are porting a Godot 3.0 gizmo to 3.1+, you should go with the second approach.

    The first step is to, in our custom gizmo plugin, override the has_gizmo() method so that it returns true when the spatial parameter is of our target type.

    Then we can override methods like or all the handle related ones.

    1. # ...
    2. func _init():
    3. create_handle_material("handles")
    4. func redraw(gizmo):
    5. gizmo.clear()
    6. var spatial = gizmo.get_spatial_node()
    7. var lines = PoolVector3Array()
    8. lines.push_back(Vector3(0, 1, 0))
    9. lines.push_back(Vector3(0, spatial.my_custom_value, 0))
    10. var handles = PoolVector3Array()
    11. handles.push_back(Vector3(0, 1, 0))
    12. handles.push_back(Vector3(0, spatial.my_custom_value, 0))
    13. gizmo.add_handles(handles, get_material("handles", gizmo))
    14. # ...

    Note that we created a material in the _init method, and retrieved it in the redraw method using get_material(). This method retrieves one of the material’s variants depending on the state of the gizmo (selected and/or editable).

    Note that we just added some handles in the redraw method, but we still need to implement the rest of handle-related callbacks in to get properly working handles.

    In some cases we want to provide our own implementation of EditorSpatialGizmo, maybe because we want to have some state stored in each gizmo or because we are porting an old gizmo plugin and we don’t want to go through the rewriting process.

    In these cases all we need to do is, in our new gizmo plugin, override , so it returns our custom gizmo implementation for the Spatial nodes we want to target.

    1. # MyCustomGizmoPlugin.gd
    2. extends EditorSpatialGizmoPlugin
    3. const MyCustomSpatial = preload("res://addons/my-addon/MyCustomSpatial.gd")
    4. const MyCustomGizmo = preload("res://addons/my-addon/MyCustomGizmo.gd")
    5. func _init():
    6. create_material("main", Color(1, 0, 0))
    7. create_handle_material("handles")
    8. func create_gizmo(spatial):
    9. if spatial is MyCustomSpatial:
    10. return MyCustomGizmo.new()
    11. else:

    This way all the gizmo logic and drawing methods can be implemented in a new class extending EditorSpatialGizmo, like so: