Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

Estensioni di gizmo 3D

Introduzione

Le estensioni dei gizmo 3D sono utilizzate dall'editor e dalle estensioni personalizzate per definire i gizmo collegati a qualsiasi tipo di nodo Node3D.

Questo tutorial illustra i due approcci principali per definire i propri gizmo personalizzati. La prima opzione è ideale per gizmo semplici e crea meno ingombro nella struttura delle proprie estensione, mentre la seconda consente di memorizzare alcuni dati per ogni gizmo.

Nota

Questo tutorial presuppone che si sappia già come creare estensioni generiche. Se in dubbio, consultare la pagina Creare estenzioni.

L'EditorNode3DGizmoPlugin

A prescindere dall'approccio scelto, dovremo creare un nuovo EditorNode3DGizmoPlugin. Questo ci permetterà di impostare un nome per il nuovo tipo di gizmo e di definire altri comportamenti, come ad esempio se il gizmo può essere nascosto o meno.

Questa sarebbe una configurazione basilare:

# my_custom_gizmo_plugin.gd
extends EditorNode3DGizmoPlugin


func _get_gizmo_name():
    return "CustomNode"
# MyCustomEditorPlugin.gd
@tool
extends EditorPlugin


const MyCustomGizmoPlugin = preload("res://addons/my-addon/my_custom_gizmo_plugin.gd")

var gizmo_plugin = MyCustomGizmoPlugin.new()


func _enter_tree():
    add_node_3d_gizmo_plugin(gizmo_plugin)


func _exit_tree():
    remove_node_3d_gizmo_plugin(gizmo_plugin)

Per i gizmo più semplici, basta ereditare EditorNode3DGizmoPlugin. Se si desidera memorizzare dati per ogni gizmo, è consigliabile adottare il secondo approccio.

Approccio semplice

Il primo passo è quello di sovrascrivere il metodo _has_gizmo() nella nostra estensione gizmo personalizzata in modo che restituisca true quando il parametro node è del nostro tipo da influenzare.

# ...


func _has_gizmo(node):
    return node is MyCustomNode3D


# ...

Successivamente possiamo sovrascrivere metodi come _redraw() o tutti quelli che riguardano gli handle.

# ...


func _init():
    create_material("main", Color(1, 0, 0))
    create_handle_material("handles")


func _redraw(gizmo):
    gizmo.clear()

    var node3d = gizmo.get_node_3d()

    var lines = PackedVector3Array()

    lines.push_back(Vector3(0, 1, 0))
    lines.push_back(Vector3(0, node3d.my_custom_value, 0))

    var handles = PackedVector3Array()

    handles.push_back(Vector3(0, 1, 0))
    handles.push_back(Vector3(0, node3d.my_custom_value, 0))

    gizmo.add_lines(lines, get_material("main", gizmo), false)
    gizmo.add_handles(handles, get_material("handles", gizmo), [])


# ...

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).

Pertanto l'estensione finale sarebbe simile a questa:

extends EditorNode3DGizmoPlugin


const MyCustomNode3D = preload("res://addons/my-addon/my_custom_node_3d.gd")


func _init():
    create_material("main", Color(1,0,0))
    create_handle_material("handles")


func _has_gizmo(node):
    return node is MyCustomNode3D


func _redraw(gizmo):
    gizmo.clear()

    var node3d = gizmo.get_node_3d()

    var lines = PackedVector3Array()

    lines.push_back(Vector3(0, 1, 0))
    lines.push_back(Vector3(0, node3d.my_custom_value, 0))

    var handles = PackedVector3Array()

    handles.push_back(Vector3(0, 1, 0))
    handles.push_back(Vector3(0, node3d.my_custom_value, 0))

    gizmo.add_lines(lines, get_material("main", gizmo), false)
    gizmo.add_handles(handles, get_material("handles", gizmo), [])


# You should implement the rest of handle-related callbacks
# (_get_handle_name(), _get_handle_value(), _commit_handle(), ...).

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

Approccio alternativo

In alcuni casi vogliamo fornire la nostra implementazione di EditorNode3DGizmo, magari perché vogliamo che uno stato sia memorizzato in ogni gizmo o perché stiamo trasferendo una vecchia estensione gizmo e non vogliamo riscriverla del tutto.

In questi casi, tutto ciò che dobbiamo fare è sovrascrivere _create_gizmo() nella nostra nuova estensione gizmo, in modo che sia restituita la nostra implementazione gizmo personalizzata per i nodi Node3D che vogliamo influenzare.

# my_custom_gizmo_plugin.gd
extends EditorNode3DGizmoPlugin


const MyCustomNode3D = preload("res://addons/my-addon/my_custom_node_3d.gd")
const MyCustomGizmo = preload("res://addons/my-addon/my_custom_gizmo.gd")


func _init():
    create_material("main", Color(1, 0, 0))
    create_handle_material("handles")


func _create_gizmo(node):
    if node is MyCustomNode3D:
        return MyCustomGizmo.new()
    else:
        return null

In questo modo tutta la logica e i metodi di disegno dei gizmo possono essere implementati in una nuova classe che estende EditorNode3DGizmo, così:

# my_custom_gizmo.gd
extends EditorNode3DGizmo


# You can store data in the gizmo itself (more useful when working with handles).
var gizmo_size = 3.0


func _redraw():
    clear()

    var node3d = get_node_3d()

    var lines = PackedVector3Array()

    lines.push_back(Vector3(0, 1, 0))
    lines.push_back(Vector3(gizmo_size, node3d.my_custom_value, 0))

    var handles = PackedVector3Array()

    handles.push_back(Vector3(0, 1, 0))
    handles.push_back(Vector3(gizmo_size, node3d.my_custom_value, 0))

    var material = get_plugin().get_material("main", self)
    add_lines(lines, material, false)

    var handles_material = get_plugin().get_material("handles", self)
    add_handles(handles, handles_material, [])


# You should implement the rest of handle-related callbacks
# (_get_handle_name(), _get_handle_value(), _commit_handle(), ...).

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