top of page

Python

SpeedTree: Texture Renamer

I had previsouly created this same tool (but now this version is better) at a studio I was working for to help speed up the repetative speedtree ingestion tasks. We had a number of different tree species and vaiants within the same species. 

Like all tools that I make I start working where any user input is done through the terminal, no UI. However for this I wanted to create a standalone interface and go through the process of designing and implimenting the code for this.

The tool reanames both the texture files and the .stmat (xml formatted) file that has all the associations for each material for that particular tree asset.

Tool breakdown

QtDesigner

Main - Renaming Tab
I wanted to keep the UI simple, minimal inputs for the user. The more control the user has, the more error handling I would have to account for and catch.
So just two inputs needed, 'Path to Files' and 'Asset name'.

I also knew that its helpful having a log to print back exactly what has been processed and where it is. When dealign with a lot of items and that the process is very repetative its easy to have made a mistake and not know about it untill you are in deep at which point it can be hard to go back to find the exact point where things when wrong.

I also wanted to include a clear log function which will help with organisation and keepingtrack of where you are in processign a lot of items.

Naming Conventions Tab

This was a new idea whilst developing this incarnation of the tool. I tried to make something that will work at multiple studios or projects in the same studio but with different naming conventions so that it has longevity. I did add some other featuers here but due to scope creep I removed them.

I was consious to make the anming for all the componets obvious and unquie so that I can refeance them in the code cleanly. I will also help to isolate items when working with CSS.

I used a little bit of CSS for the UI.
Some useful bits that i picked that I didn't know before:

[targetClass]{

someAttriubte: rgb(0,0,0);

}

The class of the UI element that you're targeting can be defined before the '{ }'. Everything inside the curly brackets applies to this. If a more specific UI element needs to be targeted you can use the the '#' and then the name of the UI element after the class. If an action for the UI element needs its own style then a double colon can be used '::'.
See the example in the above screenshot for clearLog_pushButton.

Converting .ui with PySide6

There's a couple of differnat way you could referance the file tat contains the UI infomation. You can referance the .ui itself. from what I understood though this isn't as performant. Plus the studio I was working at at the time requested Python 2.7 and PySide2. Pyside is often preferable over PyQt as the liecensing is more open.

To convert the .ui file, from the directory containing it start a terminal. from the termainl enter:

PySide6-uic [name of file to convert].ui -o [name to file to be created].py

Its also useful to know the name of the class for the main window/dialouge/widget that you built the UI on. You'll need to referance this when importing into the main script.

Main script inital set up
 

To referance the UI python file use;

'from [name of file] import [main window class]'.

Inside the mian UI class, I set up the intial states of checkboxes and default values in QLineEdit's.

The other think i set up was the function calls when a button has been clicked.

The main button that triggers the the renaming process is 'run_pushButton' calling 'self.onRunAction'.

Before actual editing of files happens we want to catch any user input errors.

There are separate functions for catching different errors. If its does detect a error it will return an error message. this error message is then passed into the 'error function(errorDetails)' which prints out the error message to the QTextBrowser and changes the StyleSheet for that ui element.

Check by UI class type
 

I wanted to highlight this bit of code as it was new for me to use. I wanted to check all the QLineEdits on the naming convention tab to see if they were empty.

Because I had named the frame 'components_frame' it was easy to referance and then use '.findChildren([classType])'.

Any QLineEdit that was blank the name of it would be returned out of the function with the error details to be printed to the QTextBrowser. 

Set Verticle Scrollbar To Bottom
 

This deserves its own section because annoyingly both times I've coded this tool it has actually taken the most amount of time to figure than any other part.
As you can see the solution is the second from last line.

Dictionary for MapTypes
 

SpeedTree is consistant with its naming (apart fromt he diffuse map).

So when the naming needs to be swapped it can look up its matching pair from the dicitionary for the mapType. The naming it will swap for will be user defined from the 'Naming Convention QLineEdits'.

This will make it easy to add extra items to the dicitonary if there's new maps from speedtree or if current ones need to be adjusted.

Read and Edit XML data
 

I used the ElementTree library to go through the .stmat (xml formatted) file.

To traverse through the XML document its helpful to see inside it first to know what the tags and attriubtes are.
The 'Tag' name is the first part to appear after '<'. Attibutes are after this. The name of the attriubtes are on the left side of the equals sign and the values on the right. The assocaited attubtes are end with '/>'.

I did two 'nested For loops' looking for each map inside each material.Once an Attiubte has been updates with new naming, tree.write needs to be used.

 

I added in the "UTF-8" encoding and xml declaration so that its as simular to the orginal .stmat file.

bottom of page