Call a powershell script from maxscript

Only recently I have discovered Powershell, and I must say it is kind of addicting. You can do ANYTHING with it in a simple way. The syntax might seem weird in the beginning, but soon you learn all the basics.
If you are curious about it and want to start learning, I recommend you to look up the beginners tutorials by SAPIEN Technology in their youtube channel.

I wanted to do a maxscript code that captures the view in the viewport selected by the user, and then saved them in 2 formats:

  • bmp (200px wide)
  • jpeg (full size)

This can be easily done in maxscript using gw.getViewportDib(). However, I wanted to watermark the .jpeg image with the name of the originating .max file.

The most straightforward solution in this case is to call dotnet objects. But as I said, powershell is so addictive that I wanted to give it a try in this case. Searching the internet on how to add texts to images, I came across this wonderful piece of code. Also dotnet funcions by the way.


I adapted this code to my own purpose:

 Function AddTextToImage {
[Parameter(Mandatory=$true)][String] $sourcePath,
[Parameter(Mandatory=$true)][String] $destPath

$Title = Get-Item -Path $sourcePath
$Title = $Title.BaseName + ".max"
Write-Host "The title is " $Title

Write-Verbose "Load System.Drawing"
[Reflection.Assembly]::LoadWithPartialName("System.Drawing") | Out-Null

Write-Verbose "Get the image from $sourcePath"
$srcImg = [System.Drawing.Image]::FromFile($sourcePath)

Write-Verbose "Create a bitmap as $destPath"
$bmpFile = new-object System.Drawing.Bitmap([int]($srcImg.width)),([int]($srcImg.height))

Write-Verbose "Intialize Graphics"
$Image = [System.Drawing.Graphics]::FromImage($bmpFile)
$Image.SmoothingMode = "AntiAlias"
$Rectangle = New-Object Drawing.Rectangle 0, 0, $srcImg.Width, $srcImg.Height
$Image.DrawImage($srcImg, $Rectangle, 0, 0, $srcImg.Width, $srcImg.Height, ([Drawing.GraphicsUnit]::Pixel))

Write-Verbose "Draw title: $Title"
$Font = new-object System.Drawing.Font("Verdana", 32)
$Brush = New-Object Drawing.SolidBrush ([System.Drawing.Color]::FromArgb(255, 255, 255,255))
$Image.DrawString($Title, $Font, $Brush, 740, 800)

Write-Verbose "Save and close the files"
$$sourcePath, [System.Drawing.Imaging.ImageFormat]::Bmp)

AddTextToImage $args[0] $args[1]

The key line here is this:

AddTextToImage $args[0] $args[1]

Here we are telling the powershell function that we are expecting external arguments (array $args), which we will pass through the command line.

Notice that the argument array, like in most languages, starts with 0, so our arguments are $args[0] and $args[1]


I spent some time researching this; there are plenty of pages out there that explains how to do this, and unfortunately I forgot to write them down, so I cannot reference them. But in this post all is explained.

The structure is as follows:

-File pathtoyourpowershellscript\yourpowershellscript.ps1 argument1 argument2

“-File” tells powershell that you want to execute a powershell script

Arguments: you specify them one after the other. Note that the path to the script does not use quotes, despite being a string. The paths to the images though, use \” (backslash – quote). The backslash prevents maxscript from causing errors for strings closed too early, it tells maxscript to read the quotes as any other character.


Back to 3ds max scripting, the way to launch a powershell script is with the command ShellLaunch (search for Executing External Commands in the maxscript documentation)
ShellLaunch takes the name of the app (.exe file) to be executed, and the parameters to pass to that app.

In my case:

fn callPowershellScript imgPath=
app = "powershell.exe"
cmd = "-File pathtoyourpowershellscript\yourpowershellscript.ps1  \"" + imgPath + "\" \"" + imgPath + "\""
ShellLaunch app cmd

It took me some time to make this work. At first I used DosCommand, but for some reason the script wouldn’t execute.
Besides, the command line window closed so fast, I wasn’t able to read why the script failed.
Stack Overflow came once again to the rescue and I found in this post that you need to add the parameter -noexit to the command, so that powershell waits for you to close the command line window and you can read all the output.
So, if you want powershell not to close the command line window before you can read the errors, this is what you write:

cmd = "-noexit -File pathtoyourpowershellscript\yourpowershellscript.ps1  \"" + imgPath + "\" \"" + imgPath + "\""

Since I wanted to overwrite the original image with the watermarked image, I passed the imgPath twice. There are probably more elegant ways to do this but hey, the script does the job I want.

I hope this can be useful to someone!


VBA – Generating unique keys for TreeView module

Today I came across a problem while creating a hierarchy tree for 3D models in Microsoft Access.

My hierarchy tree system looks like this:

*A (parent node)












My problem was that the node keys for the Dot.Net TreeView module tend to repeat, for example when reaching A11 in the first level of hierarchy (A11)

There are probably more elegant solutions out there, but mine was to generate an unique key for the first generation of the tree (first branch). From A to Z, and when we run out of letters, start with AA-ZZ and then from AAA-ZZZ. This should, in theory (still to be tested) do for extensive hierarchy trees.

Hereunder the code. If somebody stumbles across this code and has any suggestion, it will be appreciated

Option Compare Database
Option Explicit

Private basicLetterCount As Integer
Private timesLooped As Integer
Private keyDict As New Scripting.Dictionary
Private alphabet As New Collection
Private existingKeys As New Scripting.Dictionary

' ------------------------------------
' ------------------------------------

Public Sub initializeKeyGeneratorSystem()

Call populateAlphabet

basicLetterCount = 1
timesLooped = 0

End Sub

Public Function generateKey(i As Integer)

Dim currentLetter As String

currentLetter = alphabet.Item(basicLetterCount)
existingKeys.Add generateNewKey(currentLetter, timesLooped), i

If (basicLetterCount >= 26) Then
basicLetterCount = 1
timesLooped = timesLooped + 1
basicLetterCount = basicLetterCount + 1

End If

generateKey = GetKey(existingKeys, i)

End Function

' ------------------------------------
' ------------------------------------
Private Sub populateAlphabet()

Dim str As String
Dim i As Integer


For i = 1 To Len(str)
alphabet.Add (mID(str, i, 1))
Next i

End Sub

Private Function generateNewKey(letter As String, nrRepeat As Integer) As String
Dim result As String
Dim i As Integer

result = letter
For i = 1 To nrRepeat
result = result + letter
Next i

generateNewKey = result

End Function

Private Function GetKey(Dic As Dictionary, strItem As Integer) As String
Dim key As Variant
For Each key In Dic.Keys
If Dic.Item(key) = strItem Then
GetKey = CStr(key)
Exit Function
End If
End Function

Usage in the main function:


Private Function myFunctionName()

Dim externalCount As Integer
Dim i As Integer

externalCount = 100
'Initialize the key generator system
Call initializeKeyGeneratorSystem
'You need to pass an external count to the keygenerator
For i = 1 To externalCount
Debug.Print (generateKey(i))
Next i
End Sub

3ds Max and FlightStudio: getting around with the Flight Studio Hierarchy menu

I have been developing some maxscript scripts in order to automatize the process of exporting models to .flt format. The purpose was to programmatically create object/xref dummy nodes from maxscript. However, the Open Flight functions are barely accessible and documented in the 3ds Max help. Which is a pity. According to the documentation, you can create a flt object in the hierarchy window with maxscript, using this function of the Flight Studio interface:


But, how do you access the properties of this newly created node? Change its name? Define which file it refers to, in the case of xref flight nodes? I got this workaround: create the flt object/xref node, and immediately after, look for any dummies in the scene which begins with x* (in the case of xref flt nodes) or o* (in the case of object nodes). After you have found it, you can access its properties just as with any max object.

local allobjs = $*


for o in allobjs do 
if (classOf o == Dummy) then 
if (matchPattern pattern:"x*" ignoreCase:false) then (

--put the xref path
fltStudio.PutExternalRefFilename o (fileextToFLT fPath)

--rename = fName

-- align it to the parent object PIVOT (not center)
o.rotation = rot o.position = pos o.boxsize = [0.5, 0.5, 0.5]

-- put in object's layer 
If (objLayer == undefined) then objLayer = "0"
local target = LayerManager.getLayerFromName 
objLayer target.addNode o 
append createdDummies o 

On light and space – [d]espacio series (2011)

Video 13′ 46”

Music by Ángel Arranz

De la luz y del espacio is the fourth and last piece of the series entitled [d]espacio, composed by Ángel Arranz and visualized by Beatriz del Saz, inspired on four different avant-garde buildings in Spain. De la luz y del espacio is based on Bodegas Qumrán, a work by the architecture studio Konkrit Blu from Barcelona.

The piece takes as a model the resonances of the real spaces, recorded by the composer self.
To this end, a glass of wine was used as a resonator by introducing inside a small microphone. This noise-silence captured by using naturally amplified resonators was taken as a metaphor of light translated to sound. So do video animations. These are based on the real 3D model of the winery. Few colors were used in order to enhance the quality of shapes, while the duality between light and space is represented with the colors black and white.

The video was created in close collaboration with the composer, and this made possible a special synergy with the musical discourse.

Quaternions and OpenFrameworks

There are multiple ways of representing rotation in a 3D environment. You have “normal” rotation (degrees about the XYZ axis), axis-to-angle rotation (rarely used in 3D animation), Euler angles, and quaternions. Each of them has its advantages and disadvantages, it just depends on the kind of project you are working on.

I found that in my particular case, for the video I am working on, quaternions were the best option. But… What is a quaternion? It took me a while to get to understand what this obscure mathematical word means, and I think I still don’t quite understand it, but well, here is my attempt to make this concept a little bit more clear – from the animator’s point of view.

OpenFrameworks code

This code is based on an example published by an user called julapy, from Sydney, on this post of the OpenFrameworks forum.

1) ofQuaternion class
In OpenFrameworks, creating a quaternion is as simple as declaring an instance of the class ofQuaternion.
OF007 includes this class in its core, however, if you are using OF006, you’ll have to use the “ofxQuaternion” add-on, and include its header accordingly in testApp.h.

ofQuaternion qr (angle, axis);

Note that the class ofQuaternion has several constructors. This means that you can initialize an instance in several ways (in Xcode, you can see this by right-clicking in the name ofQuaternion and selecting the option Jump to Definition).
I am going to use the constructor accepting a float scalar and a ofVec3f. The scalar represents the angle or amount of rotation, while the ofVec3f is a 3-dimensional vector representing a (normalized) axis of rotation. That is to say, the axis around which the rotation is produced.

2) Create 4 quaternions
Now we are going to create 4 quaternions:

  • A quaternion for “roll” rotation (rotation around Z-axis)
  • A quaternion for “pill” rotation (rotation around Y-axis)
  • A quaternion for “yaw” rotation (rotation around X-axis)
  • A quaternion to include all the 3 rotations combined
//Declare the normalized XYZ axis as vector variables
ofVec3f Znormal(0, 0, 1);
ofVec3f Xnormal(1, 0, 0);
ofVec3f Ynormal(1, 0, 1);

//Create the quaternions
ofQuaternion qr (roll, Znormal); // quat roll.
ofQuaternion qp (pitch, Xnormal); // quat pitch.
ofQuaternion qh (heading, Ynormal); // quat heading or yaw.
ofQuaternion qt; // quat total.

Basically we are telling our quaternion: please rotate “roll/pitch/heading” degrees around the “Znormal/Xnormal/Ynormal” axis.
As it seems, this way of thinking is not correct mathematically, but it serves our purposes.

Note: If you observe the complete code (see below), the variables roll, pitch and yaw are changed by user interaction, if you press a key the angle of each of them is incremented by one.

3) Combine the 3 quaternions into one

Now we want to obtain a single “definitive” quaternion which contains the rotations of qr, qp, and qh. We do this by multiplying all the quaternions. Note that THE ORDER DOES MATTER: Apply roll first, then pitch, then heading.

 qt = qr * qp * qh;

4) Apply transformation
This is the most important step. We extract the quaternion information and transform it into a “normal” 4×4 matrix, like the ones OpenGL uses to make transformation operations. This way we can go on working with our old friend glRotatef.

How do we do this? Don’t worry, the difficult stuff was already implemented by the clever OF developers. We are just using one member function of the ofQuaternion class.

First we create two new variables which stores the angle of rotation after quaternion transformation, and the axis around which the rotation occurs, also after quaternion transformation.
I like to imagine it this way: when you create a quaternion, you are specifying a rotation around an axis in a world which has no euclidean xyz coordinates. You cannot define this rotation as up, down, left or right as it has no references.
Once this rotation is performed, you have to come back to the “real world”, and translate this rotation into the coordinate space you are working on. This transformation is made with the function member getRotate(qangle, qaxis).
We are telling the quaternion to give back some elements which the application will use to build a normal 4×4 transformation matrix, so that it can go on with the transformation process. Recall that for example in OpenGL transformations and rotations are made by multiplying multiple matrices in a given order. More on this in the OpenGL Red Book.

ofVec3f qaxis; float qangle;
qt.getRotate(qangle, qaxis);

ofRotate(qangle, qaxis.x, qaxis.y, qaxis.z);
//here goes the object we want to draw

You can download and see the complete code in this GitHub repository page.

Further reading…

– Great FAQ pagina to get you started (as found in Roxlu’s blog)

– Wikipedia pagina on quaternions

– Book “3D Math Primer for Graphics and Game Development” – a must-read, really useful if you don’t have much of a maths background

SAH – [d]espacio series (2012)

Video 11′ 51″

Music by Ángel Arranz

AH is the third video of the acoustic series [d]espacio, with music by Ángel Arranz and inspired in Bodegas Ysios winery by the architect Santiago Calatrava. The video replicates the visual structure of the winery’s facade, and has 3 straightforward, clearly differentiated parts. In this case, music and video evolve in a separate way, and the structure of one does not influence the structure of the other. In the style of ancient Egyptian architecture, the video uses straight lines exclusively, which combine in whimsical patterns. The colors remind of the desert landscapes of Egypt, of the white garments of the gods represented in the tombs’ mural paintings, of their extraordinary treasures, and naturally, of the red and rosy hues of wine: a beverage whose elaboration, as the legend goes, Osiris taught to mankind.

JavaScript interpolation and Max/Jitter

For my last video, Qumran B, I wanted to create have 9 objects ( each with a different texture, so I decided to implement a piece of JavaScript code.
I have been messing around with C++ and OpenFrameworks the last months, and somehow coming back to the pre-made graphical environment in Max/Jitter felt quite annoying.

After some posting in the fantastic Max support forum (the community there is incredibly helpful and always give you great tips) I came out with this code.

The idea is that whenever the function “randomize” is called, these pieces jump to different location in space interpolating (tweeing) from the original position to the final position. These intermediate positions are calculated inside the js object and then sent to 9 different [receive] objects inside my patch.

I also found this fantastic article by Paul Bourke. In this article he describes the commonest interpolation methods and he even shares the C++ functions to make them possible.

The script’s basis are tasks. JS tasks are basically functions which are programmed to happen at a given interval, or to repeat until they are stopped. You do not need to call these functions everytime (for example, by sending a bang into the js object), instead you program when you want the function to start repeating, and when you want it to end.

When creating interpolation, it is important to take into account that the original and final positions need to be the same from the beginning to the end of the moment, otherwise the interpolation won’t work properly.

Here the code:

//Complete corrected js code  
var nPieces =9;
var pieces = new Array(nPieces);
var finalPos = new Array(nPieces); //store actual positions, then generate new positions
var sendObj = ["send0", "send1", "send2", "send3", "send4", "send5", "send6", "send7", "send8"];
var rScale = 5;
var counter = 0.0;
var refreshCounter = 0.01;
var interpYesNo = false;
var PI = 3.141594;
var tsk = new Task(updateCounter, this);
tsk.interval = 50; //repeats each 50 ms
function piece(x, y, z, w, h) { //pieces constructor
this.pos = [x,y, z];
this.scale = [w,h, 1.0];
this.vel = [0.0, 0.0, 0.0];
function setUpPieces () {
for(i=0; i<nPieces; i++)
pieces[i] = new piece(0.0, 0.0, 0.0, 1.0, 1.0);
messnamed(sendObj[i], "position", pieces[i].pos[0], pieces[i].pos[1], pieces[i].pos[2]);
function randomPos () {
return(((Math.random()-0.5)*rScale), ((Math.random()-0.5)*rScale), ((Math.random()-0.5)*rScale));
function calculateNewPositions() {
//store origin and final pos
for(i=0; i<nPieces; i++){
//originPos[i] = pieces[i].pos;//DELETE THIS LINE
finalPos[i] = [randomPos(), randomPos(), randomPos()];
function interpolation (initialPos, finalPos, time) {
for(i=0; i<nPieces; i++)
messnamed(sendObj[i], "position",
interpolation(pieces[i].pos[0], finalPos[i][0], c),
interpolation(pieces[i].pos[1], finalPos[i][1], c),
interpolation(pieces[i].pos[2], finalPos[i][2], c));
function randomize() {
if (interpYesNo == false) {
interpYesNo= true;
tsk.repeat(); //start task
function updateCounter() {
if(counter < 1.0)
counter += refreshCounter;
post(counter, "\n");
counter = 0.0;
interpYesNo = false;
for(i = 0; i<nPieces, i++)
pieces[i].pos = finalPos[i]; //STORE FINAL POSITION AS INITIAL POSITION }
arguments.callee.task.cancel(); //cancel the task
updateCounter.local = 1; //prevent triggering the task directly from outside the js
function stop() {
interpYesNo = false;


Video installation (45′)

Tallereando is a multidisciplinary exhibition which integrates a series of photographies by José Luis Rodríguez Posadas, a sound composition by the composer Ángel Arranz and a video installation with abstract 3D images by myself.

The video tries to recreate the dynamism and aural ambiances produced by the old tools portrayed in the photographies.

DK Between the East and the West (2011)

Live video improvisation

Music by Ángel Arranz

DK <qumran> is a series of multidisciplinar pieces consisting of three electronic pieces with acoustic instruments composed by Ángel Arranz, with visual improvisations inspired in the architecture of the winery Bodegas Qumrán, by the architecture studio konkritblu

Extrusion – [d]espacio series (2011)

Video 9′ 24”
Music by Ángel Arranz

Extrusion is a video created in close collaboration with the composer of the music, Angel Arranz. The term ‘Extrusion’ means:

1. The act or process of pushing or thrusting out.
2. The act or process of shaping by forcing through a die.
3. An object or material produced by extruding.

Usually this term is associated to plastics, and in this sense the video depicts a fluid, flexible process of transformation in several stages. It describes the transit from a dramatic, colliding and artificial sort of transformation, such as that occuring in industrial environments, to a more natural, “accepted” change, similar to the ones happening in nature, most of the time with unpredictable results.

The video is created by using OpenGL environments and JavaScript scripting.