[Closed] Isolated Problem With Max 8 Script Controller
I am working on a scripted utility that automates the creation of a superskeleton over the top of an animation-driven skeleton, the entirety of which superskeleton is controlled by constraints, script controllers, and so forth. However, I am having a problem with one of the script controllers and have isolated the cause, but cannot figure out what is happening. The basic process in the setup tool is as follows:
theController = arrayOfScriptedBones[someIndex].position.controller = position_script()
theController.addNode "node_nodeName" MatrixHierarchy[someOtherIndex] --There are 4 of these defined node variables
theScript = "/* These are pointers to other objects in the scene used in the calculation */
"
theScript += "local node_nodeNameP = node_nodeName.parent
"
/* A series of mathematical operations here */
theScript += "local someAngle = (node_someOtherNodePointer.transform * inverse node_nodeNameP.transform).rotation
"
/* The rest of the contents of the script controller */
theController.script = theScript
With the exception that none of my other scripts have more than one defined node variable (that is as defined in the script controller interface), everything else follows this basic pattern and works. The problem here seems to be this line within the script controller:
theScript += "local someAngle = (node_someOtherNodePointer.transform * inverse node_nodeNameP.transform).rotation
"
If I comment out this line, and any others that multiply the transform matrix [b]node_nodeNameP[/b] with a node variable's transform matrix (such that no references to that node exist within the script controller apart from its definition) then the script evaluates fine, albeit without the correct result. However, if I leave in those lines, the script controller will crash once the setup tool has run and tell me that (depending upon which line I comment) some node is undefined (one that is determined by traversing the hierarchy in the controller's script--not one that is defiend using the controller's interface). When I look in the script editor window, none of the variables I defined via the [b]addNode[/b] function (which is executed before the contents of the script controller are created or changed) exist. To make matters more confusing, if I comment out those lines and allow the tool to create a script controller that incorrectly evaluates, I can enter the script controller and manually insert those lines which were commented out and have it evaluate properly. If anyone has any ideas or needs more information please feel free to share.
[b]EDIT:[/b] I have tried using the controller interface ([b]addNode[/b]) to add the node variables I had been acquiring by traversing the hierarchy within the script in order to resolve the problem, and the results appear to be the same. The operations are still failing on lines that involve ([b]node_someOtherNodePointer.transform * inverse node_nodeNameP.transform[/b]), regardless of whether or not I decompose the matrix. Keep in mind that this is not a dependency problem, as [b][b]node_nodeNameP [/b][/b]is a top level hierarchy node, and the computations still work when I add them into the script controller by hand if I bypass them in the setup tool.
Hi, AdamMechtley
I’ve tested your setup and cannot find any problem with it. My only difference is that the nodes referenced in the script are either created with the .addNode method or within your local variable assigned to the node’s parent. It all works fine. To simplify your setup, Ive created a three spheres scene, each named $Sphere01, $Sphere02, $Sphere03 (the default names) and made the 02 child of 01. Then run this script:
a = $Sphere01
b = $Sphere02
c = $Sphere03
d = #(a,b,c)
theController = c.position.controller = position_script()
theController.addNode "node_nodeName1" d[1]
theController.addNode "node_nodeName2" d[2]
theScript = "local node_nodeNameP = node_nodeName2.parent
"
theScript += "local someAngle = (node_nodeName2.transform * inverse node_nodeNameP.transform).rotation
"
theScript += "global myVariable = someAngle
"
theScript += "[0,0,0]"
theController.script = theScript
it all turns out correctly, the node assignments are showing in the variables window on the script and the global myVariable can be tested at any time and returns a correct value.
Not much help, I know, but I have isolated your lines and work fine. Could it be somewhere else?
Rafael Polit Jr.
Quito, Ecuador.
Here is some more information if it helps. Below is a direct cut and paste from part of my setup tool to show you exactly the lines that, if commented out, let it work.
theController = ExpressionDrivenJoints[29+indexMove].position.controller = position_script()
theController.addNode "node_armLower" MatrixHierarchy[13+hierarchyMove]
theController.addNode "node_armUpper1" ExpressionDrivenJoints[13+indexMove]
theController.addNode "node_deltoidOrigin" ExpressionDrivenJoints[18+indexMove] --AcromionProcess
theController.addNode "node_deltoidInsertion" ExpressionDrivenJoints[14+indexMove] --ArmUpper2
theScript = "/* These are pointers to other objects in the scene used in the calculation */
"
theScript += "/* node_deltoidOrigin references a null object in 3DS Max to bypass a dependency loop that will not exist in game */
"
theScript += "local node_armUpper = node_armLower.parent
"
theScript += "local node_shoulder = node_armUpper.parent
"
theScript += "local node_ribcage = node_shoulder.parent
"
theScript += "
"
/* Some more of the script here */
theScript += "local angleArmUpper1 = (node_armUpper1.transform * inverse node_ribcage.transform).rotation
" --THIS LINE FAILS
/* Some more of the script here */
theScript += "local insertionPosition = (node_deltoidInsertion.transform * inverse node_ribcage.transform).position
" --THIS LINE FAILS
theScript += "local originPosition = (node_deltoidOrigin.transform * inverse node_ribcage.transform).position
" --THIS LINE FAILS
/* Some more of the script here */
theController.script = theScript
If it is helpful, I also want to note that this exact process worked fine in Max 7 using node custom attributes attached to the controller. I guess really what it will take to solve this problem is someone understanding the symptom that I am observing.
Thanks!
I have made some changes to surrounding areas of the script that (for no apparent reason) seem to have solved the problem of the nodes not showing up in the interface. However, what happens now when I run the tool is it still breaks execution after assigning this script to the controller in question with the exact same error message as before, but I can simply press the evaluate button in the interface and close it and it works fine (with the exception of course that it does not perform the remaining operations of the tool). The operations within the controller’s script that seem to be confusing it are used in other controllers’ scripts as well (multiplying a different node’s matrix by the inverse matrix of the node that seems to be causing problems here), which is further confusing me.
OK well I found a solution to this problem. However, I am not sure why I had to do this one different from all the others in order to get it work. I used the following basic process:
theController = position_script()
theScript = scriptContents
theController.script = theScript
theBone.position.controller = theController
Contrast with the method I am using on other bones:
theController = theBone.position.controller = position_script()
theScript = scriptContents
theController.script = theScript
Hi AdamMechtley
I have never seen a three way equal like that before. Is it a common practice among programmers? I admit it worked when I tested it from your script, but is did seem a little strange. Since Im very new to programming I assumed that was common.
Glad to know you worked things out (and all by yourself, with no help over here! )
Rafael Polit Jr.
Quito, Ecuador.
Hi Rafael,
It is not necessarily common, just something MaxScript allows you to do (the expression basically works right to left) to cut down on indirection and lines.
Essentially what is happening in my case is, if I create the controller as a separate node not attached yet to an object, it can evaluate before it is attached, and then just hold its value. Otherwise, when it is attached to an object, it is going to try to update continually (like whenever a change is detected in the SG), which meant (I guess) that it was trying to evaluate the script before all of the connections were re-evaluated. Times like this I just like to declare victory and leave the battlefield, but it would still be nice to know why it broke only on this controller–much more complexity, many more node connections? No idea.
I know what you mean. One has to find a middle point between having succeded (problem solved) and learning something new so it doesnt happen again and, hopefuly, scripts get smaller and more efficient in time. But one can get stuck learning and learning without realy producing anything final or keep producing final results with more unfolded and less efficient scripts that are not really what one hopped for but do the job.
Anyway, thanks for sharing your findings. Sure others can benefit from them.
Rafael Polit Jr.
Quito, Ecuador.