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.
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.
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 { } } }
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())