How do I create an animation of a Material Modifier (in C++)

How do I create an animation of a Material Modifier (in C++)

johnny.johanssonSZ55P
Participant Participant
1,276 Views
9 Replies
Message 1 of 10

How do I create an animation of a Material Modifier (in C++)

johnny.johanssonSZ55P
Participant
Participant

I am new to the SDK and animations seem like a complex subject, so I am not even sure where to start looking.

I have created a Material Modifier:

Modifier *material_modifier = (Modifier*)i7->CreateInstance(OSM_CLASS_ID, Class_ID(MATERIALOSM_CLASS_ID, 0));

And I have successfully associated it with a number of nodes in the scene:

GetCOREInterface12()->AddModifier(*node, *material_modifier);

So far everything works, but I also need to animate the modifier so that at frame 0, the ID is 0 and at frame 1, the ID is 1 and so on. Probably very easy if you know enough, but I am pretty lost. There are no other animations in this scene if that makes a difference.

I would really appreciate it if anyoune could point me in the right direction!

 

0 Likes
1,277 Views
9 Replies
Replies (9)
Message 2 of 10

istan
Advisor
Advisor

Where does your "ID" come from?

If you use standard paramblk values, the animation will be handled from Max without any extra code from your plugin (with a suitable controller).

0 Likes
Message 3 of 10

johnny.johanssonSZ55P
Participant
Participant

My "ID", do you mean MATERIALOSM_CLASS_ID? This is what I, by trial and error, figured out I need to use in order to create a Material modifier. It is quite possible that there is a better way to do that, but on the other hand, this part seems to be working.

 

To clarify, I am not developing any new functionality here. I am trying to automate certain steps that are already available and could be done manually in 3DS. The steps are:

 

1 - Create a Material modifier, which I have done and it is working.
2 - Associate it with certain nodes, which I have done and can verify in 3DS that it works.
3 - Animate the "Material ID" of the Material modifier, which is trivial to do, using "Auto Key" in 3DS, but I can not figure out how to do from code...

 

I hope this clarifies what my problem is. I would really appreciate any help I can get here!

MaterialModifierID.png

 

 

0 Likes
Message 4 of 10

istan
Advisor
Advisor

ah.. ok..

Why don't you consider using MXS for this? You could call MXS from C++.

Otherwise, I would search the SetValue() id in the samples for this specific parameter. But since this ParamBlock has just one parameter, I would test with ParamBlk Id=0.

 

0 Likes
Message 5 of 10

johnny.johanssonSZ55P
Participant
Participant

MXS = Maxscript, right? Which might be a good idea, although, this problem is just a small part of huge Maxscript based process that I am rewriting as a plugin in C++, because once you get to a certain code size, Maxscript becomes totally unmaintainable. I could do limited parts as Maxscript though and call them from the plugin.

 

However, I seem to have stumbled upon a solution. One of the first things I tried was this:

 

IParamArray *P = material_modifier->GetParamBlock();
IParamBlock *PB = P->GetParamBlock();

for (int i = 0; i < num_materials; ++i) {
	// Hardcoded for 30 fps. 
	constexpr int fps = 30;
	constexpr int ticks_per_frame = TIME_TICKSPERSEC / fps;

	PB->SetValue(0, i * ticks_per_frame, i + 1);
}

 

But it would not work, only the last of the values was set and there was no animation. However, I just found out that if i call AnimateOn() before the loop and AnimateOff() after, it works!

 

This seems more like hacking than programming to me, but as long as this is working, I am going to stick with it!

 

Thank you for your efforts though, I appreciate it!

0 Likes
Message 6 of 10

istan
Advisor
Advisor

yes, I abbreviate MaxScript by MXS since decades 😉

Instead of using AnimateOn() you could also directly add keys to the controller of the ParamBlk value..

0 Likes
Message 7 of 10

johnny.johanssonSZ55P
Participant
Participant

That sounds like a much neater solution, but I tried a bunch of stuff like that and the problem is that PB->GetController(0) returns NULL. I assume this is because the modifier isn't animated (PB->isAnimated() returns false).

 

So it is a Catch-22: I can't add keyframes to animate the modifier, because the modifier isn't animated...

 

0 Likes
Message 8 of 10

istan
Advisor
Advisor

Have you also tried assigning a new controller with pb->SetController() first?

0 Likes
Message 9 of 10

johnny.johanssonSZ55P
Participant
Participant

No, I have not tried exactly that. I did try to AssignController(NewDefaultFloatController(), 0) directly to the Modifier, but that would fail (return FALSE) and I abandoned that line of investigation.

 

But setting a new (default float) controller on the IParamBlock per your suggestion does allow me to create keyframes where I need them, but I am failing to set different values. All keyframes get the same value.

 

Looking at the header file comments for Control::SetValue, I note that:

 

Note: Developers who want to create keys for a keyframe controller by calling SetValue() directly can do so, but the animate button should be turned on using the following code:
SuspendAnimate()
AnimateOn()
Call SetValue() -- make sure commit=1
ResumeAnimate()

So I guess there really is no way to do this without messing with global state!

 

 

 

 

0 Likes
Message 10 of 10

istan
Advisor
Advisor

But setting a new (default float) controller on the IParamBlock per your suggestion does allow me to create keyframes where I need them, but I am failing to set different values. All keyframes get the same value.

Did you ever see your keyframes in the e.g. curve editor?

btw, take a look at \maxsdk\howto\import_export\asciimp\import.cpp

0 Likes