Community
3ds Max Programming
Welcome to Autodesk’s 3ds Max Forums. Share your knowledge, ask questions, and explore popular 3ds Max SDK, Maxscript and Python topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

C# Api. Access Controller/Sub Anim Values

4 REPLIES 4
Reply
Message 1 of 5
enterNameHere
854 Views, 4 Replies

C# Api. Access Controller/Sub Anim Values

Hey All

 

I'm dipping my toe into the max c# api. I'm trying to access the values of a node's basic transform sub anim tree but i'm running in to issues.

 

The code below is some simple code that should recurse the sub anim tree of a selected node (INode) and show a tree view representing the controller tree.

 

I want the tree to also show the current value of the sub anim, so i'm trying to access the 'value' via a parameter block (i gather from the docs that's how they are stored and accessed).

However i am unable to access any parameter blocks. in the code below numberOfParamBlocks is always zero.

 

So i'm stumped on how to access the data. I'm not sure if i'm going about this all wrong?

 

        
/// <summary>
/// Recursive function that adds tree items for each sub anim and its values
/// </summary>
/// <param name="subAnim"></param>
/// <param name="fullList"></param>
/// <param name="treeParentItem"></param>
private void recurseSubAnims(IAnimatable subAnim, List<IAnimatable> fullList, TreeViewItem treeParentItem = null)
{
    // create a tree node for the current sub anim
    TreeViewItem treeItem = new TreeViewItem();
    string saName = subAnim.ClassName.ToString();
    treeItem.Header = saName;
    treeParentItem.Items.Add(treeItem);
            
    // loop the child sub anims
    for (int i = 0; i < subAnim.NumSubs; i++)
    {
        // current child sub anim
        IAnimatable childSubAnim = subAnim.SubAnim(i) as IAnimatable;

        if (childSubAnim != null)
        {

            // store the number of param blocks... for debugging                    
            int numberOfParamBlocks = childSubAnim.NumParamBlocks; // ALWAYS 0!

            // loop the parameter blocks to get acces to the data values..
            for (int pb_i = 0; pb_i < numberOfParamBlocks; pb_i++)
            {
                // NEVER GET HERE!!

                // create an object variable for the unknown data type.
                object val ;

                // get the current param block
                IIParamBlock2 pb = childSubAnim.GetParamBlock(pb_i);                        
                        
                // time variable for the getValue()
                int time = (int)MaxUtils.maxIntr.Time;

                // seems the getValue needs this...
                Autodesk.Max.MaxSDK.AssetManagement.IAssetUser au = null;

                // and also this...
                IInterval ivalid = null;

                // get the value. 
                pb.GetValue(1, MaxUtils.maxIntr.Time, au, ivalid, -1);

                // add a tree item representing the value
                TreeViewItem valTreeItem = new TreeViewItem();
                treeItem.Items.Add(valTreeItem);

                // recurse
                this.recurseSubAnims(childSubAnim, fullList, treeItem);
            }
        }
    }
}
        
/// <summary>
/// Main populate method for the tree node
/// </summary>
/// <param name="node"></param>
public void populateTree( IINode node ){

    // list that will be populated by reference
    List<IAnimatable> fullList = new List<IAnimatable>();
            
    // get a list of all selected nodes.
    List<IINode> selectedNodes = MaxUtils.getSelectedNodes();
            
    // loop the selected nodes
    for (int i = 0; i < selectedNodes.Count; i++)
    {
        // variable to current Inode
        IINode maxNode = selectedNodes[i];

        // create a tree item
        TreeViewItem nodeTreeItem = new TreeViewItem();
        nodeTreeItem.Header = maxNode.Name;
        this.treeView_subAnims.Items.Add(nodeTreeItem);

        // im just casting varibles so i can see them in debugging...
        int numSubs = maxNode.NumSubs;
                  
        // loop the sub anims
        for (int tr = 0; tr < numSubs; tr++)
        {
            // current sub anim
            IAnimatable childSubAnim = maxNode.SubAnim(tr);

            if (childSubAnim != null)
            {
                // kick off main recurse
                this.recurseSubAnims(childSubAnim, fullList, nodeTreeItem);
            }

        }
    }
}

 

 

Thanks for any help.

4 REPLIES 4
Message 2 of 5

Hi, I am not sure I understand exactly what you want. Essentially parameter blocks can be sub-animatables themselves. For this, I think you are going to have to go more specifically to the controller hierarchy and get the values. Each controller may handle different types, too, so be careful when pulling the values.

 

I would suggest looking in the SDK samples. The .NET API is simple thin wrappers around the C++ API. Many times you can find techniques in the C++ code that can be applied to the .NET side.

 

Hope it helps.


Kevin Vandecar
Developer Technical Services
Autodesk Developer Network



Message 3 of 5

Hi Kevin

 

Aplogies if i was unclear, and thanks for the reply. I'm testing parsing scene data with the api. In the long term i hope to export bits of data we need for our pipeline. I can technically do this with maxscript, but maxscript is slow with large data sets... and it's maxscript.

 

I may have had the wrong idea that all data values were managed via parameter blocks. Again my max coding is limted to maxscript and i'm just looking into the c# api.

 

I took your advice and looked at the TMController tree. I'm pretty sure now that I can get the data through the IControl.GetValue(), however my current code below is causing a hard crash, with no debugging help on crash.

 

Hopefully I'm not going about this completely incorrectly.

 

  public void populateTree( IINode node ){

            int sceneTime = Kernel.Interface.Time;
            
            // get a list of all selected nodes.
            List<IINode> selectedNodes = MaxUtils.getSelectedNodes();
            
            // loop the selected nodes
            for (int i = 0; i < selectedNodes.Count; i++)
            {
                // variable to current Inode
                IINode maxNode = selectedNodes[i];

                // create a tree item
                TreeViewItem nodeTreeItem = new TreeViewItem();
                nodeTreeItem.Header = maxNode.Name;
                this.treeView_subAnims.Items.Add(nodeTreeItem);
				
				//**********************************************************************************
				// below i am only trying to get the position x value of a selected node...
				
                // get the matrix controller
                IControl tm = node.TMController;
				
				// get the position controller instance.. 
				// c# uses properties to replace pointers
                IControl pc = tm.PositionController;
                
				// create an interval
				IInterval ivalid = Kernel.Global.Interval.Create();
				
				// set it to now
                try
                {
                    ivalid.SetInstant(sceneTime);
                }
                catch { }
				
				// create a system object to hold the unkown value type
                object pXval = new object();

                try
                {
                    //allways crashes max, with no debug info on what caused it..
                    pc.XController.GetValue(sceneTime, ref pXval, ivalid, GetSetMethod.Relative);
                    
                }
                catch { }

            }
        }
Message 4 of 5

Ok im still stuck on this.

 

So, i'm going to pose the question in a different way.

 

I want to recreate the maxscript code, below, in the api (c# but an example in C++ would be great). Below i am getting a node, recursing its subanims, querying a .controller and, if there is one, getting the current value.

 

I realize something like this may be much more complex than maxscript, but i'm really not getting anywhere, and i'm not even sure i'm going about this the right way.

 

So, if anyone would have any idea how to do this, and could help me out, it would be a great help.

 

fn recurseSubAnims theSubAnim levelStr:"--" =(
	
	-- loop to the number of sub animation tracks (.numsubs)
	for subIndx = 1 to theSubAnim.numSubs do(
		
		-- get a handle to the child sub anim at the index number.
		local childSubAnim = getSubAnim theSubAnim subIndx
		
		-- we'll just do some nice printing for now
		print (levelStr + "> " + childSubAnim.name)
		
		-- here's where i get stuck in the api
		if childSubAnim.Controller != undefined then(
			-- I WANT THIS VALUE !!!!!
			print (levelStr + "> VALUE >> " + (childSubAnim.Controller.value as string))
		)
		
		-- call this function again, using childSubAnim now as the element to search for further child subanims
		recurseSubAnims childSubAnim levelStr:(levelStr+"--")
	)
	
)

-- kick off the recursion at the top level with a single selected node
recurseSubAnims (Sphere())
Message 5 of 5
jcdeblok
in reply to: enterNameHere

For anyone stumbling across this, setting the pXval object to a value of the type you are about to receive makes it work. so after declaring it as an object add this: pXval=0.0f; (if it's a float your after)

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report