Open Search
    Providing Viewport Representations of Node Materials

    Table of Contents

    Describes how to define the viewport representation of a node material.

    Code

    The viewport material preview defines how the node material is displayed in the viewport. The preview is defined by implementing a MaterialExchangeInterface and maxon::nodes::MaterialExchangeInterface::LoadMaterialDefaults() allows to load the material description of a given type. The interface contains the static function templates Extract(), Insert() and InsertData(). These functions are used to edit the DataDictionary containing the material description in GetMaterialParameters().

    MAXON_METHOD maxon::Result<maxon::DataDictionary> NodeRendererViewPortMaterialHandbookImpl::GetMaterialParameters()
    {
    {
    // In case of error, return the default Material
    };
    // Check node and node type
    const maxon::NodePath rootNodePath = (_soloNodePath.IsPopulated() == true) ? _soloNodePath : _endNodePath;
    const maxon::GraphNode rootNode = _graph.GetNode(rootNodePath);
    // Note: only return a changed timestamp when the parameter really has changed.
    const maxon::UInt timestamp = rootNode.GetGraph().GetModificationStamp();
    const maxon::Color baseColor{ 1.0, 1.0, 0.0 };
    maxon::nodes::MaterialExchangeInterface::Insert(parameters, maxon::NODESPACE::EXCHANGE::BUNDLE::VIEWPORTMATERIAL::TYPE, maxon::NODESPACE::EXCHANGE::BUNDLE::VIEWPORTMATERIAL::TYPE_ENUM_CONSTANT, true, 0) iferr_return;
    maxon::nodes::MaterialExchangeInterface::Insert(parameters, maxon::NODESPACE::EXCHANGE::BUNDLE::VIEWPORTMATERIAL::EMISSION_COLOR, baseColor, true, timestamp) iferr_return;
    return parameters;
    }
    BUNDLE
    The data type is a bundle type.
    Definition: apibase.h:83
    Definition: graph.h:1950
    const GraphModelRef & GetGraph() const
    Definition: graph.h:1992
    Definition: resultbase.h:766
    static MAXON_METHOD Result< DataDictionary > LoadMaterialDefaults(const Id &materialType)
    static Result< void > Insert(DataDictionary &parameters, KEY &&id, T &&value, Bool isConstant, UInt dynamicTimestamp)
    Definition: nodematerialexchange.h:203
    #define parameters
    Definition: graminit.h:11
    UInt64 UInt
    unsigned 32/64 bit int, size depends on the platform
    Definition: apibase.h:189
    #define MAXON_METHOD
    Definition: interfacebase.h:1001
    static constexpr LiteralId NODESPACE
    Neutron node space identifier.
    Definition: neutron_ids.h:108
    The maxon namespace contains all declarations of the MAXON API.
    Definition: autoweight.h:14
    #define iferr_scope_handler
    Definition: resultbase.h:1402
    #define iferr_return
    Definition: resultbase.h:1519

    The class has to be registered with a macro.

    MAXON_COMPONENT_CLASS_REGISTER(NodeRendererViewPortMaterialHandbookImpl, g_nodeRendererViewportMaterial);
    #define MAXON_COMPONENT_CLASS_REGISTER(C,...)
    Definition: objectbase.h:2409

    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;
    maxon::BaseArray<maxon::Id> materialExchangeBundleIds;
    materialExchangeBundleIds.Append(maxon::NODESPACE::EXCHANGE::BUNDLE::VIEWPORTMATERIAL::GetId()) iferr_return;
    spaceData.Set(maxon::nodes::NODESPACE::MATERIALEXCHANGEBUNDLEIDS, std::move(materialExchangeBundleIds)) iferr_return;
    spaceData.Set(maxon::nodes::NODESPACE::MATERIALEXCHANGECLASS, NodeRendererViewPortMaterialHandbookImpl::GetClass()) 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()
    MAXON_ATTRIBUTE_FORCE_INLINE ResultRef< T > Append(ARG &&x)
    Definition: basearray.h:677
    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: delegate.h:240
    Definition: genericdata.h:20
    Definition: apibaseid.h:253
    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
    return OK
    Definition: apibase.h:2690
    Col4< Float, 1 > ColorA
    Definition: vector4d.h:60
    #define MAXON_DECLARATION_REGISTER(...)
    Definition: module.h:933
    #define MAXON_INITIALIZATION(...)
    Definition: module.h:795
    Definition: animation_attributes.h:10
    #define iferr_scope
    Definition: resultbase.h:1384
    Definition: node.h:10