Start Here!!!

0

Hi there 🙂

This Guide will cover Basic to Advanced Scripting, Programming, Plugin Development, Class Creation and much more. Including lots of handy titbits and explanations, like how to successfully use the Xsi help files. The goal being to equip you with the knowledge and tools you need to create awesome scripts, plugins and even external tools that speed up your workflow and make you a super programming genius!!! Which all results in your life being made a whole lot easier and giving you more time to spend on the artistic side of things, or you could even move over completely and work as a super programming genius. Either way this blog puts the power in your hands 😉

Hope you enjoy!
(And feel free to let me know what you think)

The Lessons are split up into sections:

  1. Recruit – Introduction to Scripting
  2. Trooper – The simple programming side of scripting
  3. Hardened – Basic Programming and Plugins
  4. Veteran – Classes, Modules, Threads and PyQt for Xsi.

And the Sections are made up of the following lessons:

Recruit:

  1. Easily turn echoed commands into buttons.
  2. Applying a command to multiple objects.

Trooper:

  1. Finding Parameters (Introduction to the “Object Model”).
  2. Finding How to Access Parameters Visually.
  3. Finding parameters and their values with code.
  4. Successfully using the help files.

Hardened:

  1. Creating a Plugin.
  2. Adding a Plugin to a Menu.
  3. Plugins that take Input and give Output
  4. On Event Plugins
  5. What is PyQt and how does it make my plugins AWESOME?!
  6. Installing PyQt for Softimage
  7. Creating a Simple PyQt Plugin

Veteran:

  1. Modules
  2. Multi-Model Importer

 

You can also download these lessons in PDF Book form here.

Part 1 – Creating a Plugin

2

Creating plugins or to be more specific – a “Plugin Command” is really easy in Xsi. All you need to do is go to your Plugin Manager and choose to Create a new plugin for you and it sets it all up and even opens your new plugin in the script editor for you.

So, click File >> Plug-in Manager. In the plugin Manager click the “File” button. Choose “New” and then “Command”.

Xsi will now ask us to set some options for the plugin. The first but is the Command Name. This is what we will call when running the plugin. E.g for Xsi’s command: Application.DeselectAll(), the “DeselectAll” is the Command Name.

For this exercise I’m going to call the plugin “LogSelection” and what I will make this plugin do is to log (Xsi’s version of print)  the names of all the objects I have selected in my scene.

Then when I hit enter the “Plug-in Name” also updates.

Make sure the “Coding Language” is set to Python.

For now I’m going to leave the “Output Directory” as is but if I wanted to save this plugin to an Xsi Workgroup all I’d have to do is change the path from:

C:\Users\firstname.lastname\Autodesk\Softimage_Subscription_Advantage_Pack_SP1\Application\Plugins

to

\\server\workgroups_folder\workgroup\Application\Plugins

And lastly I click “Generate Code”.

Now the Script Editor pops up with my brand spanking new plugin. Any code that I want the plugin to run I just put under the “LogSelection_Execute(  )” function. This function is what is run when we call “Application.LogSelection()”

So now I can start coding away:

for obj in Application.Selection:
    Application.LogMessage(obj.FullName)

so the Execute part of my plugin looks like this:

Now all we need to do is test it.

For this I’m going to close and re-open my Script Editor to get the bottom bit (The Output Section) as that is where the obj.FullName is getting logged to.

In a new tab of the Script Editor, type and run:

Application.LogSelection()

to run your command. Just make sure you have some objects selected or it won’t log anything.

So, we’ve made a plugin and it’s working but I don’t like that it’s just logging the names without giving us more info. If we had just run a few other commands that log data we wouldn’t know which command the object names came from and might confuse them. So for this I’m going to re-open my plugin and change the line:

Application.LogMessage(obj.FullName)

to

Application.LogMessage("LogSelection: " + obj.FullName)

All we need to do now is save the plugin and Xsi will automatically reload it for us. So this time when we run Application.LogSelection() we’ll get something like:

# INFO : LogSelection: Camera_Root
# INFO : LogSelection: light
# INFO : LogSelection: sphere

Part 4 – Successfully using the help files

2

In Xsi you get two main help files or “Guides”. If you click on the help menu in or press F1 in Xsi the “User’s Guide” will open. This can be very useful but not for these tutorials. The one we want is called the “SDK Guide” and is just under the User’s Guide in the help menu. The other way you can access the SDK Guide is by pressing F1 with the Xsi Script Editor as your active window (you can make it active by clicking on it).

In the SDK Guide you will see four tabs:

Out of the four tabs I only really ever use “Index” and occasionally “Contents”. The Contents tab is packed with tutorials and is great to use for refference and to learn a new section of Xsi. I reccomend at least taking a brief look through Contents just to see all the possibilities there are and if you have enough time I reccomend you go through the whole thing, Starting with “Script Development”, then moving to “Plug-in Development” and after that you’ll know enough to be decide what you want to do next.

The Search tab I don’t use because the Index tab is just a LOT quicker and easier to find what I’m looking for.

In a previous tutorial we used Application.ActiveSceneRoot.FindChild to find an object under the “Scene_Root”. If I type in “FindChild” into the search box under the Index tab I get quite a few options.

From here I choose “FindChild, X3DObject” but when I double click it to show the page I get a popup asking me if I want the C++ or SDK version. While using Python, VBScript or JavaScript we will always choose SDK. Then I click Display and the SDK Guide shows the FindChild Function along with the possible arguments (inputs).

So say I have 10 cubes in my scene, each one parented under another object and I don’t know any of their names. All I know is that there only one cube directly under the Scene Root and that is the one I want to get. According to the SDK Guide I can set the “Recursive” argument to False. If set to False Xsi says the FindChild function will only look directly under the Scene Root for my Object and not under any of the Scene Root’s children.

Now to only get cubes I can specify a Type. In the section that says Type, for its description there is a bit of blue text “siType” with a line underneath. Juat like web links clicking on these will take you to a different page. To find the correct argument for a cube, click the siType link.

For now we only need to use the right side of the page is displayed.

So now that we have all the arguments we need we’re ready to go:
As we can see the FindChild can take up to four arguments: “X3DObject.FindChild( [Name], [Type], [Family], [Recursive] )”
for [Name] we will use “*” – to find all names since we don’t know what the name could be.
[Type] = “cube”
[Family] doesn’t really matter for this case
and finally [Recursive] needs to be set to False.
Making our command look like:
cube_obj = Application.ActiveSceneRoot.FindChild("*", "cube", "", False)

Note that for [Family] we used “”. The “” just tells Xsi to use the default value.

Also when setting arguments, you have to set them in the correct order.
Running: cube_obj = Application.ActiveSceneRoot.FindChild("*", "cube", False)
would not have the same effect. Xsi will assume that you are setting the [Family] to False as [Family] is the option for the third argument. This is why even though we don’t want to change or set the [Family] argument, we still need to put something in there to be able to set the fourth argument correctly.

The help file may be a bit overwhelming now but most are at first and as time goes on you’ll get more comfortable with it. With this help file and google you’ll be able to acheive many marvelous things 😉

Part 3 – Finding parameters and their values with code

2

In some cases it can be easier and faster to find an object’s parameters and their values via code as opposed to having to look through the SDK Explorer (though it is very likely you will often use a combination of both).

As we already know, to gain access to a object we can do this:

sphere_obj = Application.Dictionary.GetObject("sphere", False)

From here we can either look for the parameters in the SDK Explorer or we can “loop” through them with code:

for param in sphere_obj.Parameters:
     print param.FullName

This will print the full path (FullName) to each parameter.

If we wanted the values too we could just print param.Value:

for param in sphere_obj.Parameters:
     print "Parameter:" + param.FullName
     print "Value:" + str(param.Value)

Now we can see exactly how to access each parameter and just to make sure its the right one we can check the value we see in Xsi (eg the Local X Position) compared to the value we see in the Script Editor Output (eg sphere.kine.local.posx)

The parameter’s path is made up of a combination of Objects followed by Properties and the finally the parameter’s ScriptName.

Image

In this case “sphere” is an object and “kine” and “local” are Properties.

An Object holds a collection of Properties and a Property holds a collection of Parameters.

You can loop through Properties just as you looped through Parameters with:

for prop in sphere_obj.Properties:
     print "Property:" + prop.FullName

Now that we know the Properties we can even loop through the Parameters of a specific Property:

for param in sphere_obj.Properties("visibility").Parameters:
     print "Parameter:" + param.ScriptName

From this we can narrow it down even further to:

print sphere_obj.Properties("visibility").Parameters("viewplaybackvis").Value

If there are other objects parented under the sohere and we only want to get those we can use:

for obj in sphere_obj.Children:
     print obj.FullName

which can be turned into (assuming you have an object named cone parented under your sphere_obj):

for prop in sphere_obj.Children("cone").Properties:
     print "Property:" + prop.FullName

And lastly we can call sphere_obj.NestedObjects. This returns any of the above mentioned things that are directly under the sphere_obj. I tend to use this as more of a last resort when calling Children, Properties or Parameters won’t work.

That said its about dinner time so I’m off home 😀

Part 1 – Finding Parameters (Introduction to the “Object Model”)

2

In Xsi, with scripting we have 4 different ways of getting the value of a parameter.

Say I have a sphere and I want find its X position. I can do any of the following:

print Application.GetValue("sphere.kine.global.posx")
print Application.Dictionary.GetObject("sphere.kine.local.posx").Value
print Application.ActiveSceneRoot.FindChild("sphere").Kinematics.Global.PosX.Value

You did ready correctly, I did say there are 4 ways though I’ve only shown 3. The fourth way is by using the FindObjects method. The reason I’ve left it out is it is a bit more complex to use than the others and in most cases you can get by by using one of the mentioned 3. But when you’re more comfortable coding in Xsi look it up in the SDK Guide.

The first method is by far the easiest. All you have to do to find what to put inbetween the brackets of the Application.GetValue().We can do this by changing the paramater we want in the viewport, seeing what the Script Editor Output says and changing it slightly. E.g: When I move my sphere along the X axis the Script Editor Outputs:

Application.SetValue("sphere.kine.global.posx", 3.435, "")

Now if I want to print the X Position of the sphere all I need to do is change the “SetValue” to “GetValue” and take out anything other than the sphere’s path:

Application.GetValue("sphere.kine.global.posx")

The first method is great for its ease but if I wanted to set the values of a few parameters on the sphere it would be quicker and easier to read in a script if we went with method 2 or 3. The reason for this is we can “get” the sphere and store it in a variable so we can access it whenever we want:

my_sphere = Application.Dictionary.GetObject("sphere")
or
my_sphere = Application.ActiveSceneRoot.FindChild("sphere")

The difference between method 2 and method 3 is that method 2 goes straight to the sphere object in memory and returns it. This method is by far the fastest of the three, Method 3 is the slowest because xsi does a search for an object named “sphere”. It searches under the Scene_Root, looking at the name of every object untill it finds one called “sphere”. For now we will go with the speedy method 2 but method 3 will come in quite handy later on.

So, back to the code. We now have the sphere object stored in the variable called “my_sphere”. This means we can set whatever parameter we wish quite easily. For example

Set sphere’s X position to 100:
my_sphere.Kinematics.Global.PosX.Value = 100

Set sphere’s Y Rotation to 20:
my_sphere.Kinematics.Global.RotY.Value = 20

Get the spheres Z Scale, devide it by two and store it in a variable called “half_scale” and finally set the sphere’s scale Z to out half_scale_z value:
scale_z = my_sphere.Kinematics.Global.SclZ.Value
half_scale_z = scale_z/2
my_sphere.Kinematics.Global.SclZ.Value = half_scale_z

Note: If you use Application.Dictionary.GetObject in your scene and the object you’re looking for doesn’t exist (or it you’re not sure) add a comma followed by False before your closing bracket. This tells Xsi NOT to throw an error if it can’t find the object. eg: If I want to try get an object named “cube” in my scene but I’m not sure if it exists in my scene or not I rune

my_cube = Application.Dictionary.GetObject(“cube”, False)    # This won’t throw an error if the object named “cube” doesn’t exist.

So I always write my Application.Dictionary.GetObject with a False at the end just incase 😉

Part 2 – Applying a command to multiple objects

2

We start off in pretty much the same manner as Part 1 (Easily turn echoed commands into buttons.) by opening the script editor (Alt+4) and clearing its previous output.

In this example I have a few cubes in my scene that I want to be able to hide and show with the click of a button. This is really easy to do 😉

I haven’t changed the names of the cubes, they are called “cube1”, “cube2” etc.

So now same as in Part 1 I manually do what I want and then copy the echoed commands.

So, first I select one cube. Then I press the “h” key to toggle its visibility.

The script editor echoes the commands:

Application.SelectObj("cube1", "", True)
Application.ToggleVisibility("", "", "")

This is great but if I were to put this into a button it would only toggle the visibility of “cube1”, I want to be able to do All the objects who’s names start with “cube”.

This is done with this little guy: * (an asterix or wildcard). This guy basically tells Xsi to look for anything who’s name starts with “cube”, regardless of what it ends with.

So when I run the commands

Application.SelectObj("cube*", "", True)
Application.ToggleVisibility("", "", "")

All the cubes in the scene are hidden, and when i run it again they are unhidden. When you want to edit a command, copy it from the bottom half of the script editor (“output”) to the top half (“editor”). In here you can change the commands as you please and test them too by pressing F5 or clicking the run button.

When you are happy with your code, select it and drag it onto a toolbar (you can turn code in from both the output or the editor section of the script editor, though in this case we are dragging from the editor section).

This asterix trick can be applied to many Xsi commands, here are a few more examples that would work:

To assign a material to all the cubes, after assigning manually the command in the script editor output is:

Application.AssignMaterial("Sources.Materials.DefaultLib.MyMaterial,cube1", "siLetLocalMaterialsOverlap")

so I change it to:

Application.AssignMaterial("Sources.Materials.DefaultLib.MyMaterial,cube*", "siLetLocalMaterialsOverlap")

If I want to turn off the render visibility for all the cubes, manually I get:

Application.SetValue("cube1.visibility.rendvis", False, "")

which I change to:

Application.SetValue("cube*.visibility.rendvis", False, "")



and so on 🙂

Part 1 – Easily turn echoed commands into buttons.

2

Firstly you need to have your script editor open (Alt+4) or use the icon Image.

For this tutorial we’re only going to be interested in the bottom half of the script editor (the “output”). This is the section of the script editor that shows the basic commands resulting from you clicking and editing things in Xsi.

Its often cluttered with all the commands that have been run so right-click on it and from the popup menu choose “Clear All”. This will make it easier for us to see exactly what code needs to go into our button.

In my case I want to freeze the modeling on all of the objects in my scene. So, I select all the objects in my scene (with Ctrl+A) and then using the Freeze M button  Image

The script editor echoes the commands:

Application.SelectAllUsingFilter("object", "siCheckComponentVisibility", "", "")
Application.FreezeModeling("", "", "")

This is what I need to add to my button. But I need a “Toolbar” to add the button to first.

You can either add a button to an existing toolbar or you can make a new toolbar (View > New Custom Toolbar).

Then all I need to do is to select the commands from and drag them onto the toolbar.

Image

Once you let go Xsi will ask you which type of button you wish to create, leave “Script Button” checked and press OK. This brings up the button’s settings. You’ll notice your code in the top “Script Commands” section. Give it a name (something descriptive, its not much fun having a toolbar filled with buttons called button1, button2, button3 etc). I also reccomending giving the button a tooltip (description of what the does).

And thats it! You’ve just made your very own custom button 🙂

Before you close Xsi and start bragging to your friends about the awesome button you’ve just made, you might want to save the toolbar so you can use the button next time you open Xsi. To do this just right-click the toolbar and choose save. Give your toolbar a name and after you’ve clicked OK a file browser will open asking you where you want to save your toolbar. Don’t change anything, just press OK again and your toolbar will be saved to your personal Xsi folder filled with all your prefferences and other things.