More tools, interfaces and refinements
I've been writing some minor tools, and going GUI crazy the last couple of weeks.
Removing Print Commands
After the discovery of how major an effect using the print command has, I decided to go through all my major scripts and removing print commands from them. Unless I'm debugging I don't need them. I also added a "Done" window that tells me how long a script takes to my longer scripts like the Animation Save/Load utility, and the spur to joint utility.
In the process, I created a new standalone script called printWin. It consists of three processes: printWin initializes the script, you invoke "addPrintWin" to add the contents of a variable to a line in the text scroll list, and showPrintWin to show the window. I didn't combine the commands because I don't want the window to show up until all the data is added, and I don't want to add showWindow to addPrintWin because it can be used in highly iterative loops, and I don't want to call showWindow over and over again hundreds of times.
I also added a log utility to the printWin window, so I could highlight some or all lines and then save them out to a log file for copying, pasting and testing if there's a malfunction. I can also open it in a text file to search for problem lines in thousands of commands to figure out what the problem is. The name and path of the log file can be changed.
This is how I located a problem with my venerable "spur to joint" script, a major script that takes all the vertices in a character, analyzes their weights, removes them from spurs and adds them to the parent bone's weight assignment. Even if it doesn't have any weights assigned to it (which is pretty typical).
In working on the problem, I decided to rewrite a bit of the code to make it more efficient. A lot of repetitive loops could be combined, and instead of parsing the name of the joint to get rid of the suffix, I could use the substitute command. In the months since I wrote the script originally, I've discovered I don't have to put `gmatch` statements into a variable, but can use them directly in "if" statements without an equal. I didn't know that before.
I also made it so I don't have to select the vertices. I can select the objects or the vertices, and the script will figure it out.
So I got the spur to joint script down to between 2 and 2 1/2 minutes running time from 5 minutes or more.
Cleanup and Windows
I wrote a cleanup utility to conform all 17 current characters to a unified naming convention. This utility forced me to learn how to manipulate GUIs in a much more coherent fashion than I'd been doing before. I needed to throw up separate analytical windows, and I didn't want them all over the place.
Window # 1 has the basic controls with 5 buttons. I used the rowColumnLayout command to make the buttons span evenly across the window, two rows of two and a close button at the bottom. There's a textField to enter a character name, and all the changes executed by the script are logged in a textfile, with new entries appearing below existing ones.
Window # 2 appears directly below it and the left edge lines up with the first. This window lists all the joints that are different from the standard model, so I can examine them and see if there's a misnaming, a difference in the hierarchy that shouldn't be there, or additional bones like tails, ears, ponytails, trunks, etc. I found a lot of names of objects that were out of standard that way.
While Window # 2 originally was designed to be used with one character at a time, I had an occassion to check multiple characters. So I rewrote it yesterday to give me the parent transform node of each character, so I'd know which character had what problem. I'm finding I have to do this often enough that I'm going to have to write a standalone script to find the character names in the scene so I don't keep writing the same code over and over again. I can see many uses for this when I do the scene building scripts.
I align the 2nd window with the first by querying the first. For example:
window -tlc (`window -q -te "window_1"` + `window -q -h "window_1`)
`window -q -le "window_1"` -h 400 "window_2";
And I'd do something like that for all the windows. I also have it so all the windows are minimized if the first one is minimized, and the close window closes all the diagnostic windows associated with the tool.
Window_2 has text on the top, followed by a scrollLayout, followed by text, a scrollLayout and then the buttons. This is pretty handy. But it forced me to learn how to put all of this together.
At the end of the script for window_2, it does a query to find out how wide the text lines are, and scales the window and scroll lists to that size. Since all of the windows next to it use a call like `window -q -w "window_2"` as part of the formula to determine their position when opened, this means that all the windows fit together like pieces of a puzzle, and self assemble even if something is moved.
This all means that I am going back to my old scripts to neaten them up. If I have a row of buttons, rather than explicitly placing them with formLayout -e, I'm using automatic calculation to determine how to get the buttons exactly spaced for the width of the window or frameLayout.
The way I'm accomplishing this is with a line like this:
int $windowWidth = `window -q -w "window_2"`;
int $offset = 3;
int $columnSpace = 3;
rowColumnLayout -e
-cw 1 (($windowWidth/5)-$offset)
-cw 2 (($windowWidth/5)-$offset)
-cw 3 (($windowWidth/5)-$offset)
-cw 4 (($windowWidth/5)-$offset)
-cw 5 (($windowWidth/5)-$offset)
-cs 1 $columnSpace
-cs 2 $columnSpace
-cs 3 $columnSpace
-cs 4 $columnSpace
-cs 5 $columnSpace
"buttonRCL";
$offset is the amount subtracted to compensate for the scroll bar and/or frameLayout margins
I don't subtract that from the window value directly so I can alter the widths of the columns to make the buttons as wide as they need to be to fit the text in each button.
Using these techniques, if a window is resized because it's contents are wider than the initial window size, that's the value that's used to resize all the components that weren't responsible for resizing the window. It's a profound discovery for me.
What Comes First, The Code or the UI?
For a simple tool, it's pretty easy to just write the code. But when I need something that does a lot of complicated things, I find myself dummying up the UI first, which then tells me what I have to write into the script. What do I want the tool to do? How do I want it to work. Writing the UI first is sort of an advanced combination of an outline and flow chart. It's actually saved me a lot of time except when I have to learn new UI tricks, but I only have to learn them once. And I write them very quickly now. It also gives me a good idea of what needs to be broken into separate global procs and what can be combined into one.
But I'm getting to the point where I'm starting to think about writing a UI to build UIs. There are some out there, but as usual, I like the control and know what I want.
Converting Motion Data
What I'm currently working on is a method for converting data on a character done before the character was all zeroed out, and when the character's primary pose was done in an "A" pose instead of a "T" pose. I've chosen to go with a "brute force" quasi-mechanical methodology over actually trying to do matrix conversions. This involves posing the old skeleton in the new skeleton's pose, creating a huge number of transforms, synchronizing one with the old skeleton, synchronizing the other with the new skeleton, parenting new to old and then synchronizing the whole thing frame by frame with the old animation. The data is then extracted from the new skeleton transforms as world space information, and transplanted either onto the skeleton itself or controls that drive the IK. A lot of flexibility can be achieved with various parenting schemes.
That's the theory anyway.
Removing Print Commands
After the discovery of how major an effect using the print command has, I decided to go through all my major scripts and removing print commands from them. Unless I'm debugging I don't need them. I also added a "Done" window that tells me how long a script takes to my longer scripts like the Animation Save/Load utility, and the spur to joint utility.
In the process, I created a new standalone script called printWin. It consists of three processes: printWin initializes the script, you invoke "addPrintWin
I also added a log utility to the printWin window, so I could highlight some or all lines and then save them out to a log file for copying, pasting and testing if there's a malfunction. I can also open it in a text file to search for problem lines in thousands of commands to figure out what the problem is. The name and path of the log file can be changed.
This is how I located a problem with my venerable "spur to joint" script, a major script that takes all the vertices in a character, analyzes their weights, removes them from spurs and adds them to the parent bone's weight assignment. Even if it doesn't have any weights assigned to it (which is pretty typical).
In working on the problem, I decided to rewrite a bit of the code to make it more efficient. A lot of repetitive loops could be combined, and instead of parsing the name of the joint to get rid of the suffix, I could use the substitute command. In the months since I wrote the script originally, I've discovered I don't have to put `gmatch` statements into a variable, but can use them directly in "if" statements without an equal. I didn't know that before.
I also made it so I don't have to select the vertices. I can select the objects or the vertices, and the script will figure it out.
So I got the spur to joint script down to between 2 and 2 1/2 minutes running time from 5 minutes or more.
Cleanup and Windows
I wrote a cleanup utility to conform all 17 current characters to a unified naming convention. This utility forced me to learn how to manipulate GUIs in a much more coherent fashion than I'd been doing before. I needed to throw up separate analytical windows, and I didn't want them all over the place.
Window # 1 has the basic controls with 5 buttons. I used the rowColumnLayout command to make the buttons span evenly across the window, two rows of two and a close button at the bottom. There's a textField to enter a character name, and all the changes executed by the script are logged in a textfile, with new entries appearing below existing ones.
Window # 2 appears directly below it and the left edge lines up with the first. This window lists all the joints that are different from the standard model, so I can examine them and see if there's a misnaming, a difference in the hierarchy that shouldn't be there, or additional bones like tails, ears, ponytails, trunks, etc. I found a lot of names of objects that were out of standard that way.
While Window # 2 originally was designed to be used with one character at a time, I had an occassion to check multiple characters. So I rewrote it yesterday to give me the parent transform node of each character, so I'd know which character had what problem. I'm finding I have to do this often enough that I'm going to have to write a standalone script to find the character names in the scene so I don't keep writing the same code over and over again. I can see many uses for this when I do the scene building scripts.
I align the 2nd window with the first by querying the first. For example:
window -tlc (`window -q -te "window_1"` + `window -q -h "window_1`)
`window -q -le "window_1"` -h 400 "window_2";
And I'd do something like that for all the windows. I also have it so all the windows are minimized if the first one is minimized, and the close window closes all the diagnostic windows associated with the tool.
Window_2 has text on the top, followed by a scrollLayout, followed by text, a scrollLayout and then the buttons. This is pretty handy. But it forced me to learn how to put all of this together.
At the end of the script for window_2, it does a query to find out how wide the text lines are, and scales the window and scroll lists to that size. Since all of the windows next to it use a call like `window -q -w "window_2"` as part of the formula to determine their position when opened, this means that all the windows fit together like pieces of a puzzle, and self assemble even if something is moved.
This all means that I am going back to my old scripts to neaten them up. If I have a row of buttons, rather than explicitly placing them with formLayout -e, I'm using automatic calculation to determine how to get the buttons exactly spaced for the width of the window or frameLayout.
The way I'm accomplishing this is with a line like this:
int $windowWidth = `window -q -w "window_2"`;
int $offset = 3;
int $columnSpace = 3;
rowColumnLayout -e
-cw 1 (($windowWidth/5)-$offset)
-cw 2 (($windowWidth/5)-$offset)
-cw 3 (($windowWidth/5)-$offset)
-cw 4 (($windowWidth/5)-$offset)
-cw 5 (($windowWidth/5)-$offset)
-cs 1 $columnSpace
-cs 2 $columnSpace
-cs 3 $columnSpace
-cs 4 $columnSpace
-cs 5 $columnSpace
"buttonRCL";
$offset is the amount subtracted to compensate for the scroll bar and/or frameLayout margins
I don't subtract that from the window value directly so I can alter the widths of the columns to make the buttons as wide as they need to be to fit the text in each button.
Using these techniques, if a window is resized because it's contents are wider than the initial window size, that's the value that's used to resize all the components that weren't responsible for resizing the window. It's a profound discovery for me.
What Comes First, The Code or the UI?
For a simple tool, it's pretty easy to just write the code. But when I need something that does a lot of complicated things, I find myself dummying up the UI first, which then tells me what I have to write into the script. What do I want the tool to do? How do I want it to work. Writing the UI first is sort of an advanced combination of an outline and flow chart. It's actually saved me a lot of time except when I have to learn new UI tricks, but I only have to learn them once. And I write them very quickly now. It also gives me a good idea of what needs to be broken into separate global procs and what can be combined into one.
But I'm getting to the point where I'm starting to think about writing a UI to build UIs. There are some out there, but as usual, I like the control and know what I want.
Converting Motion Data
What I'm currently working on is a method for converting data on a character done before the character was all zeroed out, and when the character's primary pose was done in an "A" pose instead of a "T" pose. I've chosen to go with a "brute force" quasi-mechanical methodology over actually trying to do matrix conversions. This involves posing the old skeleton in the new skeleton's pose, creating a huge number of transforms, synchronizing one with the old skeleton, synchronizing the other with the new skeleton, parenting new to old and then synchronizing the whole thing frame by frame with the old animation. The data is then extracted from the new skeleton transforms as world space information, and transplanted either onto the skeleton itself or controls that drive the IK. A lot of flexibility can be achieved with various parenting schemes.
That's the theory anyway.
