EditorNode3DGizmo in Godot – Complete Guide

Welcome to our tutorial on the EditorNode3DGizmo class in Godot 4. This powerful feature might not be something you’ve heard about before, but it’s an essential part of creating custom tools within the robust Godot editor. As you start your journey into game development or look to deepen your understanding of Godot’s inner workings, learning about gizmos can give you the skills to customize and enhance your development workspace profoundly. They form the backbone of visual editing and can be the key to unlocking a more streamlined and intuitive design process.

What is EditorNode3DGizmo?

EditorNode3DGizmo is a class derived from Node3DGizmo in the Godot game engine. A gizmo is a visual tool that helps game developers to interact with 3D objects within the editor environment. They enable you to move, scale, rotate, and manipulate game elements more efficiently, acting as a visual aid and an interactive interface for precise transformations and modifications.

What is it for?

The EditorNode3DGizmo’s purpose is clear; it’s there to boost your efficiency and make the game development workflow feel more natural. Specifically, it allows for the creation of custom gizmos within the Godot editor. These gizmos can vary in complexity from simple visual references to complex interactive tools that can assist with object placement, environmental building, and parameter tweaking in real-time.

Why should I learn it?

Grasping the EditorNode3DGizmo can make a massive difference in your development process:

– **Customization:** Tailor the editor environment to match your workflow, leading to a more personal and optimized game creation experience.
– **Productivity:** Speed up common tasks with intuitive tools that reduce the time spent wrestling with object transformations.
– **Precision:** Fine-tune object properties visually, ensuring that every adjustment is made with maximum accuracy.

Understanding gizmos and their customization will empower you to take control of the Godot editor, bending it to your will, and consequently, improving your overall productivity and enjoyment as a developer. Now, let’s dive into how you can implement these versatile tools with hands-on examples.

CTA Small Image
FREE COURSES AT ZENVA
LEARN GAME DEVELOPMENT, PYTHON AND MORE
ACCESS FOR FREE
AVAILABLE FOR A LIMITED TIME ONLY

Creating a Simple Custom Gizmo in Godot

To start creating a custom gizmo, you first need to derive a new class from EditorNode3DGizmo. Let’s begin by defining a simple gizmo that could, for example, be used to visualize the bounding box of a node.

extends EditorNode3DGizmo

func _init():
    # Example: Set up your gizmo here

Next, we need to add this gizmo to the list of gizmos that are available within the editor. This can be done by implementing the `_create()` function.

func _create():
    # Example: Add gizmo to the editor
    add_gizmo_to_library(your_custom_gizmo)

In the two pieces of code above, we’re initializing our gizmo and also providing a hook to be able to introduce it to the editor. Now it’s time to define the gizmo’s appearance and how it should look in the 3D view.

Defining Gizmo Appearance

You need to override the `_draw()` method to define the appearance of your gizmo. In this example, let’s create a simple 3D cube to represent our bounding box.

extends EditorNode3DGizmo

func _draw():
    # Draw a simple cube
    draw_handle(BoxShape.new(), true)

It’s often beneficial to give interactive capabilities to your gizmo for manipulating the associated object directly in the scene. This is where the `_is_selectable_when_hidden()` function becomes useful.

func _is_selectable_when_hidden():
    # Make sure the gizmo is selectable, even when the object is hidden
    return true

The code above ensures that your gizmo can be selected even if the main object it is associated with is not visible.

Interacting with the Gizmo

For the gizmo to be interactive, you must define how it behaves when a user interacts with it. You can define this behavior by implementing the `_intersect_ray()` method.

func _intersect_ray(camera_ray_origin, camera_ray_direction):
    # Define how the gizmo will respond to ray intersection
    # Check intersection with the shape - in this case, a box
    return your_shape_intersection_logic(camera_ray_origin, camera_ray_direction)

You can use the `_intersect_ray()` function to detect clicks on your gizmo and to make your gizmo react correctly to the user’s input.

Manipulating the Associated Object

Once a gizmo is interactive, you might want to manipulate the object it’s connected to. To move an object based on gizmo manipulation, you would handle the logic in the `_commit_handle()` method.

func _commit_handle(handle, restore, cancel):
    # Movement logic for gizmo handle
    if handle == your_handle_id:
        if cancel:
            # Logic to cancel manipulation (e.g., restore original position)
        else:
            # Logic to commit manipulation (e.g., apply new position)

The code above shows how you might initiate a process to alter the position of the object associated with the gizmo.

In the next part of our tutorial, we’ll delve into more advanced interactions and how to refine the feedback your gizmos provide, enhancing both visual cues and user input handling to create a polished and professional toolset for the Godot editor.Implementing advanced interactions with your custom gizmo requires a good understanding of both the gizmo’s context and the Editor’s response to user actions. For instance, when a user clicks and drags a gizmo handle, we want to manipulate the object in real-time.

For a more refined example, let’s say our gizmo is used to scale a 3D object on the Y-axis. We need to provide visual feedback and apply the scaling dynamically as the user interacts with the gizmo.

Visual Feedback and Dynamic Manipulation

The first step in creating this dynamic response is to track the handle being interacted with and change its color to indicate it’s active. We’ll override the `_draw()` method to add this logic.

func _draw():
    var color = Color(1, 1, 1) # White color as default
    if is_handle_highlighted(y_handle):
        color = Color(0.8, 0.8, 0) # Yellow when highlighted
    # Here we use a cylinder to represent the Y-axis handle
    draw_handle(CylinderShape.new(), true, Transform().scaled(Vector3(0.1, 0.1, 0.1)), color)

As the user interacts, we need to interpret mouse movements in terms of scaling. We’ll leverage the `EditorNode3DGizmo`’s ability to track mouse deltas in the `_compute_handle_drag()` method.

func _compute_handle_drag(handle, camera, camera_ray_start, camera_ray_pos):
    # Logic to compute dragging of the handle
    # We assume handle is for scaling along the Y-axis
    var scale_value = some_conversion_from_mouse_delta_to_scale_factor(camera_ray_start, camera_ray_pos)
    return Transform().scaled(Vector3(1, scale_value, 1))

When the user releases the mouse button, we want to save this new scale as the final transformation. The `_commit_handle()` function is where we finalize the manipulation.

func _commit_handle(handle, restore, cancel):
    var node = get_edited_object()
    if handle == y_handle && !cancel:
        var new_scale = get_handle_transform(handle).basis.get_scale()
        node.scale = new_scale

Providing additional real-time visual feedback can also be done through drawing lines or other shapes that extend from the gizmo to other points of interest. Let’s demonstrate how to draw a line when the gizmo is active:

func _draw():
    # ... Previous drawing code 
    if is_handle_highlighted(y_handle):
        # Draw a line extending from the handle position upwards
        draw_line(get_handle_position(y_handle), get_handle_position(y_handle) + Vector3(0, 10, 0), Color(1, 0, 0))

If our gizmo requires snapping to a grid or specific intervals during scaling, we must implement this in the scaling logic flow:

func _compute_handle_drag(handle, camera, camera_ray_start, camera_ray_pos):
    # ... Previous logic to compute dragging
    scale_value = snap_scale_to_grid(scale_value, grid_interval) # Assuming we've defined this function elsewhere
    # ... Rest of the method

Lastly, to make the interaction as smooth as possible, sometimes you would want to offset the gizmo’s interaction, so the starting point of the drag has a predetermined offset, giving the user a more controlled experience:

func _get_handle_drag_offset(handle):
    if handle == y_handle:
        return Vector3(0, 1, 0) # Provide an offset for Y-axis handle
    return Vector3.ZERO

As you can see, creating a custom gizmo involves handling various aspects of user interaction, drawing visual cues, and updating object transformations in response to user actions. The examples provided in this tutorial should give you the foundation to build gizmos that cater to your specific development needs, leading to a more efficient and customized game creation process within the Godot editor.To enrich the custom gizmo experience further, let’s dive into additional practical code examples. These will build upon our initial framework and enhance the gizmo functionality even more.

When working with 3D gizmos, providing multiple interaction modes can be beneficial. For example, allowing a single gizmo to handle both scaling and rotation:

var current_mode = "scale" # We can toggling between "scale" and "rotate"

func _draw():
    # Switch gizmo drawing based on current mode
    if current_mode == "scale":
        # Call your drawing function for scale handles
    elif current_mode == "rotate":
        # Call your drawing function for rotation handles

The user should be able to switch modes, perhaps with a shortcut or a UI button. Implementing a mode switch could look like this:

func _input_event(viewport, event, shape_idx):
    if event is InputEventKey and event.pressed and event.scancode == KEY_S:
        current_mode = "scale" if current_mode != "scale" else "rotate"
        update_gizmo()

Once the mode is switched, the gizmo needs to provide the correct interaction. Here’s how you might implement the rotation in the `_compute_handle_drag()` method:

func _compute_handle_drag(handle, camera, camera_ray_start, camera_ray_pos):
    match current_mode:
        "scale":
            var scale_value = get_scale_value_from_mouse(camera_ray_start, camera_ray_pos)
            return Transform().scaled(Vector3(1, scale_value, 1))
        "rotate":
            var rotation_angle = get_rotation_angle_from_mouse(camera_ray_start, camera_ray_pos)
            return Transform().rotated(Vector3(0, 1, 0), rotation_angle)

To change the gizmo’s interaction feedback based on the mode, you adjust the `_draw()` method accordingly:

func _draw():
    match current_mode:
        "scale":
            # Draw scale handles
        "rotate":
            # Draw rotation handles or arcs

It’s essential to ensure the gizmo’s appearance and behavior are intuitive to the user, so consider highlighting the active mode visually. For example, change the color of the handles based on what mode is active:

func _draw():
    match current_mode:
        "scale":
            draw_handle(your_scale_gizmo_shape, true, Transform(), is_active_mode("scale") ? Color(0, 1, 0) : Color(1, 1, 1))
        "rotate":
            draw_handle(your_rotate_gizmo_shape, true, Transform(), is_active_mode("rotate") ? Color(1, 0.5, 0) : Color(1, 1, 1))

Finally, handling undo and redo functionality is crucial for any interactive editor tool. Here’s a simple way to push an undo state when a gizmo manipulation is committed:

func _commit_handle(handle, restore, cancel):
    var node = get_edited_object()
    if handle == y_handle and !cancel:
        # Before applying changes, push the current state to the undo stack
        push_undo_state(node, "Transform")
        # Apply changes...

With these advanced interactions in your custom gizmo, you unleash powerful capabilities to manipulate objects in your Godot scenes with precision and efficiency. The code examples provided give a glimpse into the potential of custom tools, and with creativity, you can craft gizmos that finely tune to your workflow, making game development in Godot not only more productive but also more enjoyable.

Continuing Your Journey in Game Development

If you’ve enjoyed learning about the intricacies of the EditorNode3DGizmo class and customizing tools in Godot, your journey in game development is just beginning. There’s a world of knowledge and expertise waiting for you, and we’re here to guide you every step of the way. Our Godot Game Development Mini-Degree is the perfect next milestone to aim for. This comprehensive program will help you build a solid foundation in game development using the versatile Godot engine, covering a range of essential topics from GDScript programming to in-depth game mechanics.

At Zenva, we understand the importance of practical experience. That’s why our courses focus on hands-on learning that equips you with the skills and confidence to create your own games from scratch. Beyond just the tools, we delve into the creative and technical aspects of 2D and 3D game development that are fundamental to bringing your unique vision to life in the gaming world.

If you’re looking to explore a wider array of game development concepts within Godot, make sure to check out our full collection of Godot courses. Here, you’ll find content suitable for all skill levels, whether you are taking your first steps or looking to specialize further. With Zenva, you can go from a beginner to a professional game developer, unlocking your potential and expanding your creative horizons.

Conclusion

Embracing the power of custom gizmos with the EditorNode3DGizmo in Godot can transform the way you create games, offering a level of customization that paves the way for a smoother and more intuitive design process. By taking what you’ve learned here and applying it to your projects, you’re setting the stage for unparalleled efficiency and precision in game development. And remember, this is only a fraction of what you can achieve with the right knowledge and tools at your disposal.

Take the next leap in your game development journey with us at Zenva by exploring our Godot Game Development Mini-Degree, where you’ll gain the expertise to take full advantage of Godot’s capabilities. Whether you’re refining your current game project or starting an entirely new one, our courses will provide you with the knowledge to thrive in this exciting industry. Happy coding, and we can’t wait to see what you’ll create!

FREE COURSES
Python Blog Image

FINAL DAYS: Unlock coding courses in Unity, Godot, Unreal, Python and more.