Skip to content
guntrumm edited this page Nov 1, 2023 · 11 revisions

General Usage πŸ“’

Before you can open a GraphWindow you need to define the entry point/ menu entry. To get things up & running quickly you can simply download the WindowInitializer sample package.

image

From there these are the next steps:

  1. Go to Tools/GraphWindow to Open the graph window. This is your hub where all graphs are created.
  2. Click on the "Create" button to create your first graph.
  3. To spawn/add nodes to your graph open the context menu via right click.
  4. Per default you can only create the CommentNode and the GroupCommentNode. See the next section to learn how to expose your own classes as nodes.

Developing new Nodes 🎫

Creating new Nodes is done by adding certain Attributes ([Node],[Port],[GraphDisplay],[PortList]) and implement the INode interface in a serializable class.

Example πŸ“‹

// Make sure your class is serializable
// And add the Node attribute. Here you can define a special color for your node as well as organize it with subcategories.
[Serializable, Node("#007F00FF", "Special")]
public class AnotherTestNode : INode { // Make sure to implement the INode interface so the graph can serialize this easily.
    // with the Portattribute you can create visual connectable ports in the graph view to connect to other nodes.
    // it is important to also add the SerializeReference attribute, so that unity serializes this field as a reference.
    [Port, SerializeReference]
    public TestNode output = null;
    
    // With the PortList attribute you can instruct the graph view to visualize a dynamic list of ports. 
    [PortList, SerializeReference]
    public List<TestNode> dataList;

    [Serializable]
    public class SpecialData {
        [Port, SerializeReference] // You can assign ports and all other attributes in nested classes!
        public TestNode anotherOutput = null;
        // Per default, all data will show up automatically in the side inspector in the GraphView.
        // if you wish to display something directly on the node use the GraphDisplay attribute.
        [GraphDisplay(DisplayType.BothViews)] // DisplayType.BothViews visualizes this field both in the inspector and the node itself. 
        public bool toggle;
    }
    public SpecialData specialData;
}

After adding the required attributes and implementing the interface your node should be immediately available in the GraphView.

Attributes & Interfaces πŸ“œ

INode

  • Every class that should show up as a node needs to implement the INode interface in addition to the Node attribute.
  • This interface is completely empty and does not have any additional requirements.

[Node]

  • This attribute needs to be added to every class that should show up as a Node in the graph.

The node attribute contains 6 optional fields:

  • Color: Provide a hex code to tint the node in a custom color. The following format is required: #RRGGBBAA (Example: #ff0000ff for fully red)
  • Categories: Define optional sub categories for the context menu. Format requirements: "SubCategory/SubSubCategory/".
  • InputPortCapacity: Define if multiple nodes are allowed to connect to this node. Default: Allow Multiple connections.
  • InputPortName: Define a custom name for the automatically created input port.
  • NodeName : Define a custom name for the whole node.
  • CreateInputPort : Should an input port be created? Default: true.

[Port]

  • This attribute needs to be added to every field that should receive a connectable port.
  • In addition to the [Port] attribute every field also requires a [SerializeReference] attribute.
  • Commonly you want to add the [Port] attribute to every field that should reference another node.

The Port attribute contains 1 optional field:

  • name: Define a custom name for this port that is different from the field name.

[PortList]

  • This attribute needs to be added to every field that represents a list of connectable ports.
  • In addition to the [PortList] attribute every field using this attribute also requires a [SerializeReference] attribute.
  • Commonly if you require a list of referenceable nodes, you want to add this list.

[GraphDisplay]

  • This is an optional property that can be added to any field of a node enabled class.
  • With this you can control how and where this field should be visualized.

You can provide 3 fields:

  • DisplayType: Control how and where this field should be visualized. Possible values: Hide, Inspector, NodeView, BothViews
  • Editability: Control where the field is editable. Possible values: None, Inspector, NodeView, BothViews
  • CreateGroup: Control if a foldout should be created if the tagged field is a class, struct or managedReference

[PortBase]

  • This is a more configurable version of the [Port] attribute. This only needs to be used if you really need to tweak the port creation behavior.

You can provide 3 fields:

  • Capacity: Should this port allow more than one connection? (This rarely makes sense as naturally only one value can be applied to one field.)
  • Direction: Is this an input port or an output port? (Commonly you want it to be an output port, as every node already auto generates its own input port)
  • ConnectionPolicy: Which types of nodes are allowed to connect? Only a an exactly matching class? Or should subclasses be allowed as well?

Utility Nodes πŸ“

Utility nodes are meant to be editor only and are stripped away on runtime. They allow you to do pretty much anything, including operating on custom data, custom UI and custom logic.

Default Utility Nodes

A small set of utility nodes is available per default. Here is a list of all Utility Nodes that you can use right away.

CommentNode

commentNode

This node allows you to write a comment with auto resizing and renaming capabilities.

GroupCommentNode

GroupCommentNode

This node allows you to write a comment just like the CommentNode but it also lets you frame/group a section of nodes that can also be moved together. You might know this functionality from ShaderGraph, Substance Designer, Blender or other tools that feature a node graph framework.


Creation Process

  1. To create a Utility Node you need to make sure you are in an Editor only environment by either using the Editor magic folder or an editor only assembly definition file.
  2. A class that should become a UtilityNode needs to implement INode & IUtilityNode interfaces.

Example πŸ“‹

using UnityEngine.UIElements;

namespace NewGraph {
    [Node("#00000001")]
    public class CommentNode : INode, IUtilityNode { // To create UtilityNode you'll need to implement the IUtilityNode interface in addition to INode

        // Should a menu for the inspector be created?
        public bool CreateInspectorUI() => false;
        
        // Should a UI for the name property be shown?
        public bool CreateNameUI() => true;

        // Should the background be automatically colorized?
        public bool ShouldColorizeBackground() => true;

        // Initialization method where you can define any custom menu creation logic
        // Here you'll be provided with the controller object of this node which allows you to access any data.
        public void Initialize(NodeController nodeController) {
            
            NodeView nodeView = nodeController.nodeView;

            // we need auto resizing, so the comment node expands to the full width of the provided text...
            nodeView.style.width = StyleKeyword.Auto;
            nodeView.AddToClassList(nameof(CommentNode));

            // comment node is a very special snowflake... :D
            // So: We completely remove all the default ui
            nodeView.ExtensionContainer.RemoveFromHierarchy();
            nodeView.InputContainer.RemoveFromHierarchy();
            nodeView.OutputContainer.RemoveFromHierarchy();
        }
    }
}

Custom Node Editor 🎨

You can completely customize every Node you create by creating a custom node editor for your node. If you know Unity's CustomEditor functionality for MonoBehaviour: This should seem very familiar.

Creation Process

  1. Create a new class in an editor environment (Editor magic folder, etc.)
  2. Preferably name it like so: <YourNodeClassName>Editor
  3. Derive the class from NodeEditor
  4. Implement the Initialize method from the abstract NodeEditor base class.
  5. Add the [CustomNodeEditor] attribute to your newly created class and specify the node type this editor should be attached to.
  6. Do whatever you want to do in the Initialize method. You'll have access to the nodeController which gives you maximum freedom & access.

Example πŸ“‹

using NewGraph;
using UnityEngine.UIElements;

// add the CustomNodeEditor attribute to your NodeEditor class
// make sure to specify the nodeType this NodeEditor should be attached to.
// optionally you can also set a bool flag (editorForChildClasses) to re-use the same NodeEditor in child classes.
[CustomNodeEditor(typeof(DifferentNode))]
public class DifferentNodeEditor : NodeEditor { // don't forget to derive from NodeEditor!
    // Initialize is called after the base NodeView was created.
    // You'll be provided with the nodeController object from where you can modify nearly everything.
    public override void Initialize(NodeController nodeController) {
        nodeController.nodeView.TitleContainer.Add(new Label("Modded label"));
    }
}

[CustomNodeEditor]

  • This attribute needs to be attached to a class that derives from NodeEditor. This is the glue needed to automatically inject/create the defined editor for a specific node type.

You can provide 2 fields:

  • NodeType: This field is required and should contain the node type the node editor belongs to.
  • EditorForChildClasses: This is an optional field that defaults to false. It can be used to re-use the same node editor on derived nodes.

Custom Context Menu 🎨

You can completely customize the searchable right click context menu by using the [CustomContextMenu] attribute and inheriting from ContextMenu on a custom class. This is similar to creating a custom node editor.

Creation Process

  1. Create a new class in an editor environment (Editor magic folder, etc.)
  2. Derive the class from ContextMenu
  3. Add the [CustomContextMenu] attribute to your newly created class.
  4. Do whatever you want to do in your custom context menu by overriding exiting methods.

Example πŸ“‹

using UnityEngine;
using NewGraph;

/// <summary>
/// Example to create a custom context menu.
/// Inherit from NewGraph.ContextMenu and add the [CustomContextMenu].
/// Please note: There can only be one custom context menu for the whole graph.
/// </summary>
[CustomContextMenu]
public class CustomMenu : NewGraph.ContextMenu {

    /// <summary>
    /// Customize the main label for this menu.
    /// </summary>
    /// <returns></returns>
    protected override string GetHeader() {
        return "My Custom Header";
    }

    /// <summary>
    /// Modify the main node entries.
    /// </summary>
    protected override void AddNodeEntries() {
        base.AddNodeEntries();
        AddNodeEntry("custom/menu/item", (obj) => {
            Debug.Log("custom menu item was clicked!");
        });
    }
}

[CustomContextMenu]

  • This attribute needs to be added to a custom class that derives from ContextMenu. Please note that there can only be ONE custom context menu class for the whole graph. This attributes has no options.

Custom "Edge Drop" Menu 🎨

You can completely customize the searchable edge drop menu by using the [CustomEdgeDropMenu] attribute and inheriting from EdgeDropMenu on a custom class. This is similar to creating a custom node editor.

Creation Process

  1. Create a new class in an editor environment (Editor magic folder, etc.)
  2. Derive the class from EdgeDropMenu
  3. Add the [CustomEdgeDropMenu] attribute to your newly created class.
  4. Do whatever you want to do in your custom edge drop menu by overriding exiting methods.

Example πŸ“‹

using NewGraph;
using UnityEngine;

/// <summary>
/// Example to create a custom edge drop menu.
/// Inherit from EdgeDropMenu and add the [CustomEdgeDropMenu].
/// Please note: There can only be one custom edge drop menu for the whole graph.
/// </summary>
[CustomEdgeDropMenu]
public class CustomEdgeDropMenu : EdgeDropMenu {
    /// <summary>
    /// Customize the main label for this menu.
    /// </summary>
    /// <returns></returns>
    protected override string GetHeader() {
        return "My Custom Edge Drop";
    }

    /// <summary>
    /// Modify the main node entries.
    /// </summary>
    protected override void AddNodeEntries() {
        base.AddNodeEntries();
        AddNodeEntry("custom/menu/edgedropitem", (obj) => {
            Debug.Log("custom edge drop item was clicked!");
        });
    }
}

[CustomEdgeDropMenu]

  • This attribute needs to be added to a custom class that derives from EdgeDropMenu. Please note that there can only be ONE custom edge drop menu class for the whole graph. This attributes has no options.