Math Library (XSISDK)


Table of contents

Tips for using the XSI Math Libary

Object Creation and Re-use

The first thing to understand about the XSI scripting math library is that most methods and properties that return data expect you to provide an existing math object to fill in.

For example, if you have a SITranformation object and you want to get the scaling information you need to provide an existing SIVector object as an argument.

oSITransformation.GetScaling( vScaling )

The method erases any existing content of vScaling and fills it in with the scaling information.

At first this may appear to be an irritating design, because the caller has the burden of creating the vector object:

vScaling = XSIMath.CreateVector3
oSITransformation.GetScaling( vScaling )

Which is harder to write and less readable than this code:

vScaling = oSITransformation.GetScaling()

However this is actually an intentional design choice and the reason is performance.

It costs a certain amount of time to create a vector object. The fewer vector objects that are created the better. To minimize the creation of math objects the math API encourages callers to re-use their objects.

For example, it you have an array with 10,000 transformations, it would be faster to re-use a single vector object:

vScaling = XSIMath.CreateVector3

for ( i = 0 ; i < 10000 ; i++ )
{
    oSITransformationArray(i).GetScaling( vScaling ) ;
    //Do something with vScaling
}

rather than:

// Slower code
for ( i = 0 ; i < 10000 ; i++ )
{
    vScaling = XSIMath.CreateVector3
    oSITransformationArray(i).GetScaling( vScaling ) ;
    //Do something with vScaling
}

This optimization is only possible with an API that lets you provide an existing object to fill in, rather than forcing the creation of a new one at each call. So the simplistic API might be easier to learn, but it would force you down the path of slow code.

A great example of an ideal environment for Math object re-use is when writing Custom Operators.

For example, this is a Scripted Operator by Michael Isner (from Quaternion Spells (http://www.isner.com/tutorials/quatSpells/quaternion_spells_14.htm)).

Image:MathInScriptedOperator.jpg

Notice how he creates the Math Objects outside the Update() function. That means that they don't need to be recreated each time the operator is updated - they are cached as global variables. (To be strictly accurate, Aquat, Bquat, Cquat and Crot are cached purely for object reuse reasons, but C is cached both for object reuse and to avoid recalculation for each output port.)

Manipulating the Transform of an Object

One approach is to simulate the same actions that are performed in the UI by reading and writing the Parameter values of the global or local Kinematic state objects (posx, posy, posz, rotx etc....)


// Example of using the ParameterCollection of
// a KinematicState object

var oNull = ActiveSceneRoot.AddNull( "Null" ) ;

// The transform can be set through the parameters
// of the kinematicstate object
var oLocalKinematics = oNull.Kinematics.Local ;
oLocalKinematics.Parameters( "posx" ).Value = 10 ;
oLocalKinematics.Parameters( "posy" ).Value = 20 ;
oLocalKinematics.Parameters( "rotx" ).Value = 90 ;
oLocalKinematics.Parameters( "sclz" ).Value = 3 ;

// All the SRT values, plus many more parameters can 
// be read via the parameter collection
var oAllParameters = oLocalKinematics.Parameters ;
for ( var i = 0 ; i < oAllParameters.count ; i++ )
{
	logmessage( oAllParameters(i).ScriptName + ":" + 
				oAllParameters(i).Value ) ;
}

//Output:
//INFO : blendweight:1
//INFO : active:true
//INFO : posx:10
//INFO : posy:20
//INFO : posz:0
//INFO : rotx:90
//INFO : roty:0
//INFO : rotz:0
//INFO : quatw:0.7071067811865476
//INFO : quatx:0.7071067811865475
//INFO : quaty:0
//INFO : quatz:0
//INFO : sclx:1
//INFO : scly:1
//INFO : sclz:3
//INFO : sclorix:0
//INFO : scloriy:0
//INFO : scloriz:0
//INFO : cnsscl:true
//INFO : cnsori:true
//INFO : cnspos:true
//INFO : affbyscl:true
//INFO : affbyori:true
//INFO : posxmaxactive:false
//INFO : posxminactive:false
//INFO : posymaxactive:false
//INFO : posyminactive:false
//INFO : poszmaxactive:false
//INFO : poszminactive:false
//INFO : rotxmaxactive:false
//INFO : rotxminactive:false
//INFO : rotymaxactive:false
//INFO : rotyminactive:false
//INFO : rotzmaxactive:false
//INFO : rotzminactive:false
//INFO : siscaling:true
//INFO : rotorder:0
//INFO : pivotactive:true
//INFO : pposx:0
//INFO : pposy:0
//INFO : pposz:0
//INFO : protx:0
//INFO : proty:0
//INFO : protz:0
//INFO : psclx:1
//INFO : pscly:1
//INFO : psclz:1
//INFO : pivotcompactive:true
//INFO : pcposx:0
//INFO : pcposy:0
//INFO : pcposz:0
//INFO : pcrotx:0
//INFO : pcroty:0
//INFO : pcrotz:0
//INFO : pcsclx:1
//INFO : pcscly:1
//INFO : pcsclz:1
//INFO : nposx:0
//INFO : nposy:0
//INFO : nposz:0
//INFO : nrotx:0
//INFO : nroty:0
//INFO : nrotz:0
//INFO : nsclx:1
//INFO : nscly:1
//INFO : nsclz:1
//INFO : nsclorix:0
//INFO : nscloriy:0
//INFO : nscloriz:0

Another approach is to use the SITransformation object.

// Example of using the SITransformation to read
// and write the scaling, rotation and translation
// of an object

var oNull = ActiveSceneRoot.AddNull( "MyNull" ) ;

//Change the position and rotation of the null
//by providing a new transform

oNewLocalTransform = XSIMath.CreateTransform() ;

// Change posx, posy
oNewLocalTransform.SetTranslationFromValues( 5, 6, 0 ) ;

// set rotx to 180 degrees (pi radians)
oNewLocalTransform.SetRotationFromXYZAnglesValues( XSIMath.pi, 0, 0 ) ; 

// scale y-axis (scly)
oNewLocalTransform.SetScalingFromValues( 1, 2, 1 ) ; 

oNull.Kinematics.Local.Transform = oNewLocalTransform ;


PrintTransformation( oNull.Kinematics.Local.Transform ) ;

// Show the "SRT: of a SITransformation object
function PrintTransformation( in_oTransform )
{
	var oVector = XSIMath.CreateVector3();

	in_oTransform.GetScaling( oVector ) ;
	PrintVector( "Scaling:", oVector ) ;

	// In Radians
	in_oTransform.GetRotationXYZAngles( oVector ) ;
	PrintVector( "Rotation:", oVector ) ;

	in_oTransform.GetTranslation( oVector ) ;
	PrintVector( "Translation:", oVector ) ;
}

// Print a vector.  Values are rounded to 3 decimal places
function PrintVector( in_Prefix, in_oVec )
{
	logmessage( in_Prefix + " " + 
			XSIRound(in_oVec.x,3) + ", " + 
			XSIRound(in_oVec.y,3) + ", " + 
			XSIRound(in_oVec.z,3) ) ;
}

// Output:
//INFO : Scaling: 1, 2, 1
//INFO : Rotation: 3.142, 0, 0
//INFO : Translation: 5, 6, 0



// Example of using the SITransformation to read the local
// and global transforms of an object

newscene(null,false) ;

var oNull = ActiveSceneRoot.AddNull( "ParentNull" ) ;

//Change the position and rotation of the null
//by providing a new transform

oNewLocalTransform = XSIMath.CreateTransform() ;

// Change posx, posy
oNewLocalTransform.SetTranslationFromValues( 10, 20, 0 ) ;

// set rotx to 90 degrees (pi/2 radians)
oNewLocalTransform.SetRotationFromXYZAnglesValues( XSIMath.pi / 2, 0, 0 ) ; 

oNull.Kinematics.Local.Transform = oNewLocalTransform ;


PrintLocalGlobalTransforms( oNull ) ;


var oNullChild = oNull.AddNull( "ChildNull" ) ;
PrintLocalGlobalTransforms( oNullChild ) ;


// Show but the local and global SRT of an object
function PrintLocalGlobalTransforms( in_obj )
{
	logmessage( "--------" + in_obj.Name + "---------" ) ;

	var oLocalSITranformation = in_obj.Kinematics.Local.Transform ;
	logmessage( "Local Transform" ) ;
	PrintTransformation( oLocalSITranformation ) ;

	logmessage( "" ) ;

	logmessage( "Global Transform" ) ;
	var oGlobalSITranformation = in_obj.Kinematics.Global.Transform ;
	PrintTransformation( oGlobalSITranformation ) ;

	logmessage( "" ) ;	
}


// Show the "SRT: of a SITransformation object
function PrintTransformation( in_oTransform )
{
	var oVector = XSIMath.CreateVector3();

	in_oTransform.GetScaling( oVector ) ;
	PrintVector( "Scaling:", oVector ) ;

	// In Radians
	in_oTransform.GetRotationXYZAngles( oVector ) ;
	PrintVector( "Rotation:", oVector ) ;

	in_oTransform.GetTranslation( oVector ) ;
	PrintVector( "Translation:", oVector ) ;
}

// Print a vector.  Values are rounded to 3 decimal places
function PrintVector( in_Prefix, in_oVec )
{
	logmessage( in_Prefix + " " + 
			XSIRound(in_oVec.x,3) + ", " + 
			XSIRound(in_oVec.y,3) + ", " + 
			XSIRound(in_oVec.z,3) ) ;
}


//Output: (note how the local transform of
//the Child null is relative to the center 
//of the parent null)
//
//INFO : --------ParentNull---------
//INFO : Local Transform
//INFO : Scaling: 1, 1, 1
//INFO : Rotation: 1.571, 0, 0
//INFO : Translation: 10, 20, 0
//INFO : 
//INFO : Global Transform
//INFO : Scaling: 1, 1, 1
//INFO : Rotation: 1.571, 0, 0
//INFO : Translation: 10, 20, 0
//INFO : 
//INFO : --------ChildNull---------
//INFO : Local Transform
//INFO : Scaling: 1, 1, 1
//INFO : Rotation: -1.571, 0, 0
//INFO : Translation: -10, 0, 20
//INFO : 
//INFO : Global Transform
//INFO : Scaling: 1, 1, 1
//INFO : Rotation: 0, 0, 0
//INFO : Translation: 0, 0, 0

Rotations

// Demonstrate some different representations of
// a rotation: 
//
// -As a SIRotation object
// -As a 3x3 matrix
// -As a 4x4 matrix
// -As a SITransformation object
// -As a SIVector3 object

var oSIRotation = XSIMath.CreateRotation() ;

oSIRotation.SetFromXYZAnglesValues( 
				XSIMath.DegreesToRadians( 45 ),
				XSIMath.DegreesToRadians( 30 ),
				XSIMath.DegreesToRadians( 15 ) ) ;

oSIMatrix3 = XSIMath.CreateMatrix3() ;
oSIRotation.GetMatrix3( oSIMatrix3 ) ;

oSIMatrix4 = ConvertMatrix3ToMatrix4( oSIMatrix3 ) ;

oSITransformation = XSIMath.CreateTransform() ;
oSITransformation.SetMatrix4( oSIMatrix4 ) ;

var oSIVector3 = XSIMath.CreateVector3() ;

oSITransformation.GetRotationXYZAngles( oSIVector3 ) ;

// Prove that we haven't lost the original rotation values
logmessage( "Rotation " + 
			XSIMath.RadiansToDegrees( oSIVector3.X ) + ", " +
			XSIMath.RadiansToDegrees( oSIVector3.Y ) + ", " +
			XSIMath.RadiansToDegrees( oSIVector3.Z ) ) ;

// Output (notice very small rounding problems that occur
// when dealing with pi and trig functions):
//INFO : Rotation 45, 29.999999999999996, 14.999999999999998

function ConvertMatrix3ToMatrix4( oM3 )
{
	// Helper function to convert 3x3 rotation matrix
	// to equivalent 4x4 transformation matrix:
	//
	// r11 r12 r13 0
	// r21 r22 r23 0
	// r31 r32 r33 0
	// 0   0    0  1

	oSIMatrix4 = XSIMath.CreateMatrix4() ; 

	oSIMatrix4.Set( 
		oM3(0,0), oM3(0,1), oM3(0,2), 0,
		oM3(1,0), oM3(1,1), oM3(1,2), 0,
		oM3(2,0), oM3(2,1), oM3(2,2), 0,
		0,        0,        0,        1 ) ;

	return oSIMatrix4 ;	
}

Quaternions

Michael Isner Quaternion Tutorial (http://www.isner.com/tutorials/quatSpells/quaternion_spells_14.htm)

This page was last modified 20:17, 14 Dec 2010.
This page has been accessed 189314 times.

© Copyright 2009 Autodesk Inc. All Rights Reserved. Privacy Policy | Legal Notices and Trademarks | Report Piracy