SDK-C# Set transform controller value


#1

I’m trying to set value for a node’s transform controller, but not working:

using Autodesk.Max;
using System.Windows;

namespace TestLibrary
{
    public partial class TestWindow : Window
    {
        private readonly static IGlobal globalInterface = GlobalInterface.Instance;
        private readonly static IInterface coreInterface = globalInterface.COREInterface;

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            int time = coreInterface.Time;
            IINode selNode = coreInterface.GetSelNode(0);
            if (selNode == null) MessageBox.Show("Selection empty.");
            else
            {
                IMatrix3 matrix = globalInterface.Matrix3.Create(true);
                selNode.TMController.SetValue(time,matrix,true,GetSetMethod.Absolute);
                globalInterface.COREInterface.RedrawViews(time, RedrawFlags.Normal, null);
            }
        }

        public TestWindow()
        {
            InitializeComponent();
        }
    }
}

What is wrong in my code?


#2

have you tried…

selNode.SetNodeTM(time, matrix);

?

otherwise you need to know what controller you are going to be dealing with usually a PRS so you have to deal with the sub controllers e.g.

Control *c;
c = node->GetTMController()->GetPositionController();

I think the setvalue above would only work if you were using a dedicated tm controller


#3

I want to save and load a pose for the entire rig, it may be biped or cat or max bones. SetNodeTM works globally, I need the local one. I’m just wondering why SetValue for the transform controller doesn’t work.


#4

try the c# version of this…

SetXFormPacket pckt(destTM);
tmControl->SetValue(ip->GetTime(), &pckt);

#5

I can’t convert this to the C# code, Would you explain why we should use this?


#6
virtual void Control::SetValue  (  TimeValue  t,  
  void *  val,  
  int  commit = 1,  
  GetSetMethod  method = CTRL_ABSOLUTE 
 )  [pure virtual] 

This method sets the value of the controller at the specified time.

val  Points to an instance of a data type that corresponds with the controller type. These are the same as GetValue() above with the following exceptions:

For rotation controllers, if the GetSetMethod is CTRL_RELATIVE, *val points to an AngAxis, while if it is CTRL_ABSOLUTE it points to a Quat.

For Matrix3 controllers *val points to an instance of class SetXFormPacket. See Class SetXFormPacket.

#7

It should be pretty straightforward in theory, but in practice it throws system exception and crashes max :slight_smile:
Don’t know if it will work when used from compiled c# dll

code
tea = Teapot isSelected:true

g = (dotNetClass "Autodesk.Max.GlobalInterface").Instance
n = g.coreinterface14.getselnode 0

tm_parent = g.Matrix3.create()
tm_parent.IdentityMatrix()

tm = g.Matrix3.create()
tm.IdentityMatrix()
tm.SetTranslate (g.point3.create 0 0 50)

tm_xf = g.SetXFormPacket.Create tm tm_parent

g.suspendanimate()
n.TMController.SetValue currenttime.ticks tm_xf true (dotNetClass "Autodesk.Max.GetSetMethod").absolute
g.resumeanimate()

#8

It will crash in C# also:

                object setXFormPacket = globalInterface.SetXFormPacket.Create(matrix,globalInterface.Matrix3.Create());
                node.TMController.SetValue(coreInterface.Time, setXFormPacket, true, GetSetMethod.Absolute);

globalInterface.SetXFormPacket.Create has more overloads, maybe we should use it another way.


#9

@Swordslayer may you help us?


#10

“&” in &pckt means we should send the pointer not variable, right? how we can do it in C#?


#11

I tried something like this:

    ISetXFormPacket setXFormPacket2 = globalInterface.SetXFormPacket.Create();
    setXFormPacket2.Aa = globalInterface.AngAxis.Create();
    setXFormPacket2.Command = SetXFormCommand.Set;
    setXFormPacket2.LocalOrigin = true;
    setXFormPacket2.P = globalInterface.Point3.Create();
    setXFormPacket2.Q = globalInterface.Quat.Create();
    setXFormPacket2.TmAxis = globalInterface.Matrix3.Create();
    setXFormPacket2.TmParent = globalInterface.Matrix3.Create();

    IntPtr setXFormPacket = Wrappers.CustomMarshalerSetXFormPacket.GetInstance(string.Empty).MarshalManagedToNative(setXFormPacket2);
    node.TMController.SetValue(time, setXFormPacket, true, GetSetMethod.Absolute);

But again crashing …


#12

“&” in &pckt means we should send the pointer not variable, right?

yes in you are passing the memory address of the object… you could also do it like this

SetXFormPacket*  pckt = new SetXFormPacket(destTM);
tmControl->SetValue(ip->GetTime(), pckt);
delete pckt;

#13

So, We can’t do it in C#?


#14

what about…

object setXFormPacket = globalInterface.SetXFormPacket.Create(matrix,globalInterface.Matrix3.Create());
object* ptr = &setXFormPacket ;
node.TMController.SetValue(coreInterface.Time, ptr, true, GetSetMethod.Absolute);

#15

I got several errors for this:
Compiler Error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
Compiler Error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('object')


#16

declare it as unsafe


#17

“object” type can not be declared as pointer.


#18

could try something like…

  unsafe
    {
        object setXFormPacket = globalInterface.SetXFormPacket.Create(matrix,globalInterface.Matrix3.Create());
        void* ptr = &setXFormPacket ;
        node.TMController.SetValue(coreInterface.Time, ptr, true, GetSetMethod.Absolute);
    }

#19

Not working…

|Error|CS0208|Cannot take the address of, get the size of, or declare a pointer to a managed type 
|Error|CS1503|Argument 2: cannot convert from 'void*' to 'object

which dotnet version do you use? mine is 4.7.2 and “Allow unsafe code” option is enabled.


#20

I’m not using dotnet , just making guesses as I know nothing about c# and max. The only I can think of trying is to create your own c# callable c++ function wrapper to handle it.