Set tangents type (C#)


#1

How we can access keyframes of a controller to change outtangenttype and intangenttype?


#2

in c++ we would do something like this…

Control *ctrl= node->GetTMController()->GetPositionController();
IKeyControl* keys = GetKeyControlInterface(ctrl);
int numkeys = keys->GetNumKeys();

// if bezier controller

IBezPoint3Key kf;
keys->GetKey(i,&kf);

// tweak  

kf.outtan = Point3(1,0,0);

keys->SetKey(i,&kf);

you’ll have to translate it into c#


#3

Thank You! how we can change the tangents type to #Step?


#4
// istdplug.h
#define BEZKEY_SMOOTH	0
#define BEZKEY_LINEAR	1
#define BEZKEY_STEP	2
#define BEZKEY_FAST	3
#define BEZKEY_SLOW	4
#define BEZKEY_USER	5
#define BEZKEY_FLAT	6

// wm3_channel.cpp
void morphChannel::SetUpNewController()
{
	int in, out;
	GetBezierDefaultTangentType(in, out);
	SetBezierDefaultTangentType(BEZKEY_STEP, BEZKEY_STEP);
	Control *c = (Control*)CreateInstance(CTRL_FLOAT_CLASS_ID,GetDefaultController(CTRL_FLOAT_CLASS_ID)->ClassID());
	cblock->SetValue(0,0,0.0f);
	cblock->SetController(0,c);
	SetBezierDefaultTangentType(in, out);
}

this is probably what you need.
found it in sdk files in a second using grepWin


#5

No , I don’t want to change the global default tangent type. I just want to change all tangents of a controller.


#6

they are stored as flags in the IKey::flags data member…

#define  BEZKEY_SMOOTH   0 
#define  BEZKEY_LINEAR   1 
#define  BEZKEY_STEP   2 
#define  BEZKEY_FAST   3 
#define  BEZKEY_SLOW   4 
#define  BEZKEY_USER   5 
#define  BEZKEY_FLAT   6 
#define  NUM_TANGENTTYPES   7 

#define  BEZKEY_NUMTYPEBITS   3 
#define  BEZKEY_INTYPESHIFT   7 
#define  BEZKEY_OUTTYPESHIFT   (BEZKEY_INTYPESHIFT+BEZKEY_NUMTYPEBITS) 
#define  BEZKEY_TYPEMASK   7 

#define  GetInTanType(f)   int(((f)>>BEZKEY_INTYPESHIFT)&BEZKEY_TYPEMASK) 
#define  GetOutTanType(f)   int(((f)>>BEZKEY_OUTTYPESHIFT)&BEZKEY_TYPEMASK) 
#define  SetInTanType(f, t)   {(f) = ((f)&(~(BEZKEY_TYPEMASK<<BEZKEY_INTYPESHIFT)))|(t<<BEZKEY_INTYPESHIFT);} 
#define  SetOutTanType(f, t)   {(f) = ((f)&(~(BEZKEY_TYPEMASK<<BEZKEY_OUTTYPESHIFT)))|(t<<BEZKEY_OUTTYPESHIFT);}

where f is the flags data member and t is the type

so in the previous example i posted it would be…

IBezPoint3Key kf;
keys->GetKey(i,&kf);
SetInTanType(kf.flags, BEZKEY_STEP );
SetOutTanType(kf.flags, BEZKEY_STEP );

#7

Thanks again, But it seems so complicated to translate to c# for me :slight_smile:


#8

there’s actually nothing much complicated
try to use it as an example

c# sdk

public static bool SetControllerTangentType( int anim_handle )
        {
            // todo: DISPOSE

            IAnimatable anim = global.Animatable.GetAnimByHandle( new UIntPtr( (uint)anim_handle ) );
            IControl ctrl = (IControl)anim;
            IIKeyControl keys = (IIKeyControl)(ctrl.GetInterface( InterfaceID.Keycontrol ));

            if ( keys == null ) return false;
           
            IIBezFloatKey kf = global.IBezFloatKey.Create();
            keys.GetKey( 0, kf );                 

            uint BEZKEY_STEP = 2;
            // ...
            // ...
            

            uint BEZKEY_NUMTYPEBITS = 3;
            int  BEZKEY_INTYPESHIFT = 7;
            int  BEZKEY_OUTTYPESHIFT = (int)(BEZKEY_INTYPESHIFT + BEZKEY_NUMTYPEBITS);
            uint BEZKEY_TYPEMASK = 7;

            // #define SetInTanType(f, t)   {(f) = ((f)&(~(BEZKEY_TYPEMASK<<BEZKEY_INTYPESHIFT)))|(t<<BEZKEY_INTYPESHIFT);}
            kf.Flags = (kf.Flags & (~(BEZKEY_TYPEMASK << BEZKEY_INTYPESHIFT))) | (BEZKEY_STEP << BEZKEY_INTYPESHIFT);

            // #define SetOutTanType(f, t)   {(f) = ((f)&(~(BEZKEY_TYPEMASK<<BEZKEY_OUTTYPESHIFT)))|(t<<BEZKEY_OUTTYPESHIFT);}
            kf.Flags = (kf.Flags & (~(BEZKEY_TYPEMASK << BEZKEY_OUTTYPESHIFT))) | (BEZKEY_STEP << BEZKEY_OUTTYPESHIFT);

            keys.SetKey( 0, kf );

            return true;
            
        }

mxs test script

b = bezier_float()
animate on
(
	at time 0 b.value = 10
	at time 20 b.value = 20
)

handle = getHandleByAnim b
SetControllerTangentType handle

c = Cylinder()
c.height.controller = b

ant don’t forget to dispose anything that can be disposed otherwise it will surely leak


#9

Very Nice! Thank You!


#10

I little organized the code:

using Autodesk.Max;
using System;

namespace Library
{
    public static class ControllerHelper
    {
        static IGlobal globalInterface = GlobalInterface.Instance;

        public static class TangentType
        {
            public static uint Smooth = 0, Linear = 1, Step = 2, Fast = 3, Slow = 4, User = 5, Flat = 6;
        }

        const uint NUM_TANGENTTYPES = 7;
        const uint BEZKEY_NUMTYPEBITS = 3;
        const int BEZKEY_INTYPESHIFT = 7;
        const int BEZKEY_OUTTYPESHIFT = (int)(BEZKEY_INTYPESHIFT + BEZKEY_NUMTYPEBITS);
        const uint BEZKEY_TYPEMASK = 7;

        public static int GetInTanType(uint f)
        {
            return (int)((f >> BEZKEY_INTYPESHIFT) & BEZKEY_TYPEMASK);
        }

        public static int GetOutTanType(uint f)
        {
            return (int)((f >> BEZKEY_OUTTYPESHIFT) & BEZKEY_TYPEMASK);
        }

        public static void SetInTanType(ref IIBezFloatKey key, uint t)
        {
            key.Flags = (key.Flags & (~(BEZKEY_TYPEMASK << BEZKEY_INTYPESHIFT))) | (t << BEZKEY_INTYPESHIFT);
        }

        public static void SetOutTanType(ref IIBezFloatKey key, uint t)
        {
            key.Flags = (key.Flags & (~(BEZKEY_TYPEMASK << BEZKEY_OUTTYPESHIFT))) | (t << BEZKEY_OUTTYPESHIFT);
        }

        public static bool StepAllKeys(int control_handle)
        {
            IControl control = (IControl)globalInterface.Animatable.GetAnimByHandle(new UIntPtr((uint)control_handle));
            IIKeyControl keyControl = (IIKeyControl)(control.GetInterface(InterfaceID.Keycontrol));
            if (keyControl == null) return false;
            IIBezFloatKey key = globalInterface.IBezFloatKey.Create();
            for (var i = 0; i < keyControl.NumKeys; i++)
            {
                keyControl.GetKey(i, key);
                SetInTanType(ref key, TangentType.Step);
                SetOutTanType(ref key, TangentType.Step);
                keyControl.SetKey(i, key);
            }
            control.Dispose();
            keyControl.Dispose();
            key.Dispose();
            return true;
        }
    }
}

#11

ignore me


#12

All we did are based on your code, Thank You my master!
I’m not native English speaker and sometimes I’m not sure I understand your meaning. For example “ignore me” doesn’t makes sense for me in this case.


#13

i just edit an irrelevant post about checking the class ID to make sure the control was a bezier type.


#14

Aha, I got it.