Finding materials used by a model

Here’s one way to get the materials used by model. Note that this will also get any materials applied to clusters.


def get_mdl_materials( m ):
	from win32com.client import constants as c
	return m.FindObjects( c.siMaterialID )

Application.GetPresetModel("Man_Character", "Man_Character", "", "Character.Character_Designer")
for m in get_mdl_materials( si.Dictionary.GetObject( 'Man_Character' ) ):
	print m

And here’s an old-school way that uses a couple of string expressions:

mdl = si.Dictionary.GetObject( 'Man_Character' )

import win32com.client
mats = win32com.client.Dispatch( "XSI.Collection" )
mats.Items = '{0}.{1},{0}.{2}'.format(mdl.Name, "*.cls.*.material", "*.material")

for m in mats:
	print (m)

Getting the DataArray2D for the Materials ICE attribute

Here’s the Python way:

Application.SelectObj("Pedestrian_Mesh.Actor_Copies", None, None);
o = Application.Selection(0)

a = o.ActivePrimitive.Geometry.GetICEAttributeFromName("Materials")
print len(a.DataArray2D)
print len(a.DataArray2D[0] )
print a.DataArray2D[0][0]
for s in a.DataArray2D[0][0]:
    print s

# 1
# 1
# (u'', u'Sources.Materials.PedestrianLib.Shoes', u'Sources.Materials.PedestrianLib.Hair', u'Sources.Materials.PedestrianLib.Legs', u'Sources.Materials.PedestrianLib.Skin', u'Sources.Materials.PedestrianLib.Shirt')
# Sources.Materials.PedestrianLib.Shoes
# Sources.Materials.PedestrianLib.Hair
# Sources.Materials.PedestrianLib.Legs
# Sources.Materials.PedestrianLib.Skin
# Sources.Materials.PedestrianLib.Shirt

And here’s how to do it in JScript:

o = Selection(0);

a = o.ActivePrimitive.Geometry.GetICEAttributeFromName("Materials");

x = new VBArray( a.DataArray2D ).toArray();
y = new VBArray( x[0] ).toArray();
for ( var i = 0; i < y.length; i++ )
    LogMessage( y[i] )

Getting a list of all shaders in a render tree

Here’s a Python snippet that gets all the shaders in the render tree for a specific material. As usual, I always feel that my Python snippet could be made more pythonic; for now, this will have to do…

PS The Shader reference page has a VBScript example, but that doesn’t work anymore because it was written before ShaderParameters were introduced.

from sipyutils import si		# win32com.client.Dispatch('XSI.Application')

import win32com.client
coll = win32com.client.Dispatch( "XSI.Collection" )

def doit( s, coll ):

	for p in s.Parameters:
		if p.Source and p.Source.IsClassOf( C.siShaderParameterID ):
			print p.Source.Parent.Name
			coll.Add( p.Source.Parent )
			doit( p.Source.Parent, coll )
	for l in s.TextureLayers:
		for y in l.Parameters:
			if y.Source and y.Source.IsClassOf( C.siShaderParameterID ):
				print y.Source.Parent.Name
				coll.Add( y.Source.Parent )
				doit( y.Source.Parent, coll )

# Get a material or shader to use as a starting point
mat = si.Dictionary.GetObject("Sources.Materials.DefaultLib.Architectural")
doit( mat, coll )

coll.Unique = True
coll.Add( mat.AllImageClips.GetAsText() )

This snippet worked for this [nonsensical test] render tree:

Checking if a material is being used by somebody anybody

If you want to know whether a material is used by any objects in the scene, you can check the UsedBy property.

Here’s a Python snippet that finds unused materials in the current material library:

from siutils import si

if Application.Version().split('.')[0]>= "11":
	si = si()					# win32com.client.Dispatch('XSI.Application')

from siutils import log		# LogMessage
from siutils import disp	# win32com.client.Dispatch
from siutils import C		# win32com.client.constants

matlib = si.ActiveProject.ActiveScene.ActiveMaterialLibrary
for mat in matlib.Items:
	if mat.UsedBy.Count == 0:
		log( '%s <Not used>' % mat.Name )