Voxel Plugin
1.2 Legacy
1.2 Legacy
  • Getting Started
    • Quick Start
      • Examples
    • World Generation
      • C++ World Generators
      • Voxel Graph Quick Start
      • Floating Islands
  • Core Systems
    • VoxelWorlds
      • Import Content
      • Voxel Data Items
      • Collisions and Navmesh
      • World Size and Level Of Details
      • Save and Load
      • Multiplayer
      • Easy Systems RPG
    • Voxel Graphs
      • Voxel Graph General Concepts
      • Voxel Graphs Tips and Tricks
      • Voxel Graph Nodes Reference
      • Voxel Graph Outputs
      • Voxel Graph Parameters
      • Custom Graph Nodes
    • Voxel Spawners
    • Materials
      • Multi Index Materials
  • Technical Notes
    • Performance and Profiling
    • Console Commands
    • Blueprint API
    • Release Notes
      • Release Notes 1.1
      • Release Notes 1.2
    • UE5.1 - Material Crash
Powered by GitBook
On this page
  • Quick start
  • Range analysis examples
  • Supporting C++ translation
  • Compact nodes
  • Node that uses X/Y/Z

Was this helpful?

  1. Core Systems
  2. Voxel Graphs

Custom Graph Nodes

Creating custom voxel graph nodes is really easy!

Quick start

First, add the VoxelGraphmodule dependency to your build.cs.

Then, create a class similar to this:

#include "VoxelNodes/VoxelNodeHelpers.h"

// Return atan2(Y, X) <- tooltip
UCLASS(meta = (DisplayName = "Atan2"))
class YOURMODULE_API UVoxelNode_Atan2 : public UVoxelNodeHelper
{
    GENERATED_BODY()
    GENERATED_VOXELNODE_BODY()

public:
    UVoxelNode_Atan2()
    {
        SetInputs(EC::Float, "Y", EC::Float, "X");
        SetOutputs(EC::Float);
    }

    GENERATED_COMPUTENODE
    (
        DEFINE_INPUTS_REVERSED(float, float),
        DEFINE_OUTPUTS_REVERSED(float),
        _O0 = UVoxelNode_Atan2::Atan2(_I0, _I1);
    )

public:
    static float Atan2(float Y, float X)
    {
        return FMath::Atan2(Y, X);
    }
    static TVoxelRange<float> Atan2(const TVoxelRange<float>& Y, const TVoxelRange<float>& X)
    {
        return { -4, 4 };
    }
};

Atan2(float, float)is where the real computation happens.

Atan2(TVoxelRange, TVoxelRange)is for range analysis: here, the output will always be between -4 and 4.

Range analysis examples

Here are some examples of range analysis functions:

inline TVoxelRange<int> RoundToInt(const TVoxelRange<float>& Value)
{
    return { FMath::FloorToInt(Value.Min), FMath::CeilToInt(Value.Max) };
}
inline TVoxelRange<float> Lerp(const TVoxelRange<float>& A, const TVoxelRange<float>& B, const TVoxelRange<float>& Alpha)
{
    return A + Alpha * (B - A);
}
inline TVoxelRange<float> Tan(const TVoxelRange<float>& A)
{
    if (A.IsSingleValue())
    {
        return { FMath::Tan(A.Min), FMath::Tan(A.Max) };
    }
    else
    {
        return { MIN_flt, MAX_flt };
    }
}

You can use the Minand Max fields of voxel ranges. They also support basic arithmetic operators (* / + -). If you can't compute a range for those inputs, either call FVoxelRangeFailStatus::Fail() to show an error to the user or return min inf, max inf.

Supporting C++ translation

When compiling a voxel graph to C++, the code you put in GENERATED_COMPUTENODEwill be copied to the C++ file. However, if you are using functions (eg here UVoxelNode_Atan2::Atan2), those won't be included in the generated file.

To fix that, you need to add a custom include, like done here:

// Return atan2(Y, X) <- tooltip
UCLASS(meta = (DisplayName = "Atan2"))
class YOURMODULE_API UVoxelNode_Atan2 : public UVoxelNodeHelper
{
    GENERATED_BODY()
    GENERATED_VOXELNODE_BODY()

public:
    UVoxelNode_Atan2()
    {
        SetInputs(EC::Float, "Y", EC::Float, "X");
        SetOutputs(EC::Float);
    }

    class FLocalVoxelComputeNode : public FVoxelDataComputeNode
    {
    public:
        GENERATED_DATA_COMPUTE_NODE_BODY()

        using FVoxelDataComputeNode::FVoxelDataComputeNode;
        GENERATED_COMPUTE
        (
            DEFINE_INPUTS_REVERSED(float, float),
            DEFINE_OUTPUTS_REVERSED(float),
            _O0 = UVoxelNode_Atan2::Atan2(_I0, _I1);
        )
        void SetupCpp(FVoxelCppConfig& Config) const override
        {
            Config.AddInclude("MyInclude.h");
        }
    };

public:
    static float Atan2(float Y, float X)
    {
        return FMath::Atan2(Y, X);
    }
    static TVoxelRange<float> Atan2(const TVoxelRange<float>& Y, const TVoxelRange<float>& X)
    {
        return { -4, 4 };
    }
};

Compact nodes

By default, nodes look like this:

Sometimes you want to have a more compact look, like here:

To do that, add COMPACT_VOXELNODE("ATAN2") below GENERATED_VOXELNODE_BODY().

Node that uses X/Y/Z

You can access X/Y/Z in GENERATED_COMPUTE by using _C0: for instance, _C0.X + _C0.Y - _C0.Z.

However, if you do so, you need to tell the voxel graph compiler that you are using those coordinates. To do that, use the SET_NODE_DEPENDENCIES macro:

Add

SET_NODE_DEPENDENCIES(EVoxelAxisDependenciesFlags::XYZ) // Or X Y XY XZ YZ depending on what you're using

below GENERATED_VOXELNODE_BODY().

PreviousVoxel Graph ParametersNextVoxel Spawners

Last updated 1 year ago

Was this helpful?