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