Open Search
    Providing Preview Images for Nodes

    Table of Contents

    Describes how to implement a preview image for a node in the Node Editor.

    Code

    Preview images are created with an implementation of PreviewImageProviderInterface.

    // This is the id that identify the component
    static maxon::Id g_nodeRendererPreviewProvider = maxon::Id("net.maxonexample.handbook.class.noderendererpreviewprovider");
    class PreviewImageProviderExampleHandbook : public maxon::Component<PreviewImageProviderExampleHandbook, maxon::nodes::PreviewImageProviderInterface>
    {
    public:
    MAXON_METHOD maxon::Result<void> Initialize(maxon::DataDictionaryObjectRef request, maxon::Int numThreads);
    MAXON_METHOD maxon::Result<void> ComputeIteration(const maxon::JobRef parentThread);
    private:
    maxon::Id _assetID;
    maxon::IntVector2d _imageSize;
    maxon::NodePath _nodePath;
    maxon::Bool _final;
    };
    Definition: baseref.h:62
    Definition: objectbase.h:2651
    Definition: apibaseid.h:253
    Reference to a job (JobInterface).
    Definition: job.h:1222
    Int64 Int
    signed 32/64 bit int, size depends on the platform
    Definition: apibase.h:188
    bool Bool
    boolean type, possible values are only false/true, 8 bit
    Definition: apibase.h:181
    @ NORMAL
    Samples the surface as the user moves over it the SculptObject and returns a new hit point and normal...
    #define MAXON_COMPONENT(KIND,...)
    Definition: objectbase.h:2212
    #define MAXON_METHOD
    Definition: interfacebase.h:1001

    The image provider must be registered within the NodeSpaceInterface implementation. A static function sets the reference:

    static maxon::Result<void> ConfigurePreviewImageRequest(maxon::DataDictionaryObjectRef request)
    {
    request.Set(maxon::nodes::PREVIEWIMAGEREQUEST::PROVIDER, PreviewImageProviderExampleHandbook::GetClass()) iferr_return;
    return maxon::OK;
    }
    return OK
    Definition: apibase.h:2690
    #define iferr_scope
    Definition: resultbase.h:1384
    #define iferr_return
    Definition: resultbase.h:1519

    This static function is referenced in the implementation of NodeSpaceInterface::Init():

    // Defines the callback function that will configure the preview image request
    spaceData.Set(maxon::nodes::NODESPACE::CONFIGUREPREVIEWIMAGEREQUESTFUNC, maxon::nodes::NODESPACE::ConfigurePreviewImageRequestFunc(ConfigurePreviewImageRequest)) iferr_return;
    Definition: delegate.h:240

    Render Scenes

    The context-menu to select the render scene for the preview image is added to nodes that are registered in maxon::nodes::NODESPACE::MATERIALPREVIEWIDS. This is done in the Init() function of the implementation of the node space.

    maxon::BaseArray<maxon::Id> materialPreviewNodes;
    materialPreviewNodes.Append(maxon::Id("net.maxonexample.handbook.noderenderer.usernode_shade")) iferr_return;
    materialPreviewNodes.Append(maxon::Id("net.maxonexample.handbook.noderenderer.usernode")) iferr_return;
    materialPreviewNodes.Append(maxon::Id("net.maxonexample.handbook.node.constantnode")) iferr_return;
    spaceData.Set(maxon::nodes::NODESPACE::MATERIALPREVIEWIDS, std::move(materialPreviewNodes)) iferr_return;
    MAXON_ATTRIBUTE_FORCE_INLINE ResultRef< T > Append(ARG &&x)
    Definition: basearray.h:677

    The selected scene identifier is then stored under maxon::nodes::PREVIEWIMAGEREQUEST::SCENETYPE, accessible in PreviewImageProviderInterface::Initialize():

    DiagnosticOutput("scene type: @", type);
    #define DiagnosticOutput(formatString,...)
    Definition: debugdiagnostics.h:176
    SCENETYPE
    Definition: previewimageprovider.h:89
    @ MatPreviewDefault
    Default (may be a user preference).
    PyObject ** type
    Definition: pycore_pyerrors.h:34

    Final Code

    If all the steps have been followed, the code should look like the following:

    #include "maxon/module.h"
    #include "maxon/nodeslib.h"
    static maxon::nodes::NodeSystemClass g_nodeSystemClass;
    // This description processor has to be used for all nodes of the example namespace unless they register themselves at the BuiltinNodes registry (such as DynamicNode).
    MAXON_DECLARATION_REGISTER(maxon::DescriptionProcessors, "net.maxonexample.handbook.nodespace.noderendererprocessor")
    {
    return maxon::nodes::NodesLib::CreateNodeDescriptionProcessor([] (const maxon::Id& descriptionId, const maxon::DataDescription& dataDescription) -> maxon::Result<maxon::nodes::NodeTemplate>
    {
    {
    return maxon::nodes::NodesLib::BuildNodeFromDescription(descriptionId, g_nodeSystemClass);
    }, g_nodeSystemClass);
    });
    }
    static maxon::Result<void> CreateMaterialGraphDefaultSetup(const maxon::nodes::NodesGraphModelRef& graph)
    {
    // Instantiate a node that only has a description, but no process function.
    maxon::nodes::NodeTemplate userNodeSystem = maxon::nodes::NodesLib::LoadTemplate(maxon::AssetInterface::GetBuiltinRepository(), maxon::Id("net.maxonexample.handbook.noderenderer.usernode")) iferr_return;
    maxon::GraphNode userGraphNode = graph.AddChild(maxon::Id("user node instance"), userNodeSystem) iferr_return;
    maxon::nodes::NodeTemplate shaderNodeSystem = maxon::nodes::NodesLib::LoadTemplate(maxon::AssetInterface::GetBuiltinRepository(), maxon::Id("net.maxonexample.handbook.noderenderer.usernode_shade")) iferr_return;
    maxon::GraphNode shaderNode = graph.AddChild(maxon::Id("shader node instance"), shaderNodeSystem) iferr_return;
    // Connect the two instances.
    maxon::GraphNode outPort = userGraphNode.GetOutputs().FindChild(maxon::Id("net.maxonexample.handbook.node.usernode.out")) iferr_return;
    maxon::GraphNode inPort = shaderNode.GetInputs().FindChild(maxon::Id("usernode_shade.colorA")) iferr_return;
    outPort.Connect(inPort) iferr_return;
    // Replace the default value for the first instance.
    maxon::GraphNode valuePort = shaderNode.GetInputs().FindChild(maxon::Id("usernode_shade.colorB")) iferr_return;
    valuePort.SetDefaultValue(maxon::Data(maxon::ColorA(1.0, 1.0, 0.0, 1.0))) iferr_return;
    return maxon::OK;
    }
    static maxon::Result<void> ConfigurePreviewImageRequest(maxon::DataDictionaryObjectRef request)
    {
    request.Set(maxon::nodes::PREVIEWIMAGEREQUEST::PROVIDER, PreviewImageProviderExampleHandbook::GetClass()) iferr_return;
    return maxon::OK;
    }
    MAXON_METHOD maxon::Result<void> NodeRendererNodeSpaceImpl::Init(maxon::DataDictionary spaceData)
    {
    _class = NodeRendererNodeSystemClassImpl::GetClass().Create() iferr_return;
    spaceData.Set(maxon::nodes::NODESPACE::NODESYSTEMCLASS, _class) iferr_return;
    // Defines the End Node for this node systems
    maxon::BaseArray<maxon::Id> materialEndNodeIds;
    // Define the node we want to be defined as the end node.
    materialEndNodeIds.Append(maxon::Id("net.maxonexample.handbook.noderenderer.usernode_shade")) iferr_return;
    // Define the information in the DataDictionnary.
    spaceData.Set(maxon::nodes::NODESPACE::MATERIALENDNODEIDS, std::move(materialEndNodeIds)) iferr_return;
    // Defines the supported render
    // Create a BaseArray that store the supporter's engine ID.
    maxon::BaseArray<maxon::Int> supportedRenderers;
    // Here, g_nodeRendererId is the ID of a render engine.
    supportedRenderers.Append(g_nodeRendererId) iferr_return;
    supportedRenderers.Append(1023342) iferr_return;
    supportedRenderers.Append(0) iferr_return;
    // Add the array in the DataDictionnary.
    spaceData.Set(maxon::nodes::NODESPACE::RENDERERS, std::move(supportedRenderers)) iferr_return;
    // Defines the callback function that will create the default setup for the graph.
    spaceData.Set(maxon::nodes::NODESPACE::CREATEMATERIALGRAPHFUNC, maxon::nodes::NODESPACE::CreateMaterialGraphFunc(CreateMaterialGraphDefaultSetup)) iferr_return;
    // Defines the callback function that will configure the preview image request
    spaceData.Set(maxon::nodes::NODESPACE::CONFIGUREPREVIEWIMAGEREQUESTFUNC, maxon::nodes::NODESPACE::ConfigurePreviewImageRequestFunc(ConfigurePreviewImageRequest)) iferr_return;
    maxon::BaseArray<maxon::Id> materialPreviewNodes;
    materialPreviewNodes.Append(maxon::Id("net.maxonexample.handbook.noderenderer.usernode_shade")) iferr_return;
    materialPreviewNodes.Append(maxon::Id("net.maxonexample.handbook.noderenderer.usernode")) iferr_return;
    materialPreviewNodes.Append(maxon::Id("net.maxonexample.handbook.node.constantnode")) iferr_return;
    spaceData.Set(maxon::nodes::NODESPACE::MATERIALPREVIEWIDS, std::move(materialPreviewNodes)) iferr_return;
    super.Init(spaceData) iferr_return;
    return maxon::OK;
    }
    static maxon::Id g_nodeRendererDatabaseID = maxon::Id("net.maxonexample.handbook.nodes.registereddatabase");
    static maxon::GenericData g_exampleNodeSpace;
    static maxon::Result<void> LoadResources()
    {
    {
    err.CritStop();
    return err;
    };
    // Get plugin location
    const maxon::Url& binaryUrl = maxon::g_maxon.GetUrl();
    // Get plugin folder
    maxon::Url pluginDir = binaryUrl.GetDirectory();
    // Get resource folder (this folder must exist)
    const maxon::Url resourceUrl = pluginDir.Append("res"_s).Append("nodes"_s) iferr_return;
    // Register database
    // Register the node space
    // Use the same ID as in the resource files
    const maxon::Id spaceDescriptionId = maxon::Id("net.maxonexample.handbook.nodespace.node_renderer");
    // Load the description
    maxon::DataDictionary nodeRendererData = maxon::nodes::NodeSpaceHelpersInterface::LoadDescription(spaceDescriptionId) iferr_return;
    maxon::nodes::NodeSpaceRef nodeRendererSpace = NodeRendererNodeSpaceImpl::CreateInit(nodeRendererData) iferr_return;
    // Register the node space implementation
    g_exampleNodeSpace = maxon::nodes::MaterialNodeSpaces::Register(NodeRendererNodeSpaceImpl::GetDescriptor().GetId(), nodeRendererSpace) iferr_return;
    return maxon::OK;
    }
    static void FreeResources()
    {
    {
    err.CritStop();
    return;
    };
    // Unregister a database
    g_exampleNodeSpace = maxon::GenericData();
    g_nodeSystemClass = nullptr;
    }
    MAXON_INITIALIZATION(LoadResources, FreeResources);
    static MAXON_METHOD const AssetRepositoryRef & GetBuiltinRepository()
    static MAXON_METHOD Result< void > RegisterDatabaseWithUrl(const Id &databaseId, const Url &url, const CString &version=CString::NullValue())
    static MAXON_METHOD Result< void > UnregisterDatabase(const Id &databaseId)
    Definition: genericdata.h:20
    Definition: url.h:952
    static MAXON_METHOD Result< DataDictionary > LoadDescription(const Id &spaceDescriptionId)
    static MAXON_METHOD Result< NodeTemplate > CreateLazyTemplate(const Id &nodeId, Delegate< Result< NodeTemplate >()> &&creator, Delegate< Result< Bool >(const NodeSystemClass &cls)> &&support={})
    static MAXON_METHOD Result< DescriptionProcessor > CreateNodeDescriptionProcessor(Delegate< Result< NodeTemplate >(const Id &descriptionId, const DataDescription &dataDescription)> &&delegate)
    static MAXON_METHOD Result< NodeTemplate > LoadTemplate(const AssetRepositoryRef &repo, const Id &assetId)
    static MAXON_METHOD Result< NodeSystemBasedNodeTemplate > BuildNodeFromDescription(const Id &id, const NodeSystemClass &nodeClass, Bool addDependencies=true, const Delegate< Result< void >(const MutableRoot &root, const TemplateArguments &args)> &finalizer={})
    OK
    Ok.
    Definition: ge_prepass.h:0
    Col4< Float, 1 > ColorA
    Definition: vector4d.h:60
    #define MAXON_DECLARATION_REGISTER(...)
    Definition: module.h:933
    #define MAXON_INITIALIZATION(...)
    Definition: module.h:795
    The maxon namespace contains all declarations of the MAXON API.
    Definition: autoweight.h:14
    Definition: animation_attributes.h:10
    #define iferr_scope_handler
    Definition: resultbase.h:1402
    Definition: node.h:10