Articles by " LoneRobot"

HitchHiker Update v4.4

Oct 9, 2010 by     29 Comments    Posted under: 3dsMax, DotNet, User Controls


I’ve been so swamped with work this last year, my planned update to Hitchhiker had to be stalled. It’s a shame really, as I have had a working version of the updated assembly for a while but no time to update the help files to show how to use it. However I’ve been pleased with the progress made in it’s place – I’ve been able to write RigStudio, Digit and Character Silo which I’m really proud of. Hopefully I will get a bit of breathing space to allow me to concentrate on next generation 3dsMax UI stuff, namely learning WPF.

There are a few updates – mainly from great feedback I’ve had from the community. I am glad people are using HitchHiker in any way to augment their Asset Browsing scripts. With the new additions that I’ve made, I am hoping this will be even better.

Please let me know if you like Hitchhiker and use it for anything useful. You feedback is critical as my time tends to be limited. So if i feel people are using the control I can spend my time improving it. I’d love to spend all my time refining this control but there are so many other project that I have to work on! But feedback on any level will always motivate me to fix and improve!

Recent Updates/Fixes –

v4.4 – 19th January 2011

Added the .buttonborder <boolean> property. If you set this to false, Hitchhiker will not render the black border around each control. If used with the .gap <integer> property set to 0, Hitchhiker will render like a seamless section of tiles.


Instantiating HitchHiker

I had to have a re-organisation of my namespaces as they were getting confusing. Since HitchHiker isn’t really anything to do with characters, i decided to change the default namespace to lonerobot.ui.controls. If you have any scripts that were written with the previous release of this assembly, you can just do a search and replace of ‘character’ for ‘controls’

make sure that you call dotnet.loadassembly <hitchhiker dll location> in your script before using.

if using on a dotnetform or maxform – dotNetobject “lonerobot.ui.controls.hitchhiker”

if using on a maxrollout – dotNetcontrol “lonerobot.ui.controls.hitchhiker” width:<int> height:<int>

please refer to the hitchhiker tab at the top of this site for more detailed help, all these are still valid

Additions to Version 4.4 of HitchHiker

Max file support –

Hitchiker will now support the searching of the Maxfile type. Not only this, you can render an associated thumbnail directly from the assembly to be displayed with the file when previewing it in HitchHiker.

Additional populate methods –

Hitchhiker was always designed to operate on a folder level, whatever was inside with the designated filetype was displayed. Now you have two options.

populate (by directory string)

populate (by file array)

This means you can now pass an array of filepath strings to be displayed in the hitchhiker window.

This can also be utilised with the enhanced search parameters –  PopulateFilterSearch

Hitchhiker will now allow you to display files that start with, end with or contain certain characters. So if you are doing a recursive search population of many folders, you can tell it to only display those with a particular character’s name for example.

Other options is that you could prefix or suffix a filename “Approved” or “Unapproved” and allow the showing of approved files only.

Fast Cache Display Mode

Hitchhiker is reasonably fast in realtime mode, but (like most asset browsers) can slow down when loading multiple hi-resolution images inside folders. Hitchhiker has a display state that  can be set to cache – meaning the thumbnails are stored locally on the user’s machine, meaning that the slowdown only exists the first time the populate method is called. Subsequent calls result in the control being populated very fast!

hh.cache =  (dotnetclass “lonerobot.ui.controls.hitchhiker+cachestate”).cache

Store Favourites of your commonly used directories

Hitchhiker can now add locations that you use to populate from to save specifying the folder each time

Fully integrated toolbar

Hitchhiker can be run without the toolbar and it’s behaviour controlled entirely by script, but setting the toolbar to true allows you to do everything from the menu system, set thumbnail sizes, search parameters etc, meaning it really is a pretty comprehensive asset browser straight out of the box.

A few caveats I have noticed about this release –

Occasionally the keyboard focus can be stolen by HitchHiker if you close the dialog. Make sure you call the housekeeping function in your close handler, as this will make sure max gets it’s shortcuts back.

Feel free to download at the link below. If you find any issues with using this version of Hitchhiker, please let me know and I’ll do my best to fix it. I would ordinarily like to test a release more than this one has been – But didn’t want to delay the release this to the community any longer. I hope it helps you make great utilities with minimum effort.


Flexible Animation System for Fingers and Hands

Oct 8, 2010 by     No Comments    Posted under: 3dsMax, Characters, DotNet, User Controls


For many years as a character animator I have wanted a system to aid with the animation of fingers. It’s one of the things that tend to be done as an afterthought when pushed for time on a production, but there is no doubting that some of the nicest animation will always have really great hand gestures. The balance is trying to find the balance between time and ease of animation. If you are really pushed for time, it would be far better that you could store hand poses that you use most of the time, with a view to having a robust toolset to allow you to refine them afterwards.

I recently wrote a system called Digit that goes some way towards addressing this issue in production. The key to this system working well was to provide a UI that was intuitive to the way people currently work in max, and making it minimal and simple enough that it didn’t need too much understanding. This article will hopefully explain the process that I undertook in planning and executing this system.

Planning the control layout


I usually start with some sketches – i have a technical journal that I write ideas and loops into. This over the years (and much to my chagrin) has replaced my sketchbook but it does give me a kind of technical reference for everything. I will scribble UI ideas down before I code anything, as it helps me to plan in advance potential layout conflicts. It is by no means final but it gets me thinking about how everything is going to interact. The thing to remember is that it’s not something you’ll proudly display, but it helps to organise your mind and avoid any UI layout problems along the line. UI design is a hard thing to do, generally people will tell you when it is wrong in a heartbeat and not even notice if it is right. It’s one of those thankless tasks that only you can appreciate.

With Digit I felt I could deviate from the look of the max UI – firstly, square controls were simply not going to cut it, and I wanted to allow control to adjust the layout when running in either a portrait or landscape mode.  The FlowLayoutPanel is built for this task and I’ve used it extensively for my controls up to now. The layout logic was pretty simple, I didn’t want to separate the controls too much, what it gave me was two main panels – the selection interface, and the slider controls.

The critical thing for me in terms of the functionality of the system was that it was as intuitive as possible, and mimicked a lot of the same methods as the native max UI. This was mainly the use of CTRL and ALT to add and remove from selection, and the double-click hierarchy selection. My other consideration was to try to keep the dialog as minimal as possible. I had setup finger controls in the past and found, due to the nature of wanting them to be able to control individual fingers, that they can become large slider interfaces. I thought that this time i would be able to use less and still have the same level of control. Here is what I came up with in the end, they are the same UserControl, they have a hand property, Left and Right which decides what UI colour they get.

Colour profiles

Selection based curl slider

I did this by having a two stage approach, working on a specific selection or on the entire hand. If no finger element was selected, the curl slider affected the entire hand. If a particular finger had been selected, then the curl would only operate on that finger. The same went for resetting the finger position. This worked well, you could quickly set up different poses based on others.

Splay and Thumb position and rotation were different. You don’t want to splay individual fingers, it looks odd so this acts on the entire finger rig. And individual thumb position and rotation are also necessary. However the thumb curl operates on the global curl slider.

The +Thumb button was something that came from the evolution of the control and testing it on some real characters. Sometimes, you didn’t want to move the thumb but still move the fingers. This checkbutton allows you to affect the thumb curl and splay with the other fingers – as before, it is based on the selection, so you have to have no part selected for this to work.


Its all put in place with a bit of simple matrix rotation. You can prerotate a matrix according to an angle, so each time the slider moves, it is calling a function that supplies the current transform and returns a new transform matrix that is prerotated by the angle from the slider.

Medial,Distal and Proximal Selectors

The three selectors to the left of the fingers are to select across the first, second and third bones. I thought this gives an extra control if the automatic blended rotation of the fingers isn’t quite enough to get the hand pose you are after.

Pose Storage and Mirroring Transforms

I have been using XML for a while now to store any sort of pose when I use a reference transform monitor to store a node. Most of my facial animation systems and rig setups use these. Once the directory is specified, you can store the local transform of each node and that’s all you need. I use an XMLLayoutPanel to handle the files. Its a dotnet user control I released a while ago that handles all the layout and even lets you specify a custom thumbnail. Check my previous blog post if you want to have a go at using it.

When you apply it back on the hand later, you multiply the current finger’s parent transform with the XML preset’s local transform and you have applied your stored preset. Because you extract the local transform, the pose is the same, even when applied to a different hand position as you are making a new transform matrix from the current parent’s position. When you want to mirror the transform to the other hand, that is a little more involved.

You start by reading the local transform of the finger nodes. Then, you Mirror the transform matrices of all bones, by creating a mirrored transform around a common parent (like the character’s root). However the other arm is not necessarily in the same position. So, you need to create a mirrored transform of the hand too. Once you have this, you can get the mirrored bones local transform matrix. This becomes the one you use, as you can then multiply this mirrored local transform onto the current location of the parent (i.e. the opposite hand) With this you can paste a hand pose from one arm to the other, regardless of the arm position. I was grateful for all of the brilliant examples on the CGTalk board to help with this, specifically from Paul Neale.


It is possible to set up a character with this complete hand animation system without any Maxscript. This works on Bipeds, CATrigs, Puppetshop rigs and custom bone rigs, so hopefully it will be useful for many projects to come.

Loving LINQ is easy because it’s beautiful

Oct 7, 2010 by     6 Comments    Posted under: 3dsMax, Characters, DotNet, Technical Research, User Controls

One thing is certain, XML is prolific. I wanted to research the most efficient way of using this versatile language in future systems I develop for 3dsmax animation pipelines.

One of my latest research projects is looking at various options for storing information about characters in a project. There are many different types of data that is useful to be able to pull up, from node information to walk cycle data. What i haven’t had before is a unified method for storage and retrieval. I have been using XML in my character tools for some years quite successfully, from Lipsync storage to Walk Cycles.

I’m sure most studios out there are using some form of database, whether it be for asset tracking etc, and I’m sure that this is a perfect solution. However for this problem, after looking at SQL server configurations and methods I found a different approach that could span my need for database-like data handling and the transparency of storing to XML.

XML Verbosity

I’ll hold my hat up, part of this might be because I went to art school and didn’t pay enough attention in Maths, but there was something distinctly hit and miss about using XML within a dotnet assembly. The Document Object Model (DOM) felt quite cumbersome and wasn’t like the elegant OOP approach I was looking for. What was a transparent user experience with intellisense in visual studio, using XML on an object level became a clunky affair. With my last post about RigStudio, my dynamic character selection framework, I integrated a custom XML serlializer to take the guesswork out of the XML parsing and creation.

The Microsoft Language Integrated Query framework (or LINQ) is one of the more recent introductions to the dotnet framework and allows XML data to finally be treated like data. You can now perform queries and operations on the XML tree in a proper object orientated approach. If you go the whole hog, you can also build an XML schema from an existing XML template and have intellisense support for the XML document. Most importantly, the Linq XML classes are enumerable classes, meaning you can iterate then easily, meaning you can extract, merge and join portions of the whole document tree into other branches and documents.

Also available to the VB programmer are XML Literals. Basically, this means you can begin typing a variable directly into an xml tree – so your code actually resembles an XML document and allows you to integrate variables into the tree dynamically, so you can loop object collections to build complex XML documents completely via code.


As you can see, you can format it exactly like an XML document directly from the variable declaration. To add a variable into the document, you can use :

<%= your variable here %>

This allows one to pass another XElement at this point to nest more complex trees. This is certainly far simpler to set up than a custom serliazation class.

Where LINQ fits in with 3dsMax

In terms of max, you can’t really perform the query commands that are the really useful part of LINQ (Well not to my initial research). The main class you will want to use with LINQ to XML is the XElement. In raw dotnetclass form within 3dsmax, you are using it in a similar way to how XML was previously treated – i.e. the DOM model. However, providing a class library that utilises the LINQ query methods could be worthwhile. Visual Studio is a mature development environment, and you are adding something to max. In terms of the deployment, I have no problem adding a dll to the max startup. I met with the 3dsMax design team a while back through work and they assured me dotnet is going to be with max for a long time to come.

Where the XElement class is useful, is that it can encompass many different XML files, or a single branch within a particular file. If you had a selection of XML documents that stored the scene nodes of a different scenes,You could use a LINQ query to get the filenames where a specific object resided. But my purposes, whilst similar was to get this working within a character pipeline.

My idea was to create a type of XML Database that I called Silo. This would be setup in Max using managedservices.MaxsciptSDK functions to pass object names into the assembly that could then be written to XML. It could also integrate RigStudio into the same file. What this means is there is a front end that can quickly store node data about a character rig which can then be queried, giving access potentially to any data applicable to the characters within a particular project, whether this would entail node data, mirroring information, Lipsync, Walk Cycle footstep length – the possibilities are endless.

Most of the time, animators want to be able to control visibility of characters at various points, some times you want to see the controls for speed, sometimes the mesh for previews. Having different layers for each of these types is fine, but when you have a lot of characters, it can mean navigating the layer manager is more involved. Wouldn’t it be great to just store these relationships in a datasource and keep the entire character on one layer? In fact, you could have ALL characters on a single layer if you wanted, the database could then handle all node interaction.

The front end on my prototype looks like this, I’m still trying to work out the best layout at the moment, as it feels a little thrown on to me. However it’s enough to quickly setup a multiple character database that can be automatically bound to my Rigselector control. Each tab allows me to store selected elements of the rig into the various sections.


Here’s a useful class that you can use within a dotnet assembly – I needed a way of getting the selected object names into the dotnet assembly in order to save them to XML

Public Class MaxOps
    Public Function GetCurrentSelection(ByVal SingleNode As Boolean) As List(Of String)
        Dim NodeList As New List(Of String)
        Dim Selectioncount As Integer = ManagedServices.MaxscriptSDK.ExecuteIntMaxscriptQuery("Selection.count")
        If SingleNode Then
            If Selectioncount = 1 Then
                Return NodeList
                Return Nothing
            End If
        ElseIf Selectioncount > 0 Then
            For i As Integer = 1 To Selectioncount
                NodeList.Add(ManagedServices.MaxscriptSDK.ExecuteStringMaxscriptQuery("Selection[" & i.ToString & "].name"))
            Return NodeList
            Return Nothing
        End If
    End Function
End Class

The final tab updates RigStudio for Silo compatibility. You can now build a rig selector directly from silo, or import a previous version.

One option with Silo is you can specify a species for the character, so that you can control visibility of different types of characters. For example you can use LINQ to combine types of queries. A literal translation would be to ask –

“Unhide all animation control nodes that reside in the animal species”

With LINQ, this command would look a bit like this –


You can see the use of XML style parentheses in the query. These are known as axis constraints that return the xml nodes of ANY character with the same branch name. This means you are using the XML nodes like objects.

Another thing to remember, is that within max a system.array with be cast into a max array type. So if you are using dotnet lists and specialized.collections within the assembly, that is fine, but in order to avoid extra code in maxscript it’s best to make sure the function has the appropriate return type.

Hooking up the XML Database


This is a breakdown of the SiloDatabase class – This uses LINQ to consolidate an XML file into a queryable dotnetobject in 3dsMax. As you can see, there are many methods, all of which can be hardwired into other assemblies, as you would only usually be running a single instance of this class. This means I can bind other assemblies to use the database without any maxscript interaction. This is always my goal, maximum flexibility with minimal deployment. The deployment for this whole database pipeline within a project? a couple of lines in max startup. It grows with the project and all the selection logic is built into the controls, not the deployment code, so can evolve and improve as the project goes on. The core of the database object isn’t really a database of course, its a collection of XML files. But when max instantiates the Silo Database dotnetobject, it appears and acts like one because of the LINQ query methods.

Getting the Associated Icon for a filetype in 3dsMax

Aug 18, 2010 by     1 Comment     Posted under: DotNet

Another snippet, just translated into a maxcript-friendly format.

If you need to get the file icon that is associated with a particular type, you can’t get this ordinarily from within a managed environment. There are some great examples on how to use the windows API so these can be added into maxscript by converting them into a string and sending them to the VB/C# compiler from 3dsMax. As always, thanks go to all the great information on the interwebulator, as well as Mike Biddlecombe on CGTalk who figures out all this clever stuff in the first place.

Here is a function that returns a FileIconClass. It has a public method GetIcon(Filename) that returns an image from the file type string specified as the filename argument. It’s useful for treeviews and lists etc.

fn FileTypeIconClass = 
	source = ""
	source += "Imports System.Drawingn"
	source += "Imports Microsoft.VisualBasicn"
	source += "Imports System.Windows.Formsn"
	source += "Public Class FileTypeIconsn"
	source += "Dim cIcons As New System.Collections.Hashtablen"
	source += "Public Declare Auto Function SHGetFileInfo Lib "shell32.dll" (ByVal pszPath As String, ByVal dwFileAttributes As Integer, ByRef psfi As SHFILEINFO, ByVal cbFileInfo As Integer, ByVal uFlags As Integer) As System.IntPtrn"
	source += "Public Const SHGFI_ICON As Integer = &H100n"
	source += "Public Const SHGFI_SMALLICON As Integer = &H1n"
	source += "Structure SHFILEINFOn"
	source += "Public hIcon As System.IntPtrn"
	source += "Public iIcon As Integern"
	source += "Public dwAttributes As Integern"
	source += " Public szDisplayName As Stringn"
	source += " Public szTypeName As Stringn"
	source += "End Structuren"
	source += "Private Function RetrieveShellIcon(ByVal argPath As String) As Imagen"
	source += "Dim mShellFileInfo As SHFILEINFOn"
	source += "Dim mSmallImage As System.IntPtrn"
	source += "Dim mIcon As System.Drawing.Iconn"
	source += "Dim mCompositeImage As  System.Drawing.Imagen"
	source += "mShellFileInfo = New SHFILEINFOn"
	source += "mShellFileInfo.szDisplayName = New String(Strings.Chr(0), 260)n"
	source += "mShellFileInfo.szTypeName = New String(Strings.Chr(0), 80)n"
	source += "mSmallImage = SHGetFileInfo(argPath, 0, mShellFileInfo, System.Runtime.InteropServices.Marshal.SizeOf(mShellFileInfo), SHGFI_ICON Or SHGFI_SMALLICON)n"
	source += "Tryn"
	source += "mIcon = System.Drawing.Icon.FromHandle(mShellFileInfo.hIcon)n"
	source += "mCompositeImage = mIcon.ToBitmapn"
	source +=  "Catch ex As System.Exceptionn"
	source += "mCompositeImage = New Bitmap(16, 16)n"
	source += "End Tryn"
	source += "Return mCompositeImagen"
	source += "End Functionn"
	source += "Public Function GetIcon(ByVal argFilePath As String) As Imagen"
	source += "Dim mFileExtension As String = System.IO.Path.GetExtension(argFilePath)n"
	source += "If cIcons.ContainsKey(mFileExtension) = False Thenn"
	source += "cIcons.Add(mFileExtension, RetrieveShellIcon(argFilePath))n"
	source += "End Ifn"
	source += "Return cIcons(mFileExtension)n"
	source += "End Functionn"
	source += "End Class"

		VBProvider = dotnetobject "Microsoft.VisualBasic.VBCodeProvider"
		compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"
		compilerParams.ReferencedAssemblies.add "C:WindowsMicrosoft.NETFrameworkv2.0.50727System.Drawing.dll"	
		compilerParams.ReferencedAssemblies.add "C:WindowsMicrosoft.NETFrameworkv2.0.50727System.Windows.Forms.dll"	
		compilerParams.GenerateInMemory = on
		compilerResults = VBProvider.CompileAssemblyFromSource compilerParams #(source)
		-- this is very useful to debug your source code and check for referencing errors
		if (compilerResults.Errors.Count > 0 ) then
			errs = stringstream ""
			for i = 0 to (compilerResults.Errors.Count-1) do
				err = compilerResults.Errors.Item[i]
				format "Error:% Line:% Column:% %n" err.ErrorNumber err.Line 											  
													 err.Column err.ErrorText to:errs 
			MessageBox (errs as string) title: "Errors encountered while compiling VB code"
			return undefined
			-- create a dotnetobject from the class 
		return compilerResults.CompiledAssembly.CreateInstance "FileTypeIcons"

Capturing the viewport according to render resolution.

Aug 18, 2010 by     5 Comments    Posted under: DotNet

Another snippet!

For Rig Studio, I was faced with the problem of providing a method to not only render the view to the design surface, but capture it also. I felt that sometimes a full render wouldn’t be neccesary and users would want the option of performing a viewport capture for the UI background. If you have ever used the command


to retrieve a bitmap of the current viewport, you’ll notice that even if you have the safe frames/ livearea turned on, it still returns the whole viewport.

I worked out a function to calculate the correct crop margin to return a viewport bitmap according to the current render resolution.

Fn LR_CaptureRenderAspectViewport  = 
	local ViewCap=undefined			
	local cv = getViewSize()
	local ratio = undefined

           case of 
            (cv.x > cv.y):(ratio = cv.y/cv.x)
            (cv.x = cv.y):(ratio = 1)			
            (cv.x < cv.y):(ratio = cv.x/cv.y)

		VptDib =gw.getViewportDib();
                ViewCap = bitmap renderwidth renderheight color:white
                ViewportRatio = VptDib.width/VptDib.height as float
                RenderRatio = renderwidth/renderheight as float

					case of
					(ViewportRatio <= RenderRatio):(
					CapturetoRenderHeightRatio =VptDib.width/RenderRatio as float
					TopEdge = ((VptDib.Height-CapturetoRenderHeightRatio)/ 2.0) as integer
					FullViewcap = bitmap vptdib.width CapturetoRenderHeightRatio color:white
					pasteBitmap VptDib FullViewcap (box2 0 TopEdge VptDib.width VptDib.height) [0,0]
					Copy FullViewcap ViewCap)
					(ViewportRatio > RenderRatio):(
					CapturetoRenderHeightRatio =VptDib.height*RenderRatio as float
					LeftEdge = ((VptDib.width-CapturetoRenderHeightRatio)/ 2.0) as integer
					FullViewcap = bitmap CapturetoRenderHeightRatio VptDib.height color:white
					pasteBitmap VptDib FullViewcap (box2 LeftEdge 0 VptDib.width VptDib.height) [0,0]
					Copy FullViewcap ViewCap)
                close VptDib

                if viewcap != undefined then (setclipboardbitmap viewcap;close ViewCap;return true)else(return false)

	tempbmp = LR_CaptureRenderAspectViewport()
	display (getclipboardbitmap())

I hope this is useful.