Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Register
    • Login

    Changing description of material nodes dynamically

    Cinema 4D SDK
    c++
    2
    6
    797
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • D
      Deyan
      last edited by

      Hi,

      I have two questions regarding the descriptions of nodes.

      My first question is, if it is possible and how to change some description property of a node port, based on the value of another constant port. As an example, in a NodeData::GetDDescription(..) one can easily read a parameter and change the description of another parameter (e.g. change the name of one parameter based on a checkbox).
      Is something similar possible to do in material nodes (or nodes in general) and how?

      My second question is related to the first one in regards of dynamic changes of nodes. I tried using a custom GUI implementation based on the example.nodes plugin in the SDK. In particular I used the implementation in example.nodes/source/gui/customgui_string.cpp as a reference for using a custom GUI. I found that the getDataCallback parameter delegate can be used to actually get the GraphNode for a node in UiConversionCustomGuiString::CreateC4DDescription(..). But my question is if there is a way to trigger this function to be called again upon changes on the node, to allow dynamic updates on the node based on port value in the node?

      Thanks in advance 🙂

      1 Reply Last reply Reply Quote 0
      • ManuelM
        Manuel
        last edited by

        Hi and sorry for the late reply,

        you can react to a change in a node parameter registering a changed message with RegisterValueChangedMessage
        You need to define the Node ID and the port. If you change some parameter this will call an update of the UI and CreateC4DDescription will be called.

        From there you can achieve what you want. I did not try but as you said, in the customgui_string you can defined parameter for the custom GUI.

        Let me know if it is not enough.

        #include "maxon/datadescriptiondefinitiondatabase.h"
        #include "maxon/datadescription_ui.h"
        #include "maxon/datadescription_nodes.h"
        #include "maxon/graph.h"
        #include "customnode-customnodespace_descriptions.h"
        
        static maxon::Result<void> ColorChanged(const maxon::DataDictionary& userData, maxon::DataDictionary& multiSelectionStorage)
        {
        	iferr_scope;
        
        	maxon::GraphModelRef graph = userData.Get(maxon::ARGUMENTS::NODECORE::GRAPHMODEL) iferr_return;
        	// Node that owns the port (NODECORE::PORTPATH).
        	maxon::IoNodePath nodePath = userData.Get(maxon::ARGUMENTS::NODECORE::NODEPATH) iferr_return;
        	// Internal port on which the callback was registered.
        	maxon::NodePath innerPortPath = userData.Get(maxon::ARGUMENTS::NODECORE::INNERPORTPATH) iferr_return;
        
        	// Should always just be valid if the callback is fired.
        	CheckAssert(graph);
        	CheckAssert(nodePath.first.IsPopulated());
        	CheckAssert(innerPortPath.IsPopulated());
        
        
        
        
        	maxon::GraphNode currentNode = graph.GetNode(nodePath.first);
        	if (!currentNode.IsValid())
        		return maxon::NullptrError(MAXON_SOURCE_LOCATION);
        
        	const maxon::GraphNode colorA = graph.GetNode(innerPortPath);
        	if (!colorA.IsValid())
        		return maxon::NullptrError(MAXON_SOURCE_LOCATION);
        	const maxon::GraphNode hybridPort = currentNode.GetInputs().FindChild(maxonexample::NODE::USERNODE::HYBRID) iferr_return;
        	if (!colorA.IsValid())
        		return maxon::NullptrError(MAXON_SOURCE_LOCATION);
        
        	const maxon::ColorA colorAValue = colorA.GetDefaultValue(maxon::ColorA(0)) iferr_return;
        	if (colorAValue.r > 0.5)
        	{
        		// Make the graph modifiable.
        		maxon::GraphTransaction trans = graph.BeginTransaction() iferr_return;
        
        		hybridPort.SetValue(maxon::NODE::BASE::NAME, "Code Red"_s) iferr_return;
        
        		// Apply the change to the graph.
        		return trans.Commit();
        	}
        	return maxon::OK;
        }
        
        
        MAXON_INITIALIZATION(
        	[]() -> maxon::Result<void>
        	{
        		iferr_scope;
        		maxon::DataDescriptionDefinitionDatabaseInterface::RegisterValueChangedMessage(
        			maxonexample::NODE::USERNODE::GetId(), maxonexample::NODE::USERNODE::COLORA,
        			maxon::DescriptionMessageFunction(maxon::DESCRIPTION::UI::BASE::COMMANDCONTEXT.ENUM_NIMBUSCORE, nullptr, nullptr, ColorChanged)) iferr_return;
        		return maxon::OK;
        	}, nullptr);
        
        

        Cheers,
        Manuel

        MAXON SDK Specialist

        MAXON Registered Developer

        1 Reply Last reply Reply Quote 0
        • D
          Deyan
          last edited by

          Hi @m_magalhaes, this is exactly what I was looking for. It works like a charm for my first usecase.

          But for the second part I encountered just a slight inconvenience. In my second usecase I actually don't want to change parameter name, I just want CreateC4DDescription(..) to be called again. From what I tested, if the name is set with the same value, the description creation is not triggered. I also tried changing another (seemingly irrelevant) attribute of the node, but that did not trigger a description change either (in particular I tried changing maxon::NODE::BASE::COMMENT).
          Finally, I tried adding a new hidden port, that is not actually used, just to change its name when the description change function should be called - and this seems to work as expected. I was just wondering if there is a better solution that may achieve the same result without a dummy port?

          Cheers,
          Deyan

          1 Reply Last reply Reply Quote 0
          • ManuelM
            Manuel
            last edited by

            I forgot an important point; the message will only be called at edit time (if the user changes the value). If the field is animated, the message will not get triggered.

            About just triggering the function i need to check if we can do something with timestamp.

            MAXON SDK Specialist

            MAXON Registered Developer

            1 Reply Last reply Reply Quote 0
            • D
              Deyan
              last edited by

              Another small question that came to mind - this registration function RegisterValueChangedMessage(..) seems to have been added in R26 SDK - is there an alternative for earlier SDK versions?

              1 Reply Last reply Reply Quote 0
              • ManuelM
                Manuel
                last edited by

                @deyan said in Changing description of material nodes dynamically:

                is there an alternative for earlier SDK versions?

                In our example, you have the files nodessystem_observer.h/cpp this shows how to create a ticket system. This system is based on observable that you can use, those observables are accessible in the GraphModelInterface or the NodeSystemManagerInterface.

                • ObservableTransactionStarted
                • ObservableTransactionCommitted
                • ObservableTransactionRolledBack

                You have another example in our manual

                The problem with observable is that you need to be sure that your function is registered or unregistered the right way/time. You need a proper system to handle those "tickets".
                For now, you only have this "basic system".

                Cheers,
                Manuel

                MAXON SDK Specialist

                MAXON Registered Developer

                1 Reply Last reply Reply Quote 0
                • First post
                  Last post