[SItoA] Stopping procedural textures from swimming

The Noise shader can access the Pref coordinates to prevent swimming. But for other procedural textures, you’ll have to take a different approach (unless you whip up [a relatively simple] shader to get the Pref coordinates). Here’s one way, using ICE to store UVWs in a CAV, and then a Vertex Color node in the render tree.

First, create a Spatial projection and a Color at Vertices (CAV) property on your mesh.

Then build an ICE tree that gets the projection UVWs and stores them in the CAV.

In the render tree, use a Vertex Color to get the UVW information from the CAV, and feed that into the texture coordinates of the procedural texture.

[SItoA] Unlimited batch rendering with xsibatch -processing

Hat tip: Andy Jones on the Softimage mailing list

You can use xsibatch -processing to render scenes with Arnold. With -processing, xsibatch uses a Processing token instead of a Batch license, so you’re not limited by the number of Batch licenses you happen to have. Back in the days before third-party renderers, -processing for was for non-rendering tasks. Now it’s for non-mental ray tasks!

I was sure I tested this long ago, but obviously I must have made a mistake on my command line.

 xsibatch -processing -render //server/project/Scenes/example.scn

 Autodesk Softimage

License information: using [Processing]
# INFO : [sitoa] SItoA 2.7.1 win loaded.
# INFO : [sitoa] Arnold detected.

Here’s actual proof in the form of a screenshot 🙂


[SItoA] Expressions for standins of animated sequences

A standin can load an animation sequence, such as circling_cubes.[1..25].ass.
For example, if you open an Arnold_Standin property, click Browse, and select a sequence, Softimage automatically inserts a [Frame] token into the file name:


By default, that [Frame] token resolved to the current frame, but you can override that and use an expression to drive the sequence.

For example, if you have a 25-frame sequence of ASS files, you may want to play the 25 frames and then stop. To do that, you could use this expression:


If you wanted to continuously loop the 25 frame sequence, you could use an fmod (modulo) expression like this:

cond( fmod( Fc, 25 ) == 0, 25, fmod(Fc,25) )

And if you wanted to show just frames 10 to 25, you could use this expression:

cond( Fc<10 , 10 , MIN(Fc,25) )

If you’re not sure about these expressions, try playing with them in the Expression Editor. As you move through the timeline, watch the Current Value update in the Expression Editor.

[SItoA] Adjusting camera exposure

Arnold added support for per-camera exposure awhile ago:

Camera exposure control: All cameras, even custom cameras, have an exposure parameter that scales the pixel samples by 2 ** exposure . Increasing the exposure by 1.0, or one stop, produces an image twice as bright, while reducing the exposure by one stop produces an image half as bright. The default value is 0 for backwards compatibility. You can also control this in in kick with the new -e option.

In Softimage, you can access the exposure parameter though the User Options.


Changing ASS files with the Arnold Python API

If you want to change something in existing ASS files, don’t write an ad-hoc script or your own parser for the ASS file. Use the Arnold API. The Arnold API includes a set of Python bindings, so you can fairly quickly whip up a script to do whatever it is you need to do 🙂

For example, we recently discovered (and fixed) an issue where exported ASS files were missing procedural nodes. SItoA exports hair data in chunks (one chunk for every 200K hairs), but the exported ASS had just one procedural for the first chunk (chunk 0), but there should be one procedural for each chunk.

Here’s what the procedural for chunk 0 on frame 5 looks like. The missing procedurals would be for bin files like Hair.chunk.1.5.bin, Hair.chunk.2.5.bin, and so on.

 name Hair.SItoA.5000
 dso "sitoa_curves_proc.dll"
 data "//Projects/Support/Arnold_Scenes/Hair.chunk.0.5.bin"
 load_at_init on

So, for my first dive into the Arnold API, I put together a basic little script to add the missing procedurals. To do this, I had to learn how to:

  • Read and write ASS files
  • Iterate over nodes and find a specific type of node
  • Get parameter values from a node
  • Create new nodes
from arnold import *
import glob

ass_file = "Hair_Archive.ass"

AiASSLoad(ass_file, AI_NODE_ALL)

# Iterate over all shape nodes, which includes procedural nodes
iter = AiUniverseGetNodeIterator(AI_NODE_SHAPE);
while not AiNodeIteratorFinished(iter):
	node = AiNodeIteratorGetNext(iter)
	#print AiNodeGetName( node )

	# Is the node a procedural?	
	if AiNodeIs( node, "procedural" ):
		data = AiNodeGetStr( node, "data" )
		name = AiNodeGetStr( node, "name" )
		# Find all other chunk.<chunk-number>.<frame>.bin files
		chunks = glob.glob( data.replace( 'chunk.0', 'chunk.*' ) )

		# Add procedural nodes for chunks 1,2,3...
		for i in range(1,len(chunks)):
			n = AiNode("procedural");
			AiNodeSetStr(n, "name", "%s.%s" % (name, i) )
			AiNodeSetStr(n, "dso", "sitoa_curves_proc.dll")
			AiNodeSetStr(n, "data", data.replace( 'chunk.0', 'chunk.%s' % i ) )
			AiNodeSetBool(n, "load_at_init", True)


AiASSWrite(ass_file, AI_NODE_ALL, False)

[SItoA] Applying materials to standins

In Softimage, a standin object is the polygon mesh, hair, or point cloud with the Arnold_Standin property.

If you apply a material to a standin, that material will override any materials specified in the ASS file referenced by the standin. If you don’t want that to happen, give your material a name that starts with “Scene_Material” or “Standin_Material” (it doesn’t matter if you use uppercase or lowercase for the names).

If you do that, the standin object will use that material, but the objects in the ASS file will use the materials saved in the ASS file.

Here’s what you get in an exported ASS file. If SItoA finds a standin with a material name that starts with “scene_material” or “standin_material”, it exports a procedural node with no material.

 name standin-cube.SItoA.41000
 dso "\\server\project\Arnold_Scenes\XSI_Man.ass"
 min -4 0 -4
 max 4 0 4
  1 0 0 0
  0 1 0 0
  0 0 1 0
  0 0 0 1 

Otherwise, if you name the standin material something else, the procedural node will include a shader node for that material:

 name standin-cube.SItoA.41000
 dso "\\server\project\Arnold_Scenes\XSI_Man.ass"
 min -4 0 -4
 max 4 0 4
  1 0 0 0
  0 1 0 0
  0 0 1 0
  0 0 0 1 
 shader "Sources.Materials.DefaultLib.Test.standard.SItoA.40000.1" 
 declare procedural_shader constant ARRAY NODE
 procedural_shader "Sources.Materials.DefaultLib.Test.standard.SItoA.40000.1" 

[SItoA] Doing a license check in Softimage

Setting up the environment right is what often goes wrong. Running kick -licensecheck from inside Softimage is a quick way to check that you set up the environment variables correctly.

Here’s two lines of Python that will open a command prompt and run kick -licensecheck (on Windows).

from subprocess import Popen
Popen(["cmd", "/K", XSIUtils.BuildPath( Application.Plugins('Arnold Render').OriginPath, 'kick.exe' ), "-licensecheck"])

Here’s the same thing, but broken down a bit for legibility:

si = Application

p = si.Plugins('Arnold Render')
sKick = XSIUtils.BuildPath( p.OriginPath, 'kick.exe' )

from subprocess import Popen
Popen(["cmd", "/K", sKick, "-licensecheck"])

SITOA: Adding Arnold materials through scripting

If you want to apply Arnold materials through scripting, there are a couple of undocumented commands you can use:

  • SITOA_AddMaterial takes the shader family (for example, Material or Texture) and the name of a shader, and connects that shader to the surface port on the Material node.
    # Add a standard material to the selected object
    SITOA_AddMaterial( "Material", "standard" )
    # Add ambient_occlusion to the selected object
    SITOA_AddMaterial( "Texture", "ambient_occlusion" )
  • SITOA_AddShader is similar, but it also takes a connection point as an argument, so you can connect to a specific port, such as the Environment or Displacement port.
    # Add a vector displacement shader
    SITOA_AddShader("Texture", "sta_vector_displacement", "displacement" )

However, neither of these commands return anything. So if you wanted to name the material, it’s not so easy. SITOA_AddMaterial does apply to the selection, so you could go through the selection to get the new material:

# Python
Application.SITOA_AddMaterial("Material", "standard")
sel = Application.Selection
mat = sel(0).Material
mat.Name = "MyStandardMaterial77"

You could write your own function with X3DObject.AddMaterial.

Here’s the simplest possible version. I don’t specify the path to a preset, just the name of the shader. That’s not terribly efficient, because Softimage now has to search for the preset (and that took about 0.2 seconds on my machine).

si = Application

def add_material( o, shader_name ):
	return o.AddMaterial( shader_name )

mat = add_material( si.Selection(0), 'Material', 'Standard' )
mat.Name = 'My_Standard_Mat'

Here’s a version that builds the path to the preset (just like the SITOA commands do), but that doesn’t require the shader family, just the name of the shader.

# dictionary of shader families, keyed by shader name
shader_types = {
  'ray_switch' : 'Material' , 
  'sta_vector_displacement' : 'Texture' , 
  'wireframe' : 'Material' , 
  'sta_displacement' : 'Texture' , 
  'ambient_occlusion' : 'Texture' , 
  'skin_sss' : 'Material' , 
  'sta_camera_projection' : 'Texture' , 
  'utility' : 'Texture' , 
  'bump3d' : 'Texture' , 
  'standard' : 'Material' , 
  'complex_fresnel' : 'Texture' , 
  'bump2d' : 'Texture' , 
  'motion_vector' : 'Material' , 
  'hair' : 'Material' , 
  'noise' : 'Texture' , 

si = Application

def add_material( o, shader_name ):
	arnoldPlugin = si.plugins("Arnold Shaders");
	dspresets = XSIUtils.BuildPath( arnoldPlugin.OriginPath, '..', '..', 'Data', 'DSPresets' )
	mat = None
	if shader_name in shader_types:
		preset = XSIUtils.BuildPath( dspresets, 'Shaders', shader_types[shader_name], '%s.Preset' % shader_name )
		mat = o.AddMaterial( preset )
	return mat

mat = add_material( si.Selection(0), 'noise' )

mat.Name = 'My_Noise'

Exporting ASS files from Softimage with xsibatch

You cannot use xsibatch -export to export ASS files (because of the way sitoa implements ASS exporting). But it’s not too hard to do the same thing with SITOA_ExportScene and xsibatch -script.

This is what the xsibatch command line would look like (on Windows). For readability, I used the EXPORT_SCRIPT and SCENE variables to reduce the length of the xsibatch command line.

set EXPORT_SCRIPT = batch_export_scene.pys
set SCENE = \\server\project\scenes\elephant_herd.scn
xsibatch -processing -script %EXPORT_SCRIPT% -args -start 5 -end 20 -step 1 -scene %SCENE%

And here’s the batch export script.

I expose the basic parameters only, and I use the ASS Archive output path from the Arnold Render options, the scene name, and the [Frame] token to compose the output file name.

def main( start, end, step, scene ):
	Application.OpenScene(scene, "", "")
	x = Application.Dictionary.GetObject( "Passes.Arnold_Render_Options" )
	dir = XSIUtils.ResolveTokenString( x.output_file_tagdir_ass.Value, 0, False, None, None )

	scn = Application.ActiveProject.ActiveScene.Parameters("Name").Value	
	output = XSIUtils.BuildPath( dir, '%s.[Frame].ass' % scn )

	Application.SITOA_ExportScene( start, end, step, False, False, output )