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
    • Login

    Create Gradient Attribute for Nodes Programmatically

    Cinema 4D SDK
    c++ r25
    2
    12
    1.7k
    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.
    • O
      Ogers
      last edited by Manuel

      Hello,

      I have created a gradient attribute but instead of getting a proper Gradient UI that C4D uses, I am getting this one.

      cd9993f4-e193-4c83-abaf-b1658689ef91-image.png

      I noticed that it can be achieved by settings Replace Complex UI parameter to 200001011 but I could not find a way to set this parameter pragmatically except that from the resource editor. At first, I thought that this parameter would be on datadescription_ui.h, but it was missing from there or maybe it is located in another file.
      Is there any way to set that parameter pragmatically, or any other way to show my Gradient parameters' UI as it normally should be?

      Thank you.

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

        hi,

        the ID you are looking for is maxon::DESCRIPTION::UI::NET::MAXON::UI::VARIADICPORT::COMPLEXCUSTOMUI but i was not able to make it work, even if i defined the port as variadic and add the commands. So I asked the dev what i am missing.

        Cheers,
        Manuel

        MAXON SDK Specialist

        MAXON Registered Developer

        1 Reply Last reply Reply Quote 0
        • O
          Ogers
          last edited by Ogers

          Hello,
          Thanks for the reply. After setting the right ID as you said, I was able to get the UI look I was looking for, but same as you I can't make it work properly. Here is the part of the code I have used for this.

          maxon::BaseArray<maxon::Id> var_commands;
          
          var_commands.Append(maxon::Id("addvariadicport"));
          var_commands.Append(maxon::Id("removevariadicport"));
          
          node.Set(maxon::DATADESCRIPTION_CATEGORY_DATA, maxon::DESCRIPTION::DATA::BASE::DATATYPE, maxon::Id("net.maxon.render.portbundle.gradient")) iferr_return;
          
          node.Set(maxon::DATADESCRIPTION_CATEGORY_UI, maxon::DESCRIPTION::UI::BASE::GUITYPEID, maxon::Id("net.maxon.ui.variadicport")) iferr_return;
          
          node.Set(maxon::DATADESCRIPTION_CATEGORY_DATA, maxon::DESCRIPTION::DATA::BASE::ISVARIADIC, TRUE) iferr_return;
          
          node.Set(maxon::DATADESCRIPTION_CATEGORY_DATA, maxon::DESCRIPTION::DATA::BASE::VARIADICCOUNT, 2) iferr_return;
          
          node.Set(maxon::DATADESCRIPTION_CATEGORY_DATA, maxon::DESCRIPTION::DATA::BASE::VARIADICCOMMANDS, var_commands) iferr_return;
          
          node.Set(maxon::DATADESCRIPTION_CATEGORY_UI, maxon::DESCRIPTION::UI::NET::MAXON::UI::VARIADICPORT::COMPLEXCUSTOMUI, 200001011);
          
          1 Reply Last reply Reply Quote 0
          • O
            Ogers
            last edited by

            Hello?
            Is there any news about this one yet?
            868391ba-efe4-4226-b077-5ab64582f925-image.png

            So far with the code above, I can only get to this part, but as you can see the gradient's colours are not showing on the UI.

            Also, how can I get the values set for each knot (colour, interpolation, position etc.)
            Do I have to build my own gradient data type to make it work or does the built-in gradient offers all these?

            Thank you.

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

              hi,

              there are some progresse yes, but it is still not working correctly.

              you cannot define the value of the knot while you are defining the node itself. That is a limitation of the variadic ports.

              you must define the values after using the DescriptionFinalizers with the exact same ID you used to register the node itself. You will have access to the knots and will be able to define the values. The problem is that the gradient remains black i still don't have the answer for that from our dev.

              MAXON_DECLARATION_REGISTER(nodes::DescriptionFinalizers, "net.maxon.node.procedural.firstexample")
              {
              	return nodes::DescriptionFinalizers::EntryType([](const nodes::MutableRoot& root)-> Result<void>
              		{
              			iferr_scope;
              			nodes::MutablePort knot0 = root.GetInputs().FindPort(PATTERN::NODE::GENERATOR::GRADIENT::GRADIENT).FindPort(Id("_0")) iferr_return;
              			if (knot0)
              			{
              				knot0.FindPort(RENDER::PORTBUNDLE::GRADIENT::COLOR).SetDefaultValue(ColorA(0, 0, 1, 1)) iferr_return;
              				knot0.FindPort(RENDER::PORTBUNDLE::GRADIENT::POSITION).SetDefaultValue(Float(0.0)) iferr_return;
              			}
              			return OK;
              		});
              }
              

              I've changed the title of the thread from pragmatically to programmatically so people will find this thread when using our search engine.

              MAXON SDK Specialist

              MAXON Registered Developer

              1 Reply Last reply Reply Quote 0
              • O
                Ogers
                last edited by

                Hello,
                Thanks for the update.

                Regarding the ports you have used, are they already defined as ports, or they should be created too?
                At the moment these ports PATTERN::NODE::GENERATOR::GRADIENT::GRADIENT, RENDER::PORTBUNDLE::GRADIENT::COLOR and RENDER::PORTBUNDLE::GRADIENT::POSITION cannot be accessed. I tried searching all files but could not find them.

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

                  Hi,
                  Those ports are part of the Gradient DataType.

                  just like you did

                  node.Set(maxon::DATADESCRIPTION_CATEGORY_DATA, maxon::DESCRIPTION::DATA::BASE::DATATYPE, maxon::Id("net.maxon.render.portbundle.gradient")) iferr_return;
                  

                  I'm doing

                  b.Set(DATADESCRIPTION_CATEGORY_DATA, DESCRIPTION::DATA::BASE::DATATYPE, maxon::RENDER::PORTBUNDLE::GRADIENT::GetId()) iferr_return;
                  

                  The problem is to find the right information and the right symbol to use. The resource editor helps a lot. I usually presse the first top left dropdown arrow and start typing "gradient" to find a bit faster the Data Type I'm looking for. This will search among all databases.
                  02ad5984-b022-4d7a-ac39-3eb6bc9aaca9-image.png

                  From there you can find the file where those symbols are exported
                  4488b14f-6bc4-456b-99d1-398bc00b5c00-image.png

                  The ID are in the render.framework -> patternnodes.h and you have the equivalent of the resource editor.

                  6286404a-0710-418d-ad3e-4e5dc5610dfd-image.png

                  You can also find the file by search the ID itself: net.maxon.render.portbundle.gradient

                  As the gradient port, is a Variadic Port composed by a Port Bundle the first Knot will have the id "_0"
                  that is why I'm using

                  root.GetInputs().FindPort(PATTERN::NODE::GENERATOR::GRADIENT::GRADIENT).FindPort(Id("_0"))
                  

                  And i know that this Port Bundle is composed of several port that i can find with the right ID.

                  the code I'm using to create the gradient port so far.

                                  b.BeginPort(PORT_DIR::INPUT, Id("gradient")) iferr_return;
                  		b.Set(DATADESCRIPTION_CATEGORY_DATA, DESCRIPTION::DATA::BASE::DATATYPE, maxon::RENDER::PORTBUNDLE::GRADIENT::GetId()) iferr_return;
                  		b.Set(DATADESCRIPTION_CATEGORY_DATA, DESCRIPTION::DATA::BASE::ISVARIADIC, true) iferr_return;
                  		b.Set(DATADESCRIPTION_CATEGORY_DATA, maxon::DESCRIPTION::DATA::BASE::VARIADICCOUNT, 2) iferr_return;
                  
                  		Array<Id> commands;
                  		commands.Append(Id("addvariadicport")) iferr_return;
                  		commands.Append(Id("removevariadicport")) iferr_return;
                  		b.Set(DATADESCRIPTION_CATEGORY_DATA, DESCRIPTION::DATA::BASE::COMMANDS, std::move(commands)) iferr_return;
                  		
                  		b.Set(DATADESCRIPTION_CATEGORY_UI, DESCRIPTION::UI::BASE::GROUPID, NODE::BASE::GROUP_INPUTS) iferr_return;
                  		b.Set(DATADESCRIPTION_CATEGORY_UI, DESCRIPTION::UI::BASE::GUITYPEID, Id("net.maxon.ui.variadicport")) iferr_return;
                  		b.Set(DATADESCRIPTION_CATEGORY_UI, maxon::DESCRIPTION::UI::NET::MAXON::UI::VARIADICPORT::COMPLEXCUSTOMUI, 200001011) iferr_return;
                  		b.Set(LANGUAGE_ENGLISH_ID, DESCRIPTION::STRING::BASE::TRANSLATEDSTRING, "gradient"_s) iferr_return;
                  		b.EndPort() iferr_return;
                  
                  

                  MAXON SDK Specialist

                  MAXON Registered Developer

                  1 Reply Last reply Reply Quote 0
                  • O
                    Ogers
                    last edited by Ogers

                    Hello.
                    It's weird as I don't have a render.framework on my machine, although the include file points there on my side as well.. Could this be part of S26 only?
                    I have also referred to the resource editor to build my own gradient where I found everything I needed except for the file which is missing.

                    df669c9d-fb0b-4373-9ed0-4ede7ed822a3-image.png

                    Also as you can notice from my previous messages where I showed how I was building the gradient, you can see that the only difference is that I set the datatype by typing the ID manually ("net.maxon.render.portbundle.gradient"), and all that because I could not find the right file.

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

                      ha,

                      proof that I am an idiot, if we need any, the render.framework is private xD

                      mib.gif

                      Cheers,
                      Manuel

                      MAXON SDK Specialist

                      MAXON Registered Developer

                      1 Reply Last reply Reply Quote 0
                      • O
                        Ogers
                        last edited by

                        Haha, I forget even more important stuff sometimes 🙂
                        Btw is there any workaround for this? Or will it be public in the future?

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

                          you must use the ID themself and not the symbols

                          MAXON SDK Specialist

                          MAXON Registered Developer

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

                            hi,

                            Sorry for the late reply, but this needed investigation and test from my side and communication between me and the dev.

                            You can create the NodeTemplate that way. I am using the class GradientWorkaround to create the template.
                            NodesLib::BuildNodeFromDescription must be called with false set to not create the dependency wires.

                            		
                            		NodeTemplate t = NodesLib::CreateLazyTemplate(firstNodeId,
                            			[firstNodeId]() -> Result<NodeTemplate>
                            			{
                            				iferr_scope;
                            				
                            				maxon::nodes::NodeTemplate templ = maxon::nodes::NodesLib::BuildNodeFromDescription(firstNodeId, CoreNodesNodeSystemClass(), false) iferr_return;
                            				templ = GradientWorkaround::CreateInit(templ) iferr_return;
                            				return templ;
                            
                            			}, CoreNodesNodeSystemClass()) iferr_return;
                            

                            The class itself look like this. We can create a gradient node inside the usernode itself and connect the ports. This is done inside the function InstantiateImpl.

                            class GradientWorkaround : public maxon::Component<GradientWorkaround, maxon::nodes::NodeTemplateInterface>
                            {
                            	MAXON_COMPONENT(NORMAL, maxon::nodes::NodeTemplateBaseClass);
                            
                            public:
                            	maxon::ResultOk<void> Init(const maxon::nodes::NodeTemplate& templ)
                             	{
                            		_wrapped = templ;
                            		return maxon::OK;
                            	}
                            
                            	MAXON_METHOD maxon::Result<Bool> SupportsImpl(const maxon::nodes::NodeSystemClass& cls) const
                            	{
                            		return cls.IsSubclassOf(CoreNodesNodeSystemClass());
                            	}
                            
                            	MAXON_METHOD maxon::Result<maxon::nodes::NodeSystem> InstantiateImpl(const maxon::nodes::InstantiationTrace& parent, const maxon::nodes::TemplateArguments& args) const
                            	{
                            		iferr_scope;
                            
                            		maxon::nodes::NodeSystem sys = _wrapped.Instantiate(parent, args) iferr_return;
                            
                            		maxon::nodes::MutableRoot root = sys.BeginInstantiationModification(self) iferr_return;
                            		// Asset ID : net.maxon.pattern.node.generator.gradient
                            
                            		const AssetRepositoryRef& repository = AssetInterface::GetBuiltinRepository();
                            		nodes::NodeTemplate gradient = nodes::NodesLib::LoadTemplate(repository, Id("net.maxon.pattern.node.generator.gradient")) iferr_return;
                            		MutableNode gradientNode = root.AddChild(Id("Gradient"), gradient) iferr_return;
                            		const maxon::nodes::MutablePort output = root.GetOutputs().FindPort(maxon::Id("testoutput")) iferr_return;
                            		const maxon::nodes::MutablePort gradientPort = root.GetInputs().FindPort(maxon::Id("gradient")) iferr_return;
                            
                            		const maxon::nodes::MutablePort gradientResult = gradientNode.GetOutputs().FindPort(maxon::Id("result")) iferr_return;
                            		const maxon::nodes::MutablePort gradientGradient = gradientNode.GetInputs().FindPort(maxon::Id("gradient")) iferr_return;
                            
                            		gradientResult.Connect(output) iferr_return;
                            		gradientPort.Connect(gradientGradient) iferr_return;
                            	
                            
                            
                            
                            		sys = root.EndModification() iferr_return;
                            		return sys;
                            	}
                            
                            private:
                            	maxon::nodes::NodeTemplate _wrapped;
                            };
                            MAXON_COMPONENT_CLASS_REGISTER(GradientWorkaround, "net.maxonexample.nodes.class.gradientworkaround");
                            

                            It is just like having a group of nodes and propagated ports.

                            Cheers,
                            Manuel

                            MAXON SDK Specialist

                            MAXON Registered Developer

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