Making A Hello World Substance Painter Plugin

Substance Painter plugins use the QT Meta Language, or QML files to build their interface. From Wikipedia:

It is a JSON-like declarative language for designing user interface–centric applications. Inline JavaScript code handles imperative aspects. It is part of Qt Quick, the UI creation kit developed by Nokia within the Qt framework.

Using this information, we can start building a window with a button to execute our script.

Visual Studio Code

For this tutorial I’m going to be using Visual Studio Code, a lightweight IDE from Microsoft. It’s not the same thing as Visual Studio, but it’s a nice scripting editor that’s available on Mac, Linux and PC. Other text editors like Sublime will do the job quite well.

Installing QML Syntax Highlighting

  • By default, QML files will appear as ordinary text files in Visual Studio Code. While this won’t stop you from being able to write the plugin, adding some QML support will make reading, organizing and editing our script easier. 
  • To do this, I’m going to install a QML extension in Visual Studio Code for Syntax highlighting. 
  • Use the View->Command Palette and type in Extensions: Install Extensions

  • Type in “QML” into the search bar and install the “QML language support for Visual Studio Code” extension. 
  • Once it is installed, restart visual studio code- your QML files will now have syntax highlighting. 

Starting our Plugin

  • This is some documentation online for substance painter scripting, but your installation also comes with some example plugins.
  • Plugins for Substance Painter live in 
    • Windows : C:\Users\*username*\Documents\Allegorithmic\Substance Painter\plugins 
    • Mac OS : /Users/<username>/Documents/Allegorithmic/Substance Painter/plugins 
    • Linux : /home/*username*/Documents/Allegorithmic/Substance Painter/plugins 
  • Note that for this tutorial I am using Substance Painter 2017x - the plugin directory changed since version 2.
  • This is where we will be creating our plugin- be sure to look through the other plugins there to see how they work. 
  • Valid plugins here will automatically be detected by Substance Painter when it is first opened, and become available via the Plugins menu option. 

Making a Hello World Plugin

  • For a plugin to be valid, it needs to have a definition, and a main entry point qml file. 
  • Navigate to the plugins directory for your system. 
  • Create a folder here called “HelloPlugin” 
  • Inside the plugin, create two files- 
    • plugin.json 
    • main.qml 

Filling in the main file:

  • The main.qml file is the entry point to your plugin. 
  • When the plugin is first loaded, this file will be used to initialize any additional data or properties the plugin needs, like adding extensions to the main toolbar. 
  • For now, we are going to make a really simple main function, which will log “Hello world!” to the console when the plugin is loaded. 
Ship it!

Filling in the JSON file:

  • The JSON file contains a manifest of metadata about your plugin. 
  • When you use a plugin’s “About” menu in Substance painter, the data you see there is populated from the plugin.json file of the relevant plugin. 
  • For example, the resources-updater plugin ‘about’ window looks like this: 

  • And looking at the plugin.json file of the resources-updater plugin, we can see how this data is defined: 

  • In this case, our JSON file is defining key : value pairs which are read by Substance Painter when it loads the plugin. 
  • We can use the same structure in our HelloPlugin to have a simple about window available. 

What we get so far:

When we load the plugin...

Our very informative "about" window. 
  • Right now we can see the plugin load, but it’s not particularly useful. 
  • We also get an about window courtesy of the plugin.json file. 
  • Let’s add a window- later we can use this window to add buttons and other functionality. 

Adding a window to the plugin

  • Create a new file in our HelloPlugin directory. 
  • Name it HelloWorldWindow.qml
  • This is going to where we define our window object.
  • Inside the file, we are going to add just enough code to define an extremely simple window. 
  • A few things to note: 
    • The window class is imported using the import AlgWidgets 1.0 call. 
    • The properties are like variables on the object type.
    • Assigning a specific id to an object is useful, as it allows us to reference this object elsewhere in our plugin. 
    • Likewise, properties like the visibility can be accessed via the object id.  
  • We now have enough code to build a simple window, but before we can see our window, we need to instantiate it in the main.qml file. 
  • Open the main.qml file, and at the top, add the following code: 

  • The code above creates an instance of a HelloWorldWindow and assigns it the id “window”. 
  • As the window is first instantiated when the plugin is loaded, in order to see it you will need to disable and re-enable the plugin. We will fix this later. 

Creating a button:

  • Rather than logging to the console when the plugin is loaded, let’s make a button to do that. 
  • Open the “HelloWorldWindow.qml” file. 
  • We are going to add three things- 
    • A series of layout elements. 
    • A label. 
    • A button. 

  • QML windows are created using a series of nested layout objects- for our purposes we are going to use a column, a rectangle and a row. 
  • We need to add additional import statements to access these object types- QtQuick and QtQuick.Layouts.
  • The column represents the overall layout- elements will be stacked within this shape in the order that they are added. 
  • The rectangle allows us to fill a partition of this column with a child layout. 
  • Finally the row layout allows us to add elements that will be rendered from left to right in the order in which they were added. 
  • Adding an AlgLabel and AlgButton in the row layout adds two new elements to our window. 
  • Finally defining the “onClicked” event for the button replaces where we were logging in main.qml on startup. 

  • I also commented out our log in the main.qml file. 

Our button is very chatty. 

Reloading your script:

  • At this point it’s good to know you can reload your script on the fly using the Plugins->HelloPlugin->Reload menu in painter. This is going to be super useful as we add more complexity. 

Adding our plugin to our toolbar:

  • Right now if you close the plugin window, it’s gone until you restart the plugin. 
  • To solve this issue, let’s add a button to the toolbar. 
  • The button in the toolbar is going to be pretty simple- all it’s going to do is toggle the visibility of our plugin window when it is pressed. 
  • First, we are going to make our HelloPluginWindow start invisible. 
  • We do this by changing the ‘visible’ property from ‘true’ to ‘false’ in the HelloPluginWindow.qml file. 
  • Now we are going to make a new file called ‘toolbar.qml’ 
  • It’s pretty simple, and similar to what we have done before- it’s just a row, with a button. 
  • Something important- the property variable “windowReference” will be filled in by our plugin when it is loaded. 
  • Because locally the windowReference starts as null, we wrap the calls to it later inside a try/catch block. 
  • This will stop terrible things from happening, like a crash, if something elsewhere in our script stops us from being able to make the window- instead of a crash we can log information to the console. 

catch(err), catch(err) not a belly scratch(err)...
  • Finally, in our “main.qml” file, we are going to add an new toolbar widget, which will instantiate our “toolbar.qml” as a button on the toolbar. 
  • We also assign our HelloWorldWindow instance to the windowReference variable in our toolbar button, using it’s id. 

  • The end result is a giant blot on the toolbar that we can click to turn our window on and off: 
Now thats UI...

Adding an icon

  • Finally, even with as good as our giant white square looks, we can add an icon.svg file to our plugin and add it to the toolbar.qml script to make it more appealing. 
  • This icon will be used in the substance toolbar to show us which button is linked to our window. 
  • Wikimedia commons has some good free svg files. For our purposes I am going to use this one
  • To add the icon to our toolbar, we need to add an Image block. 
  • This is what we are going to end up with: 

Hi! What a friendly little widget.
  • To make the icon to render correctly, we need to assign it a rectangle area, and make an image widget which is the child of that area. 
  • Using the Rectangle area gives us control over the hover state colors, and the anchors. 
  • The Rectangle is a child of the Button widget, and will inherit the button’s size information by using the “anchors.fill: parent” hint. 
  • We make sure the image also inherits these size settings by using the same hint in the child Image widget. 
  • This is the code we end up with: 

  • Beside giving us a nice little icon, there is something interesting going on where we define the color of the rectangle based off the hover state. 
This is called a ternary operator, defined by the ? symbol. 

  • In this instance the rect.hovered boolean allows us to change the assignment of a variable based on the state of a boolean. 
  • The hovered state can also let us add some other cool things, like animations, to our widgets. 

Making our icon animate:

  • As a fun little exercise, we are going to animate the hand using qml animation sequences
  • Let’s make the hand wave at us. 

  • Using this code, our hand will wave at us twice each time we hover over it. 


  • Note that the sequence is actually made out of a number of nested animations. These will run top to bottom, and in the cast of the nested sequence, each animation nested in that sequence will play before moving to the next animation in the parent sequence. 
  • Using this technique, you are able to add some complex behaviors to your widgets. 

So that's it for adding a basic plugin to Substance Painter! I'm going to follow this up with another post where we actually make it do something useful...



One line Unreal Engine 4 (mac os) Review:
Doing Ue4 development on a Mac is not a great experience.

Update: Just ran into this one... cleaning your project in XCode nukes the actual editor. Case in point.


Probably familiar to any TA or Engineer who deals with their graphics pipeline, RenderDoc is a tool I have found incredibly useful for debugging graphics in Unreal.

Formerly a Crytek internal graphics debugging tool, it was released to the public in 2014. The tool is developed by Baldur Karlsson, and it boggles my mind that a tool this gosh-darn useful has been given to the public for free. Kudos to Baldur and to Crytek.

Previously I was using NVIDIA Nsight to view and debug runtime atlased textures, and it was quite slow and somewhat unintuitive to sift through the outputs to find what I was after.

RenderDoc on the other hand is not only fairly straight forward to get running, the turn around time to get meaningful output for frame-debugging is extremely rapid.

For Ue4 integration I'm using Temaran's RenderDoc Ue4 plugin, which makes frame captures in game as simple as entering a command on the command line- RenderDoc.CaptureFrame

Check it out if you need to know more about your graphics pipeline.

Substance Designer foray

I'm pretty late to the whole substance craze, having spent three years in a mobile development environment where textures larger than 512x512 caused eyebrows to raise within the engineering team.

But I kept hearing things about it being amazing, so I thought I'd give it a shot. Here is my attempt at a "hand painted" look, based off of similar processes I'd use in Photoshop.

The texture is generated using an exported sbsar material and... well, thats it. I saw a nice example online of using a switch to swap out gradient maps in a material which allowed me to create a bunch of looks in the one material.

This tool makes me happy.

A Quick Checkin- Clion, Unreal and Mac

Super quick check-in. Hello world! For the last year or so, I've been working with Echtra Inc. on a great project as a Tools Engineer/Technical Artist guy.

The project is using the Unreal Engine, which I like more and more every day. On Windows, C++ plus Visual Studio Pro and Visual Assist is a great combo, and I happily churn through my daily tasks without fighting the tools too much.

Not so on my Mac at home. Programming in Unity on a Mac is great! Mono Develop isn't amazing, but it isn't terrible. But Unreal on a Mac. I want it to be fun, I want it to be possible, but I just can't get myself to like, let alone enjoy, XCode.

On that, for anyone thinking "well, you could just use blueprints..." etc, I feel it's too much of a shackle to not be able to just dive into the guts of it. C++ or bust.

So anyway, I recently adopted PyCharm at work and really enjoyed using it for my Python tools. I noticed that JetBrains also made an IDE called CLion, and they also had recently got it running with Unreal, so I thought, what the hell, why not.

Turns out their documentation is missing a couple of important notes, that maybe they take for granted, but after a couple of forum dives I managed to actually get it compiling, and running, my little test project.

So what was missing?

Something isn't set...

Once I run through their setup scripts, these were the things I needed to double check.

  • Make sure Mono is installed and up to date, and that the mono command is available in the terminal.
  • Once you generate your CLion project via the editor (make sure to follow the instructions here) you need to update the generated configs with paths to the editor executable. 
  • eg: /Users/Shared/Epic Games/UE_4.15/Engine/Binaries/Mac/
  • Finally, now that it's pointing to the editor correctly, add an absolute path to your project's .uproject file in the project arguments. 
If everything went well, you should now be able to build and run your project from within CLion. Bye bye XCode. I'll probably post some time in the future about how I'm finding CLion. Well, it compiles, and thats a start...

GDC 2016- San Francisco Coffee places

Wait, what? 2016 already? I have not been as pro-active in this whole blogging thing as I could have been, so for now let me make it up to you all by letting you know where to find the good stuff while you are perusing the talks at GDC 2016.

Near the Moscone Center:

Special Xtra

One of my favorite places. Great coffee to get your energy back after a long talk about rigging (try the New Orleans iced coffee for a real kick). If you get there in the morning, grab one of the croissants fresh out of the oven. The staff are great, and could probably give you a bunch of pointers on good places to check out in the area.

Elite Audio and Coffee Bar

Because what goes better together than coffee and high end audio systems? Sure. Anyway, this one is very close to the Moscone, but will probably be packed full of people, so keep that in mind. Cappuccinos here are great, and once again staffed by a good crew of people. They serve Neighbor Bakehouse pastries most days, and those alone are worth checking out.

Sightglass Coffee

Great coffee, and also a good opportunity to take home a San Francisco local roast. A little bit of a walk from the Moscone, and there will probably be a line either way, but well worth the walk. Once again, Neighbor Bakehouse pastries. Eat them!

Chrome Industries

Continuing the trend of a store that sells something (in this case high end cycling gear) but also serves a decent roast, Chrome Industries is a short walk from the Moscone down 4th st. It's also near the Hotel Utah, which serves a different type of brew (worth checking out for beers!).

Not so near the Moscone Center:

Contraband Coffee bar

If you find yourself for some reason near the Polk street area, Contraband Coffee is nearby on Larkin and California. It's got good coffee and hot chocolate. The snacks are good too, but it's worth checking out Flower and Co. nearby or MyMy for a real meal. I have seen Neighbor Bakehouse pastries here too. See a trend?

The Interval

If you find yourself near Fort Mason, the interval is a good place to stop by. Good coffee, provided there aren't too many people around. The crowd can occasionally be a bit of a downer.

Four Barrel Coffee 

If you find yourself in the mission, check out the four barrel coffee place down there. I've heard mixed opinions about the Four Barrel coffee, but I'm a fan. Delicious! Being on Valencia St, its also surrounded by a bunch of excellent places to go grab lunch or dinner.

The Mill

The Mill serves four barrel coffee, as well as that whole thick toast thing. The toast is good I guess, but I really go there for the coffee- that's really good. They sell bread too which is pretty damn good bread, although carrying that around the conference floor might not work out so well.

So that's some places to get you started- have you found any that you think should be on this list? Also, hit me up you you want to meet up for coffee and talk game dev stuff. As you can tell, I like coffee.

Scratch Pad Unity Utility.

One of my friends has made his Unity Asset Store debut with "Scratch Pad"- a handy little utility that lets you bookmark scenes, animations, scripts etc.

It always kinda bugged me that you can't put files into your favorites area of the Project panel, which is something this Utility does pretty well- being able to make 'working sets' of files is pretty useful, especially when debugging all the different components that might make up a single asset in game.

Check it out here.