Create Gradient Attribute for Nodes Programmatically

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

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.

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.

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.

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;

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.

ha,

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

mib.gif

Cheers,
Manuel

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

you must use the ID themself and not the symbols

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