Assigning a per-object random value with ICE


Suppose you want to use an ICE attribute to drive some behavior in the render tree. For example, you may want to introduce some randomization to a procedural texture. Here’s one way to go about it.

First, create an ICE attribute on each object. You’ll use this object as the seed for the Random Value node (you need a different seed for each object, otherwise you’ll get the same “random” number for each object).

si = Application
i = 0
for o in si.Selection:
	a = o.ActivePrimitive.Geometry.AddICEAttribute("_seed1", 2, 1, 1  )
	a.DataArray = [ (i) ]
	i = i + 1

Now apply a simple ICE compound to each object.

Seed and random scalar value for each object

Seed and random scalar value for each object


All the compound does is feed the seed into a Random Value node, and store the random value in another ICE attribute.
PerObjectRandomValueCompound

Deleting particles by ID


Let’s say you wanted to delete certain points for some reason; maybe they were misbehaving or something. You could just stick the IDs into an array and feed that into Find in Array, like so:

DeletePointsByID

This is an answer to a question on si-community, which timed out on me when I clicked Submit. So now it’s my post for today. After struggling with Maya nParticles for an hour, I can’t think hard anymore.

Using an ICE attribute to drive a procedural texture


Here’s a simple example of using an ICE attribute to drive a procedural texture. In this case, I’m using a random integer to drive the number of repeats of a checkerboard:

randomized_checker

To set it up, I ran this script to programmatically add an ICE attribute. Unfortunately, I found I had to add an ICE tree to get the attribute to show up in the render tree.

import random

si = Application
    
for o in si.Selection:
	# Long, Single, Singleton
	a = o.ActivePrimitive.Geometry.AddICEAttribute("_random", 2, 1, 1  )
	a.DataArray = [ (random.randint(1,8))]
	si.ApplyOp("ICETree", o, "siNode", "", "", 0)

Then in the render tree I used Integer Attribute node to get the attribute value. This same material is applied to every cube in my example.
randomized_checker_mat

And if you wanted to update the ICE attribute later, eg increase the range of random values, you could do something like this:

import random

si = Application
    
for o in si.Selection:
	a = o.ActivePrimitive.Geometry.ICEAttributes("_random")
	a.DataArray = [ (random.randint(1,12))]

Screenshots of the week


sparta-like particle editing in softimage

Point position from group
by Vincent Ullmann
PointsOfGroup

PointsOfGroup_advanced

lambert shading
by Mr.Core
post-37-13590474490

Creating strands between two different objects
by Ola Madsen
Strand_between_objects_img02

wet fur effect

Create hexa tesselation
by msktkhs
“Be further divided into two right-angled triangle is divided into six triangles hexagons, X direction will take time to get to that direction cos60 * 4, Y is I will be next to the point sin60 * 2 too (laughs)”
ge88

Nodes for whirlpool spiral
by msktkhs
s09f

Volume rendering with ICE

bend paper

Saturday Snippet: russian roulette


I commented out the things that would actually “shoot a bullet”.

CrashXSI() is an actual Softimage command, but it doesn’t do anything in a release build.

import random

# bullets
def crashxsi():
	Application.LogMessage( "Bang!" )
	Application.CrashXSI()
	
def blank():
	Application.LogMessage( "Try again" )
	
def losework():
	Application.LogMessage( 'NewScene( "", False )' )
	#Application.NewScene( "", False )
	
def quitxsi():
	Application.LogMessage( "Application.Quit()" )
	#Application.Quit()


#load chambers
chambers = {1: blank,
			2: crashxsi,
			3: quitxsi,
			4: blank,
			5: blank,
			6: losework
			}
	
#spin and shoot
chambers[ random.randint(1,6) ]()

Getting PointPositions from a group


For this post, I took an explanation from an ICE developer, and added some illustrations and bit of my own explanatory text…

When you reference Group.PointPosition, ICE resolves the graph assuming the Get Data node outputs an array of 3DVectors in the context of the first primitive in the group. So, in this example, TRex is the first member of the group, so the context of Group.PointPosition is Array of 3D Vector per point of Trex.Trex:

Group.PointPosition1

In this case, the Array of 3D Vector is an array of four elements (the number of meshes in the group).

Group.PointPosition2

The indexset used (per point of Trex.Trex in this case) is reduced to its smallest size (the number of 0D from the geometry in the group with the least amount of points). The cube has 8 points, so you end up with 8 points for each group member. Since there are four groups members, you get 32 total points.
Group.PointPosition3

Here’s an alternate way to illustrate that. The Trex has 1814 points, but because of how Group.PointPosition is resolved by ICE, you get a filtered size of 8.
Group.PointPosition4

Wednesday word cloud: Softimage scripting commands


This word cloud shows the scripting names of the commands in Application.Commands (Softimage 2013 SP1)
CommandScriptingNames_2013sp1
You can see that some scripting names are repeated quite a few times:

  • ApplyTopoOp (66)
  • ApplyOp (47)
  • ApplyGenOp (44)
  • ToggleValue (43)
  • ApplyShader (37)

Some scripting commands, like Insert Curve Knot, are instances of a generic command like ApplyTopoOp:
InsertCurveKnotDescription
but with hard-coded arguments:
InsertCurveKnotArguments

See also Why ApplyOp doesn’t pop up a PPG.

Here’s a list of the TopoOp commands:

for c in Application.Commands:
	if c.ScriptingName == "ApplyTopoOp":
		print "%s : %s" % (c.ScriptingName, c.Name )
		
# ApplyTopoOp : Apply Topology Operator
# ApplyTopoOp : Insert Curve Knot
# ApplyTopoOp : Subdivide Edge
# ApplyTopoOp : Raise Nurbs Curve Degree
# ApplyTopoOp : Extrude Comp. Axis
# ApplyTopoOp : Filter Polygons
# ApplyTopoOp : Collapse
# ApplyTopoOp : Inset Polygons
# ApplyTopoOp : Subdivide Polygon
# ApplyTopoOp : Slice Polygons
# ApplyTopoOp : Offset Polygons
# ApplyTopoOp : Dice Object
# ApplyTopoOp : Surface Snip
# ApplyTopoOp : Invert Selected Polygons
# ApplyTopoOp : Delete Trim
# ApplyTopoOp : Duplicate Polygons Along Curve
# ApplyTopoOp : Curve Remove Knot
# ApplyTopoOp : Extrude Component Along Normal
# ApplyTopoOp : Dissolve Component
# ApplyTopoOp : Boolean Difference
# ApplyTopoOp : Boolean Union
# ApplyTopoOp : Boolean Intersection
# ApplyTopoOp : Local Subdivision
# ApplyTopoOp : Insert Surface Knot
# ApplyTopoOp : Remove Surface Knot
# ApplyTopoOp : Polygon Reduction
# ApplyTopoOp : Bevel
# ApplyTopoOp : Delete Component
# ApplyTopoOp : Quadrangulate
# ApplyTopoOp : Dissolve & Clean Adjacent Vertices
# ApplyTopoOp : Symmetrize Polygons
# ApplyTopoOp : Disconnect Component
# ApplyTopoOp : Set Curve Knot Multiplicity
# ApplyTopoOp : Bridge Edges
# ApplyTopoOp : Apply DelMeshPoint
# ApplyTopoOp : Invert All Normals
# ApplyTopoOp : Curve Inverse
# ApplyTopoOp : Surface Shift
# ApplyTopoOp : Curve Shift
# ApplyTopoOp : Surface Curve Shift
# ApplyTopoOp : Surface Swap
# ApplyTopoOp : Filter Edges
# ApplyTopoOp : Curve Reparameterize
# ApplyTopoOp : Surface Reparameterize
# ApplyTopoOp : Add Edge
# ApplyTopoOp : Add Polygon
# ApplyTopoOp : Nurbs Curve Delete Point
# ApplyTopoOp : Nurbs Surface Delete Point
# ApplyTopoOp : Mesh Surface Delete Point
# ApplyTopoOp : Surface Open/Close
# ApplyTopoOp : Curve Open/Close
# ApplyTopoOp : Delete Edge
# ApplyTopoOp : Surface Stitch
# ApplyTopoOp : Surface Extend to Curve
# ApplyTopoOp : Surface Clean
# ApplyTopoOp : Curve Stitch
# ApplyTopoOp : Curve Clean
# ApplyTopoOp : Surface Curve Inverse
# ApplyTopoOp : Extrude Component Along Curve
# ApplyTopoOp : Weld Edges
# ApplyTopoOp : Filter Points
# ApplyTopoOp : Weld Points to Target
# ApplyTopoOp : Delete Particle
# ApplyTopoOp : Trim by Projection
# ApplyTopoOp : Dice Polygons
# ApplyTopoOp : Bridge Polygon	

Writing a python script for processing scenes with xsibatch


Here’s the basic skeleton of a Python script that calls xsibatch -processing -script on all scene files in a given folder.

Python command line:
The python script takes two arguments: the root folder for the location of the scene files, and the name of the script file to run with xsibatch -script.

python process_scenes.pys --dir ""C:\Program Files\Autodesk\Softimage 2013 SP1\Data\XSI_SAMPLES\Scenes" --script "test.pys"

process_scenes.pys:
The python script takes care of finding all the scene files, and then running xsibatch -processing -script on each .scn file.

import os
import fnmatch
import subprocess
import sys
import getopt

XSI_BINDIR=r"C:\\Program Files\\Autodesk\\Softimage 2013 SP1\\Application\\bin"

opts, extraparams = getopt.getopt(sys.argv[1:], "d:s:", ["dir=","script="]) 

#
# Get root directory to scan for scene files
#
SCENES_DIR="C:\\Program Files\\Autodesk\\Softimage 2013 SP1\\Data\\XSI_SAMPLES\\Scenes\\OLD"
SCRIPT="test1.pys"

for o,p in opts:
  if o in ['-d','--dir']:
     SCENES_DIR = p
  elif o in ['-s','--script']:
     SCRIPT = p

#
# Generator function for finding files
#
def find_files(directory, pattern):
     for root, dirs, files in os.walk(directory):
         for basename in files:
             if fnmatch.fnmatch(basename, pattern):
                 filename = os.path.join(root, basename)
                 yield filename

#
# Open each scene file and run the specified script
#
for scn in find_files(SCENES_DIR, '*.scn'):
	sXsiBatch = "%s\\xsibatch" % XSI_BINDIR
	subprocess.call( [ sXsiBatch, '-processing', '-script', SCRIPT, '-args', '-sSceneName', scn ] )

Softimage script test.pys:
A simple test script to run with xsibatch. Note that because the function is named “main”, I don’t have to specify that on the xsibatch command line. I just have to specify the arguments.

def main( sSceneName ):
	LogMessage( sSceneName )