Python example constraining nulls to components


Just a little example that uses the Object Model to create a null and a ObjectToCluster constraint for each selected component (point, edge, polygon, …).
Note line 13. I can use CollectionItem.SubElements to get the indices of the selected components.

from win32com.client import constants as C
si = Application
log = si.LogMessage


if si.Selection.Count > 0 and si.ClassName(si.Selection(0)) == 'CollectionItem' and si.Selection(0).SubComponent is not None:

	# pnt, poly, edge, ...
	clusterType = si.Selection(0).Type.replace( 'SubComponent','' )
	o = si.Selection(0).SubComponent.Parent3DObject
	
	for i in si.Selection(0).SubElements:
		c = o.ActivePrimitive.Geometry.AddCluster( clusterType, "", [i] )
		n = si.ActiveSceneRoot.AddNull()
		n.Kinematics.AddConstraint( "ObjectToCluster", c )

Changing the default startup layout


To have Softimage start up with a certain layout, you don’t really have to do anything. When you exit Softimage, it writes the current layout to your preferences file, so that the next time you start Softimage it starts up with that same layout.

For example, if I change to the Tools Development Environment layout and exit Softimage, then my %XSI_USERHOME%\Data\Preferences\default.xsipref file will include this line:

xsiprivate.UI_LAYOUT_DEFAULT	= Tools Development Environment

So when I start Softimage again, it will start up in the Tools Development Environment.

Here’s how to access that preference in scripting:

# Python
from win32com.client import Dispatch as disp
from win32com.client import constants as C
si = disp('XSI.Application' )
log = si.LogMessage


log( C.siUILayoutDefault )
log( si.GetUserPref( C.siUILayoutDefault ) )
log( si.Preferences.GetPreferenceValue( "xsiprivate.UI_LAYOUT_DEFAULT" ) )

# INFO : UI_LAYOUT_DEFAULT
# INFO : Compositing
# INFO : Compositing

OO AddPointToNull in Python


Someone posted Olivier Ozoux’s 11-year-old AddNulltoPoints script to xisbase the other day. You can see from the install instructions that this script is old-school.

'################################################################################
'NAME: Add Null To Point v2.0
'AUTHOR: Olivier Ozoux <oliviero@softimage.com>
'LAST MODIFIED: 2001-05-22
'
'v2.0 is a complete rewrite using the Object Model where possible
'
'INSTALL
'
'1. Copy the SPDL file:
'	{5CD342AD-2FB1-4646-9D14-3E82C805177D}.spdl
'	to the spdl directory of XSI (for example):
'	C:\Softimage\XSI_1.5\Application\spdl
'
'2. Copy the Preset file:
'	AddNullToPointDialog.Preset
'	to the Preset Property directory of XSI (for example):
'	D:\Softimage\XSI_1.5\DSPresets\Properties
'
'3. Restart XSI
'
'4. Run the Script or Create a Command/Button on a toolbar
'	
'
'This tool will create a single Null for each point of the selected object(s).
'(you can also select a point cluster, or tag points). Then based on the dialog
'choice, it will either Constrain the Null to the Point using Object to Cluster
'constraint, or Deform the point to the Null with a Cluster Center operator.
'
'-Olivier Ozoux
'###############################################################################

To get rid of the SPDL and preset, I took a few minutes and updated it to Python.

#
# Softimage 2013 and later
#
from sipyutils import si			# win32com.client.Dispatch('XSI.Application')
from sipyutils import log		# LogMessage
from sipyutils import C			# win32com.client.constants
si = si()


#
# Softimage 2012
#
#from siutils import si		# Application
#from siutils import log		# LogMessage
#from siutils import disp	# win32com.client.Dispatch
#from siutils import C		# win32com.client.constants

#
# For Softimage 2011
# 
#from win32com.client import Dispatch as disp
#from win32com.client import constants as C
#si = disp('XSI.Application')
#log = si.LogMessage

def CreateUIDialog():

	oDialog = si.ActiveSceneRoot.Properties( 'AddNullToPoint' )
	
	if oDialog is None:
		oDialog = si.ActiveSceneRoot.AddProperty( 'CustomProperty', False, 'AddNullToPoint' )
		oDialog.AddParameter2("CnsType",C.siInt4,0,0,100,0,100,C.siClassifUnknown,C.siPersistable + C.siKeyable)
		oDialog.AddParameter2("NullName",C.siString,"",None,None,None,None,C.siClassifUnknown,C.siPersistable + C.siKeyable)
		oDialog.AddParameter2("ParentObj",C.siBool,True,None,None,None,None,C.siClassifUnknown,C.siPersistable + C.siKeyable)

		oLayout = oDialog.PPGLayout
		oLayout.Clear()
		oLayout.AddEnumControl( 'CnsType', [ 'Null to Point (Object to Cluster)', 0, 'Point to Null (Cluster Center)', 1 ], 'Constraint Type', C.siControlRadio )
		oLayout.AddGroup( 'Options' )
		oLayout.AddItem( 'NullName' )
		oLayout.AddItem( 'ParentObj' )
		oLayout.EndGroup()
		
		oDialog.Parameters( 'NullName' ).Value = '<obj>_pnt'
	
	return oDialog
	

def addNullToPoint( oSel, Mode, Name, Parent ):
	oRoot = si.ActiveSceneRoot
	if oSel.Type in [ 'polymsh', 'crvlist', 'surfmsh' ]:
		aIndex = [x for x in range( oSel.ActivePrimitive.Geometry.Points.Count ) ]
		oGeom = oSel.ActivePrimitive.Geometry
		oPoints = oGeom.Points
	elif oSel.Type == 'pntSubComponent':
		aIndex = oSel.SubElements
		oSel = oSel.SubComponent.Parent3DObject
		if oSel.Type in [ 'polymsh', 'crvlist', 'surfmsh' ]:
			oGeom = oSel.ActivePrimitive.Geometry
			oPoints = oGeom.Points
		else:
			log( 'Not a geometric object' )
			return
	elif oSel.Type == 'pnt':
		aIndex = oSel.Elements.Array
		oGeom = oSel.Parent
		oPoints = oGeom.Points
		oSel = oSel.Parent3DObject
	else:
		log( 'Not a geometric object' )
		return

	pntName = Name.replace( '<obj>', oSel.Name )

	for i in aIndex:
		oCls = oGeom.AddCluster( 'pnt', 'pnt' + str( i ), [i] )
		oNull = oSel.AddNull( 'pntName' + str( i ) )
		#TODO

		if Mode == 0:
			# Constrain the Null to the Cluster
			oNull.Kinematics.AddConstraint( "ObjectToCluster", oCls, False )
		elif Mode == 1:
			#Move the Null in position
			oNull.Kinematics.Local.Parameters("posx").Value = oPoints(i).Position.X
			oNull.Kinematics.Local.Parameters("posy").Value = oPoints(i).Position.Y
			oNull.Kinematics.Local.Parameters("posz").Value = oPoints(i).Position.Z

			# Create ClusterCenter
			si.ApplyOperator( "ClusterCenter", str(oCls) + ";" + str(oNull), 0 )

		#Cut The Null if needed
		if Parent == False:
			si.CutObj( oNull )

def AddNullToPointProc():
	oDialog = CreateUIDialog()
	retval = si.InspectObj( oDialog, "", "", C.siModal )

	mode = oDialog.Parameters("CnsType").Value
	name = oDialog.Parameters("NullName").Value
	parent = oDialog.Parameters("ParentObj").Value
	
	for oSel in si.Selection:
			addNullToPoint( oSel, mode, name, parent )


AddNullToPointProc()

Setting up Softimage for network rendering


I get asked this question from time to time. It’s actually pretty straightforward to set up…it’s managing the render jobs that may take more effort.

  1. On each render node, install a network-licensed version of Softimage.
  2. During the install, on the Product Information page:

    • Choose Network License.
    • Enter your serial number and the product key 590D1.
    • Enter the name of the license server computer.

Done. It’s all set up now, but there’s a few things you should check/consider:

  • Check that you can run xsibatch on the render nodes and get a license.
    If you have any problems, here’s some troubleshooting tips for xsibatch licensing.
  • Xsibatch needs to have read/write access to wherever you store your Softimage scene files and projects, and wherever you decided to output the rendered images.
    For example, you could have a separate file server for scenes and render output, or it could be the local workstation where you run Softimage.
  • Third-party addons, plugins, and shaders need to be available to the render nodes, either via a shared workstation or by installing them on the render node.
    Note that the user account used to run xsibatch will have a Softimage user folder on the render node.
  • You need a way to manage the render jobs that run on the render nodes. There are a range of possible ways to do this:
    • Manually starting xsibatch on each render node.
      You could either specify specific framesets to render, or use the –skip flag to tell xsibatch to skip frames that are already rendered [by other render nodes]
      For example:

      xsibatch –render “//server/project/scenes/Example.scn” –frames 1-10
      xsibatch –render “//server/project/scenes/Example.scn” –skip
    • Hand-rolling your own tools/scripts to start render jobs (for example, using pstools to start xsibatch jobs on the render nodes, or generating batch files to kick off render jobs)
    • Purchasing render management software (such as Royal Render—you may want to try the demo version)

Finding the menu commands added by a plugin


So you installed a plugin, but now you cannot find out how to access the plugin in Softimage.

If the plugin added a menu command, and it’s a scripted plugin, we can find it by checking the plugin code (in the Plugin Manager > Tree, right-click the plugin and click Edit).

Find the definition of XSILoadPlugin.
In the XSILoadPlugin function, look for any calls to RegisterMenu.

def XSILoadPlugin( in_reg ): #{{{
	in_reg.Author = "kim"
	in_reg.Name = "EPSexportPlugin"
	in_reg.Email = ""
	in_reg.URL = ""
	in_reg.Major = 1
	in_reg.Minor = 0

	in_reg.RegisterProperty("EPSexport")
	in_reg.RegisterMenu(constants.siMenuMainFileExportID,"EPSexport_Menu",false,false)

	# register the export command
	# 	KA_EpsExport( Application.Selection, OutputFile, CullBackFaces, doInnerLines, doBorderLines, InnerLineThickness, BorderLineThickness, AutoDiscontinuity, Xres )
	in_reg.RegisterCommand("KA_EpsExport","KA_EpsExport")

	return true

RegisterMenu uses what’s called a “menu anchor” to define a new menu command. In this example, the menu anchor is siMenuMainFileExportID.

Google the menu anchor or search the SDK docs, and you’ll find a page that describes the menu anchors: