<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Softimage Blog &#187; Programming / Scripting</title>
	<atom:link href="http://www.softimageblog.com/archives/category/scripting/feed" rel="self" type="application/rss+xml" />
	<link>http://www.softimageblog.com</link>
	<description>People and thoughts behind Softimage in production...</description>
	<lastBuildDate>Mon, 21 Jun 2010 20:40:48 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Two Undocumented Lip sync commands in Softimage 2011 SP1</title>
		<link>http://www.softimageblog.com/archives/517#utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=two-undocumented-lip-sync-commands-in-softimage-2011-sp1</link>
		<comments>http://www.softimageblog.com/archives/517#comments</comments>
		<pubDate>Mon, 21 Jun 2010 20:40:48 +0000</pubDate>
		<dc:creator>Luc-Eric</dc:creator>
				<category><![CDATA[Animation]]></category>
		<category><![CDATA[JScript]]></category>

		<guid isPermaLink="false">http://www.softimageblog.com/?p=517</guid>
		<description><![CDATA[In 2011 SP1, there are three new commands to get Face Robot lip sync data out into your own tools.  One of them doesn't even require the use of Face Robot and calls the speech recognition library directly]]></description>
			<content:encoded><![CDATA[<p>Hi there! It&#8217;s been a while..</p>
<p>In Softimage 2010, a new lip sync feature was added to Face Robot (here&#8217;s the <a href="http://softimage.wiki.softimage.com/xsidocs/dp888102.htm">doc</a>).  In 2011 SP1, there are three new commands to get the data out into your own tools.  One of them doesn&#8217;t even require the use of Face Robot and  calls the speech recognition library directly.</p>
<p>The commands return VBScript-compatible multi-dimensional arrays.    This is transparent in VBScript and Python, but it requires a bit of magic in JScript, so check the example in the first command if that&#8217;s what you&#8217;re using.</p>
<h2><strong>Getting Phonemes without Face Robot</strong></h2>
<h2>SIExtractPhonemes</h2>
<h3>Description</h3>
<div>
Extracts phonemes from an audio file using a text to guide the recognition</p>
</div>
<h3>Scripting Syntax</h3>
<div>
<table>
<tbody>
<tr>
<td>
<pre>oReturn = SIExtractPhonemes( Language, FileName, GuideText );</pre>
</td>
</tr>
</tbody>
</table>
</div>
<h3>Return Value</h3>
<div>
<p>Returns a multi-dimentional array of results. Each column will contain</p>
<p>1) The Unicode IPA code of the phoneme</p>
<p>2) The Start Time of the  phoneme, in seconds</p>
<p>3) The End Time of the phoneme, in seconds</p>
<p>4)  A human-readable hint of phoneme, useful for debugging</p>
</div>
<h3>Parameters</h3>
<div>
<table cellspacing="5" cellpadding="5">
<tbody>
<tr>
<th>Parameter</th>
<th>Type</th>
<th>Description</th>
</tr>
<tr>
<td>Language</td>
<td><a href="http://softimage.wiki.softimage.com/sdkdocs/String.htm">String</a></td>
<td>Language to use. &#8220;en&#8221; for English, or &#8220;jp&#8221; for Japanese</td>
</tr>
<tr>
<td>FileName</td>
<td><a href="http://softimage.wiki.softimage.com/sdkdocs/String.htm">String</a></td>
<td>Path to an audio file, for example a .wav or an .avi file. Mono and 16000k  is recommend. Same audio formats as Audio in Softimage; MP3 not supported.</td>
</tr>
<tr>
<td>GuideText</td>
<td><a href="http://softimage.wiki.softimage.com/sdkdocs/String.htm">String</a></td>
<td>Text that match the spoken words in the audio file. Avoid any unusual  punctuations or strange characters that may throw off the engine</td>
</tr>
</tbody>
</table>
</div>
<h3>Examples</h3>
<div>
<h4>JScript Example</h4>
<div>
<table>
<tbody>
<tr>
<td>
<pre>//returns a VBArray object, which require using the .getItem method in Jscript because they are not
//native objects there.
//However, they work transparently like multi-dimentionnal arrays in VBscript and Python
var res = SIExtractPhonemes ("en", "s:\\here_be_dragons.wav", "Here be dragons, the map says");
arraysize = res.ubound( 1 );
logmessage( arraysize + "phonemes found" );
for (  i=0; i &lt; arraysize; i++)
{
logmessage( "IPA#" + res.getItem(i,0)
         + "(" + res.getItem(i,3) + ") "
         + "Start Time(sec) " + res.getItem(i,1)
         + "End Time(sec) " + res.getItem(i,2) );
}</pre>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<p><strong><br />
</strong></p>
<h2><strong>Getting Lip Sync Stuff Out of Face Robot</strong></h2>
<p>This allows the artists to tweak the phonemes with the Face Robot UI, but used the data outside of Face Robot, perhaps in a game engine that does phoneme blending already.</p>
<p>The second command even allows you to get the result of the blend algorithm of Face Robot, so you can make a simplified playback environment.</p>
<h2>GetPhonemeFromSpeechClip</h2>
<h3>Description</h3>
<div>
<p>Returns the data of the Face Robot speech operator, as shown on the tracks of  in the Lip Sync view. The data starts at time zero, and needs to be offsetted by  the offset of the Speech Clip.</p>
</div>
<h3>Scripting Syntax</h3>
<div>
<table>
<tbody>
<tr>
<td>
<pre>oReturn = GetPhonemeFromSpeechClip( SpeechClip );</pre>
</td>
</tr>
</tbody>
</table>
</div>
<h3>Return Value</h3>
<div>
<p>Returns a multi-dimentional array of results. Each column will contain</p>
<p>1) The Unicode IPA code of the phoneme</p>
<p>2) The Start Time of the  phoneme, in seconds</p>
<p>3) The End Time of the phoneme, in seconds</p>
<p>4)  A human-readable hint of phoneme, useful for debugging</p>
<p>5) weight for this  phoneme</p>
<p>6) in falloff for this phoneme</p>
<p>7) out falloff for this  phoneme</p>
<p>8) shape weight for this phoneme</p>
<p>9) shape in falloff for  this phoneme</p>
<p>10) shape out falloff for this phoneme</p>
<p>11) blend  start scale factor</p>
<p>12) blend end scale factor</p>
<p>13) phoneme  variation</p>
</div>
<h3>Parameters</h3>
<div>
<table cellspacing="5" cellpadding="5">
<tbody>
<tr>
<th>Parameter</th>
<th>Type</th>
<th>Description</th>
</tr>
<tr>
<td>SpeechClip</td>
<td><a href="http://softimage.wiki.softimage.com/sdkdocs/String.htm">String</a></td>
<td>The Speech Clip from the animation mixer</td>
</tr>
</tbody>
</table>
</div>
<h3>Examples</h3>
<div>
<h4>VBScript Example</h4>
<div>
<table>
<tbody>
<tr>
<td>
<pre>phonemes = GetPhonemesFromSpeechClip ("Face.Mixer.Phoneme_Speech.SpeechAction_Clip")
LogMessage "phoneme data"
for i = 0 to UBound( phonemes )
	LogMessage "IPA # " &amp; phonemes(i, 0) &amp; "(" &amp; phonemes(i, 3) &amp; ")" &amp; " Start (sec)" &amp; phonemes(i, 1) &amp; " End (sec)" &amp; phonemes(i, 2)
next
</pre>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<h2>GetPhonemeBlendFromSpeechClip</h2>
<h3>Description</h3>
<div>
<p>Queries the Face Robot speech operator for the list of phonemes and weights  at a given time, as evaluated by its blend algorithm. At a given time there  generally is the current phoneme, as shown in the lipsync view, but also some of  the previous and the next one. With its different parameters, the speech  operator could evaluate a different blend for the lips, jaw and tongue.</p>
</div>
<h3>Scripting Syntax</h3>
<div>
<table>
<tbody>
<tr>
<td>
<pre>oReturn = GetPhonemeBlendFromSpeechClip( SpeechClip, [Channel], [Time] );</pre>
</td>
</tr>
</tbody>
</table>
</div>
<h3>Return Value</h3>
<div>
<p>Returns a multi-dimentional array of results. Each column will contain</p>
<p>1) The Unicode IPA code of the phoneme. Value zero is the rest pose</p>
<p>2) A human-readable hint of phoneme, useful for debugging</p>
<p>3) The  weight of the viseme at this time</p>
<p>4) The viseme variation selected by the  user</p>
</div>
<h3>Parameters</h3>
<div>
<table cellspacing="5" cellpadding="5">
<tbody>
<tr>
<th>Parameter</th>
<th>Type</th>
<th>Description</th>
</tr>
<tr>
<td>SpeechClip</td>
<td><a href="http://softimage.wiki.softimage.com/sdkdocs/String.htm">String</a></td>
<td>The Speech Clip from the animation mixer</td>
</tr>
<tr>
<td>Channel</td>
<td><a href="http://softimage.wiki.softimage.com/sdkdocs/Integer.htm">Integer</a></td>
<td>0 for Lips, 1 for Jaw, 2 for TongueDefault Value: 1</td>
</tr>
<tr>
<td>Time</td>
<td><a href="http://softimage.wiki.softimage.com/sdkdocs/Integer.htm">Integer</a></td>
<td>Frame at which to evaluate the blendDefault Value: Current frame.</td>
</tr>
</tbody>
</table>
</div>
<h3>Examples</h3>
<div>
<h4>VBScript Example</h4>
<div>
<table>
<tbody>
<tr>
<td>
<pre>phonemes = GetPhonemeBlendFromSpeechClip ("Face.Mixer.Phoneme_Speech.SpeechAction_Clip")
LogMessage "phoneme blend"
for i = 0 to UBound( phonemes )
	LogMessage "IPA # " &amp; phonemes(i, 0) &amp; "(" &amp; phonemes(i, 1) &amp; ")" &amp; " Weight " &amp; phonemes(i, 2 )
next</pre>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<img src="http://www.softimageblog.com/?ak_action=api_record_view&id=517&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.softimageblog.com/archives/517/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Slickening up the build cycle for compiled plugins</title>
		<link>http://www.softimageblog.com/archives/268#utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=slickening-up-the-build-cycle-for-compiled-plugins</link>
		<comments>http://www.softimageblog.com/archives/268#comments</comments>
		<pubDate>Thu, 19 Jun 2008 11:16:24 +0000</pubDate>
		<dc:creator>Kim Aldis</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Programming / Scripting]]></category>

		<guid isPermaLink="false">http://www.xsi-blog.com/?p=268</guid>
		<description><![CDATA[1. compile with copy, 2. oops, error, file in use, 3. switch to XSI, 4. dig down and unload plugin, 5. switch to VS, 6. compile &#8230;&#8230;. yaddda &#8230;.. you know the drill. 
For years I&#8217;ve been doing this and for years I&#8217;ve been meaning to get around to making it slicker but somehow there [...]]]></description>
			<content:encoded><![CDATA[<p>1. compile with copy, 2. oops, error, file in use, 3. switch to XSI, 4. dig down and unload plugin, 5. switch to VS, 6. compile &#8230;&#8230;. yaddda &#8230;.. you know the drill. </p>
<p>For years I&#8217;ve been doing this and for years I&#8217;ve been meaning to get around to making it slicker but somehow there was never time. So the other day it rained &#8211; fit to burst &#8211; and I had a day inside with nothing else to do and this is what I ended up with.</p>
<p>Earlier attempts ended up in a puddle on the floor because for some reason the only links I could find to VSS command line building pointed me at VCBuild.exe, which is just a plain old mess. This time, though, I found a link to a list of command line options for devenv.exe &#8211; what you run to bring up the VS IDE &#8211; at the excelent <a href="http://www.codeproject.com/KB/dotnet/builditemincontextmenu.aspx">codeproject.com</a> and these are much more straightforward.</p>
<p>The process is fairly simple: </p>
<p>1. unload the plugin.<br />
2. run a command line build using system()<br />
3. copy over the dll (my build has this built in)<br />
4. reload the plugin.<br />
5. test<br />
6. package</p>
<p>Step 2 involves a little bit of wrastling with .bat command line, um, features but really the code (at the end of this article) is quite simple. Because it&#8217;s scripted you can build entire plugin sets and package them in one go. The whole process takes only seconds because it&#8217;s self contained and it&#8217;s dead easy to stuff in some test code. You can easily slip back to the IDE when you need it and it makes working with a preferred text editor easier if that&#8217;s your bag.</p>
<p>There&#8217;s also the advantage that the build inherits the paths to libraries from the XSI version you&#8217;re working with. No more .bat file wrappers. Neat!</p>
<p>This example code is just a list of functions:</p>
<p>Build( solutionName, PluginName, forceRebuild   ); // do the actual build.<br />
GetConfig(); //gets the platform type (32/64)<br />
Package(  PluginName );  // package. Output name is hard coded in the example. </p>
<p>I stuff the plugin names in an array so I can build a bunch of them in one.</p>
<p>I also have a custom property I use with a dropdown list of my main projects along with build and package buttons.</p>
<p>And finally, I figure I might, next time it rains, get this working alongside package location. Who knows.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
</pre></td><td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">var</span> sPlugins <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">new</span> Array<span style="color: #009900;">&#40;</span> <span style="color: #3366CC;">&quot;TinyCurveExtrude&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;TinyCap&quot;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> slnName <span style="color: #339933;">=</span> sPlugins<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> sPluginName <span style="color: #339933;">=</span> slnName <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot;Plugin&quot;</span><span style="color: #339933;">;</span>
&nbsp;
Build<span style="color: #009900;">&#40;</span> slnName<span style="color: #339933;">,</span> sPluginName<span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">false</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">Package</span><span style="color: #009900;">&#40;</span> sPluginName <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// build the solution. doRebuild is a boolean, forces a complete compile and build if true.</span>
<span style="color: #006600; font-style: italic;">//</span>
<span style="color: #003366; font-weight: bold;">function</span> Build<span style="color: #009900;">&#40;</span> slnName<span style="color: #339933;">,</span> sPluginName<span style="color: #339933;">,</span> doRebuild <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #003366; font-weight: bold;">var</span> oPlugin <span style="color: #339933;">=</span> Application.<span style="color: #660066;">Plugins</span><span style="color: #009900;">&#40;</span> sPluginName <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #003366; font-weight: bold;">var</span> sPluginFileName <span style="color: #339933;">=</span> oPlugin.<span style="color: #660066;">FileName</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #339933;">!</span>oPlugin <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		logmessage<span style="color: #009900;">&#40;</span> <span style="color: #3366CC;">&quot;Can't find plugin to unload: &quot;</span> <span style="color: #339933;">+</span> sPluginName<span style="color: #339933;">,</span> siError <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #000066; font-weight: bold;">return</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	Logmessage<span style="color: #009900;">&#40;</span> <span style="color: #3366CC;">&quot;Unloading Plugin &quot;</span> <span style="color: #339933;">+</span> sPluginFileName <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>	
	Application.<span style="color: #660066;">UnloadPlugin</span><span style="color: #009900;">&#40;</span> sPluginFileName <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #003366; font-weight: bold;">var</span> Cmd <span style="color: #339933;">=</span> BuildCmdRoot<span style="color: #009900;">&#40;</span> slnName <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #003366; font-weight: bold;">var</span> sConfig <span style="color: #339933;">=</span> GetConfig<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #003366; font-weight: bold;">var</span> sOpt <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>doRebuild<span style="color: #009900;">&#41;</span> <span style="color: #339933;">?</span> <span style="color: #3366CC;">&quot; /rebuild &quot;</span> <span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot; /build &quot;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span> sConfig <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		system<span style="color: #009900;">&#40;</span> Cmd <span style="color: #339933;">+</span> sOpt <span style="color: #339933;">+</span> sConfig <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot; &amp;amp; pause&quot;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
		Logmessage<span style="color: #009900;">&#40;</span> <span style="color: #3366CC;">&quot;Build Failed&quot;</span><span style="color: #339933;">,</span> siError <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	LogMessage<span style="color: #009900;">&#40;</span> <span style="color: #3366CC;">&quot;ReLoading Plugin: &quot;</span> <span style="color: #339933;">+</span> sPluginFileName <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	Application.<span style="color: #660066;">LoadPlugin</span><span style="color: #009900;">&#40;</span> sPluginFileName <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #009900;">&#125;</span> 
<span style="color: #006600; font-style: italic;">// get the platform type, 32 or 64 bit. Release is hard coded</span>
<span style="color: #006600; font-style: italic;">//</span>
<span style="color: #003366; font-weight: bold;">function</span> GetConfig<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #003366; font-weight: bold;">var</span> sPlatform <span style="color: #339933;">=</span> Application.<span style="color: #660066;">Platform</span><span style="color: #339933;">;</span>
	Logmessage<span style="color: #009900;">&#40;</span> sPlatform <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span> sPlatform.<span style="color: #660066;">match</span><span style="color: #009900;">&#40;</span> <span style="color: #009966; font-style: italic;">/win64/i</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span> <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #3366CC;">&quot;<span style="color: #000099; font-weight: bold;">\&quot;</span>Release x64|x64<span style="color: #000099; font-weight: bold;">\&quot;</span>&quot;</span><span style="color: #339933;">;</span>
	<span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span> sPlatform.<span style="color: #660066;">match</span><span style="color: #009900;">&#40;</span> <span style="color: #009966; font-style: italic;">/win32/i</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span> <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #3366CC;">&quot;<span style="color: #000099; font-weight: bold;">\&quot;</span>Release|Win32<span style="color: #000099; font-weight: bold;">\&quot;</span>&quot;</span><span style="color: #339933;">;</span>
&nbsp;
	Logmessage<span style="color: #009900;">&#40;</span> <span style="color: #3366CC;">&quot;Unsupported Platform: &quot;</span> <span style="color: #339933;">+</span> sPlatform<span style="color: #339933;">,</span> siError <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #000066; font-weight: bold;">return</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// build the devenv.ex command line</span>
<span style="color: #006600; font-style: italic;">// NOTE: this is set to work on a 64 bit system. Take out the (x86) and spaces </span>
<span style="color: #006600; font-style: italic;">// for 32 bit. Cross compile works well enough but you'll need the 64 bit libs</span>
<span style="color: #003366; font-weight: bold;">function</span> BuildCmdRoot<span style="color: #009900;">&#40;</span> sTargetName <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #003366; font-weight: bold;">var</span> slnRoot <span style="color: #339933;">=</span> <span style="color: #3366CC;">&quot;c:<span style="color: #000099; font-weight: bold;">\\</span>fatty<span style="color: #000099; font-weight: bold;">\\</span>DEV<span style="color: #000099; font-weight: bold;">\\</span>CPP&quot;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #003366; font-weight: bold;">var</span> vcVars <span style="color: #339933;">=</span> <span style="color: #3366CC;">&quot;call <span style="color: #000099; font-weight: bold;">\&quot;</span>C:<span style="color: #000099; font-weight: bold;">\\</span>Program Files (x86)<span style="color: #000099; font-weight: bold;">\\</span>Microsoft Visual Studio 8<span style="color: #000099; font-weight: bold;">\\</span>VC<span style="color: #000099; font-weight: bold;">\\</span>vcvarsall.bat<span style="color: #000099; font-weight: bold;">\&quot;</span> x86&quot;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #003366; font-weight: bold;">var</span> slnPath <span style="color: #339933;">=</span> slnRoot <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot;<span style="color: #000099; font-weight: bold;">\\</span>&quot;</span> <span style="color: #339933;">+</span> sTargetName <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot;<span style="color: #000099; font-weight: bold;">\\</span>&quot;</span> <span style="color: #339933;">+</span> sTargetName <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot;.sln&quot;</span>
	<span style="color: #003366; font-weight: bold;">var</span> Cmd <span style="color: #339933;">=</span> vcVars <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot; &amp;amp; devenv &quot;</span> <span style="color: #339933;">+</span> slnPath<span style="color: #339933;">;</span>
	<span style="color: #000066; font-weight: bold;">return</span> Cmd<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// Package.</span>
<span style="color: #006600; font-style: italic;">// ToDo: rebuild for package location.</span>
<span style="color: #006600; font-style: italic;">//</span>
<span style="color: #003366; font-weight: bold;">function</span> <span style="color: #003366; font-weight: bold;">Package</span><span style="color: #009900;">&#40;</span> sPluginName <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	logmessage<span style="color: #009900;">&#40;</span> <span style="color: #3366CC;">&quot;Packaging ... &quot;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #003366; font-weight: bold;">var</span> sOutputPath <span style="color: #339933;">=</span> <span style="color: #3366CC;">&quot;C:/Fatty/Dev/CPP/Release&quot;</span>
&nbsp;
	<span style="color: #003366; font-weight: bold;">var</span> sPlatform <span style="color: #339933;">=</span> Application.<span style="color: #660066;">Platform</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #003366; font-weight: bold;">var</span> oPlugin <span style="color: #339933;">=</span> Application.<span style="color: #660066;">Plugins</span><span style="color: #009900;">&#40;</span> sPluginName <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #003366; font-weight: bold;">var</span> sPluginFileName <span style="color: #339933;">=</span> oPlugin.<span style="color: #660066;">FileName</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #003366; font-weight: bold;">var</span> oAddOn <span style="color: #339933;">=</span> Application.<span style="color: #660066;">CreateAddon</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	oAddOn.<span style="color: #660066;">AddItem</span><span style="color: #009900;">&#40;</span> siPluginAddonItemType<span style="color: #339933;">,</span> oPlugin.<span style="color: #660066;">FileName</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	oAddOn.<span style="color: #660066;">DefaultInstallationPath</span> <span style="color: #339933;">=</span> siUserAddonPath<span style="color: #339933;">;</span>
	oAddOn.<span style="color: #660066;">SubDirectory</span> <span style="color: #339933;">=</span> sPluginName<span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #003366; font-weight: bold;">var</span> sPluginFileName <span style="color: #339933;">=</span> sOutputPath <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot;/&quot;</span> <span style="color: #339933;">+</span> sPluginName <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot;_&quot;</span> <span style="color: #339933;">+</span> sPlatform <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot;.xsiaddon&quot;</span>
&nbsp;
	oAddOn.<span style="color: #660066;">Save</span><span style="color: #009900;">&#40;</span> sPluginFileName <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	logmessage<span style="color: #009900;">&#40;</span> <span style="color: #3366CC;">&quot;Packaged to: &quot;</span> <span style="color: #339933;">+</span> sPluginFileName  <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<img src="http://www.softimageblog.com/?ak_action=api_record_view&id=268&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.softimageblog.com/archives/268/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Dynamic Callbacks In Plugins</title>
		<link>http://www.softimageblog.com/archives/265#utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=dynamic-callbacks-in-plugins</link>
		<comments>http://www.softimageblog.com/archives/265#comments</comments>
		<pubDate>Thu, 12 Jun 2008 01:12:46 +0000</pubDate>
		<dc:creator>Patrick Boucher</dc:creator>
				<category><![CDATA[Plugins]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.xsi-blog.com/?p=265</guid>
		<description><![CDATA[I really like applications that provide rich SDKs for it&#8217;s users to play around with. I also like event based systems and callbacks. These are all things that make me absolutely love writing up plugins inside XSI. But there is one small problem, I find, with XSI&#8217;s callbacks.
Callbacks in XSI plugins are functions in the [...]]]></description>
			<content:encoded><![CDATA[<p>I really like applications that provide rich SDKs for it&#8217;s users to play around with. I also like event based systems and callbacks. These are all things that make me absolutely love writing up plugins inside XSI. But there is one small problem, I find, with XSI&#8217;s callbacks.</p>
<p>Callbacks in XSI plugins are functions in the global scope who&#8217;s name must be defined exactly the way XSI expects to find them.</p>
<p>I would have preferred callbacks to be supplied by the user in a way that allows them to have any name and in a way that allows them to be changed on the fly. In all fairness, Softimage probably has some very good reasons for the way they did things.</p>
<p>So this is where we, as users, exploit the power that has been given to us and take things into our own hands. Here is my implementation of dynamic, interchangeable, replaceable callbacks.</p>
<p><span id="more-265"></span><strong>Code Time!</strong></p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> win32com.<span style="color: black;">client</span>
<span style="color: #ff7700;font-weight:bold;">from</span> win32com.<span style="color: black;">client</span> <span style="color: #ff7700;font-weight:bold;">import</span> constants <span style="color: #ff7700;font-weight:bold;">as</span> c
<span style="color: #ff7700;font-weight:bold;">from</span> vg.<span style="color: black;">xsi</span>.<span style="color: black;">dynamic</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> XSILoadPlugin<span style="color: black;">&#40;</span> in_reg <span style="color: black;">&#41;</span>:
	in_reg.<span style="color: black;">Author</span> = <span style="color: #483d8b;">&quot;Patrick Boucher&quot;</span>
	in_reg.<span style="color: black;">Name</span> = <span style="color: #483d8b;">&quot;dynCbCommandPlugin&quot;</span>
	in_reg.<span style="color: black;">Major</span> = <span style="color: #ff4500;">1</span>
	in_reg.<span style="color: black;">Minor</span> = <span style="color: #ff4500;">0</span>
	in_reg.<span style="color: black;">RegisterCommand</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;dynCbCommand&quot;</span>, <span style="color: #483d8b;">&quot;dynCbCommand&quot;</span><span style="color: black;">&#41;</span>
	<span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">True</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> XSIUnloadPlugin<span style="color: black;">&#40;</span> in_reg <span style="color: black;">&#41;</span>:
	strPluginName = in_reg.<span style="color: black;">Name</span>
	Application.<span style="color: black;">LogMessage</span><span style="color: black;">&#40;</span><span style="color: #008000;">str</span><span style="color: black;">&#40;</span>strPluginName<span style="color: black;">&#41;</span> + <span style="color: #008000;">str</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot; has been unloaded.&quot;</span><span style="color: black;">&#41;</span>,c.<span style="color: black;">siVerbose</span><span style="color: black;">&#41;</span>
	<span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">True</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> dynCbCommand_Init<span style="color: black;">&#40;</span> in_ctxt <span style="color: black;">&#41;</span>:
	oCmd = in_ctxt.<span style="color: black;">Source</span>
	oCmd.<span style="color: black;">Description</span> = <span style="color: #483d8b;">&quot;&quot;</span>
	oCmd.<span style="color: black;">ReturnValue</span> = <span style="color: #008000;">True</span>
	<span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">True</span>
&nbsp;
@dynamic
<span style="color: #ff7700;font-weight:bold;">def</span> dynCbCommand_Execute<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
	Application.<span style="color: black;">LogMessage</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'In original callback!'</span><span style="color: black;">&#41;</span>
	setCallback<span style="color: black;">&#40;</span>dynCbCommand_Execute, callbackTwo<span style="color: black;">&#41;</span>
	<span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">True</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> callbackTwo<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
	Application.<span style="color: black;">LogMessage</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'In %s!'</span> <span style="color: #66cc66;">%</span> callback<span style="color: black;">&#40;</span>dynCbCommand_Execute<span style="color: black;">&#41;</span>.<span style="color: black;">func_name</span><span style="color: black;">&#41;</span>
	setCallback<span style="color: black;">&#40;</span>dynCbCommand_Execute, callbackThree<span style="color: black;">&#41;</span>
	<span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">True</span>	
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> callbackThree<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
	Application.<span style="color: black;">LogMessage</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'In callback three!'</span><span style="color: black;">&#41;</span>
	restoreCallback<span style="color: black;">&#40;</span><span style="color: #483d8b;">'dynCbCommand_Execute'</span><span style="color: black;">&#41;</span>
	<span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">True</span>	
&nbsp;
setCallback<span style="color: black;">&#40;</span>dynCbCommand_Execute, callbackTwo<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>The first time you run this command it will run the code in <code>callbackTwo</code> and switch itself to new code. The next time it will run <code>callbackThree</code> and the next time it will run the original callback code. It will then, with each consecutive invocation of the command, continue on in this loop. This plugin, as you have guessed, is just a demo of the dynamic callbacks.</p>
<p>The lines you have to concentrate on are the following:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> vg.<span style="color: black;">xsi</span>.<span style="color: black;">dynamic</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span></pre></div></div>

<p>and</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">@dynamic</pre></div></div>

<p>These are the lines that provide the core of the functionality which is imported from the <code>vg.xsi.dynamic</code> module. Here it is&#8230;</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">sys</span>
&nbsp;
__all__ = <span style="color: black;">&#91;</span><span style="color: #483d8b;">'dynamic'</span>, <span style="color: #483d8b;">'setCallback'</span>, <span style="color: #483d8b;">'callback'</span>, <span style="color: #483d8b;">'restoreCallback'</span><span style="color: black;">&#93;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> Wrapper<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, cb<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.__defaultCb = cb
        <span style="color: #008000;">self</span>.__cb = cb
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> call<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.__cb<span style="color: black;">&#40;</span><span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> setCallback<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, newCb<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.__cb = newCb
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> callback<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.__cb
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> restoreCallback<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.__cb = <span style="color: #008000;">self</span>.__defaultCb
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> dynamic<span style="color: black;">&#40;</span>func<span style="color: black;">&#41;</span>:
    cbWrap = Wrapper<span style="color: black;">&#40;</span>func<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> cbWrap.<span style="color: black;">call</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> setCallback<span style="color: black;">&#40;</span>bound, newCb<span style="color: black;">&#41;</span>:
    bound = _getCallable<span style="color: black;">&#40;</span>bound<span style="color: black;">&#41;</span>
    newCb = _getCallable<span style="color: black;">&#40;</span>newCb<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> bound.<span style="color: black;">im_self</span>.<span style="color: black;">setCallback</span><span style="color: black;">&#40;</span>newCb<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> callback<span style="color: black;">&#40;</span>bound<span style="color: black;">&#41;</span>:
    bound = _getCallable<span style="color: black;">&#40;</span>bound<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> bound.<span style="color: black;">im_self</span>.<span style="color: black;">callback</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> restoreCallback<span style="color: black;">&#40;</span>bound<span style="color: black;">&#41;</span>:
    bound = _getCallable<span style="color: black;">&#40;</span>bound<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> bound.<span style="color: black;">im_self</span>.<span style="color: black;">restoreCallback</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> _getCallable<span style="color: black;">&#40;</span>req<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">callable</span><span style="color: black;">&#40;</span>req<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> req
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">type</span><span style="color: black;">&#40;</span>req<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">str</span>:
        g = <span style="color: #dc143c;">sys</span>._getframe<span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>.<span style="color: black;">f_globals</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> g<span style="color: black;">&#91;</span>req<span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>I&#8217;ve removed any comments or docstrings for the sake of brevity.</p>
<p><strong>About Decorators</strong></p>
<p>The import line I said was of particular interest. Well it is but only in the sense that it will allow you to use the module in which the features are implemented&#8230; Moving on quickly.</p>
<p>The real fun is with the <code>@dynamic</code> decorator. What is a decorator and what happens when we use one (or this one in particular)? Before we look at what a decorator is and does, let&#8217;s look at what happens when we define a function.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> func<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span></pre></td></tr></table></div>

<p>When a function is defined, what is happening is that an identifier is created in your current scope and this identifier is given the name of your function. Now let&#8217;s add the decorator. A decorator is just a simple function, but a function who&#8217;s purpose is very specific and a function that must return a callable (another function most of the time).</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">@myDecorator
<span style="color: #ff7700;font-weight:bold;">def</span> func<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span></pre></td></tr></table></div>

<p>What happens here is that the identifier <code>func</code> is still created but what lies &#8216;in&#8217; this identifier is not the function itself but the result of passing said function to <code>myDecorator</code>. To help you visualize, the above code could just as easily been written like so:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> func<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span>
func = myDecorator<span style="color: black;">&#40;</span>func<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p><strong>Let&#8217;s Get Specific</strong></p>
<p>The decorator <code>@dynamic</code> takes your callback and wraps it inside a <code>Wrapper</code> object and returns the <code>call</code> method of this new object. When XSI tries to call what it thinks is just a simple callback it is actually calling the <code>call</code> method of an object that in turn calls your original callback. Whew!</p>
<p>This means that you now have the liberty of querying and editing the <em>callback object</em> and telling it to call something different depending on context. This functionality is provided by the <code>setCallback</code>, <code>callback</code> and <code>restoreCallback</code> functions.</p>
<p>These three functions either take the callback function objects or the callback&#8217;s names (as a string) as arguments.</p>
<p>There are some more particularities to this code such as the use of <code>sys._getframe</code>, the <code>im_self</code> attribute or the use of the <code>call</code> method on the <code>Wrapper</code> object instead of implementing <code>__call__</code> but I think they might be outside the scope of this article. If there are requests for it I can expand in the comments or another post.</p>
<p>Meanwhile you can <a href='http://www.xsi-blog.com/userContent/upload/2008/06/dynamiccallbacks.zip'>download the example</a>. Drop the plugin into a plugin folder (user, factory or workgroup) and drop the <em>vg</em> folder somewhere in your Python path.</p>
<p>Cheers!</p>
<img src="http://www.softimageblog.com/?ak_action=api_record_view&id=265&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.softimageblog.com/archives/265/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Object oriented programming, once again.</title>
		<link>http://www.softimageblog.com/archives/260#utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=object-oriented-programming-once-again</link>
		<comments>http://www.softimageblog.com/archives/260#comments</comments>
		<pubDate>Tue, 20 May 2008 14:32:24 +0000</pubDate>
		<dc:creator>Helge Mathee</dc:creator>
				<category><![CDATA[JScript]]></category>
		<category><![CDATA[Modeling]]></category>
		<category><![CDATA[Programming / Scripting]]></category>

		<guid isPermaLink="false">http://www.xsi-blog.com/?p=260</guid>
		<description><![CDATA[So the keen folks at the german XSI forum (http://www.xsiforum.de) discussed the topic of generating separate objects out of all of the polygon islands making up a polygonmesh. Even though this doesn&#8217;t seem to be a too tricky scripting problem, using commands to achieve this split-up can slow down XSI quite alot, especially if the [...]]]></description>
			<content:encoded><![CDATA[<p>So the keen folks at the german XSI forum (<a href="http://www.xsiforum.de">http://www.xsiforum.de</a>) discussed the topic of generating separate objects out of all of the polygon islands making up a polygonmesh. Even though this doesn&#8217;t seem to be a too tricky scripting problem, using commands to achieve this split-up can slow down XSI quite alot, especially if the source mesh contains a huge amount of polygon islands. Therefore I tried to come up with a object oriented solution, and here it is.<br />
<span id="more-260"></span></p>
<p>I put some effort into commenting the script accordingly, so that it may be used for learning purposes.</p>
<p>cheers!</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
</pre></td><td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// query the geometry data</span>
<span style="color: #003366; font-weight: bold;">var</span> obj <span style="color: #339933;">=</span> selection<span style="color: #009900;">&#40;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> geo <span style="color: #339933;">=</span> obj.<span style="color: #660066;">Activeprimitive</span>.<span style="color: #660066;">Geometry</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> polygons <span style="color: #339933;">=</span> geo.<span style="color: #660066;">Polygons</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// create an array to track which polygon has been visited</span>
<span style="color: #003366; font-weight: bold;">var</span> polygonVisited <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> polygonsLeft <span style="color: #339933;">=</span> polygons.<span style="color: #660066;">Count</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// fill up the array to say: &quot;no polygon has been visited yet&quot;</span>
<span style="color: #000066; font-weight: bold;">for</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i<span style="color: #339933;">=</span><span style="color: #CC0000;">0</span><span style="color: #339933;">;</span>i<span style="color: #339933;">&amp;</span>lt<span style="color: #339933;">;</span>polygons .<span style="color: #660066;">count</span><span style="color: #339933;">;</span>i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	polygonVisited<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// create some helper variables</span>
<span style="color: #003366; font-weight: bold;">var</span> clusterIndices <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> currentRow <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// log the start of the process</span>
logmessage<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;Starting with &quot;</span><span style="color: #339933;">+</span>polygonsLeft<span style="color: #339933;">+</span><span style="color: #3366CC;">&quot; polygons...&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// loop until there are no polygons left</span>
<span style="color: #006600; font-style: italic;">// or there are still items in the cluster array</span>
<span style="color: #000066; font-weight: bold;">while</span><span style="color: #009900;">&#40;</span>polygonsLeft <span style="color: #339933;">&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #CC0000;">0</span> <span style="color: #339933;">||</span> clusterIndices.<span style="color: #660066;">length</span> <span style="color: #339933;">&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	<span style="color: #006600; font-style: italic;">// if there are no items in the next row...</span>
	<span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>currentRow.<span style="color: #660066;">length</span> <span style="color: #339933;">==</span> <span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		<span style="color: #006600; font-style: italic;">// if there are items in the cluster index array</span>
		<span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>clusterIndices.<span style="color: #660066;">length</span> <span style="color: #339933;">&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span>
		<span style="color: #009900;">&#123;</span>
			<span style="color: #006600; font-style: italic;">// log the creation of the cluster</span>
			logmessage<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;Creating cluster with &quot;</span><span style="color: #339933;">+</span>clusterIndices.<span style="color: #660066;">length</span><span style="color: #339933;">+</span><span style="color: #3366CC;">&quot; elements...&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
			<span style="color: #006600; font-style: italic;">// create a new mesh containing all of these polygons</span>
			<span style="color: #006600; font-style: italic;">// first, create an array containing all pointindices</span>
			<span style="color: #006600; font-style: italic;">// and two additional point hash arrays</span>
			<span style="color: #006600; font-style: italic;">// of which one is used to determine if a point is already used</span>
			<span style="color: #006600; font-style: italic;">// and the second one is used to map the original index to the new one</span>
			<span style="color: #003366; font-weight: bold;">var</span> pointIndices <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
			<span style="color: #003366; font-weight: bold;">var</span> pointUsed <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
			<span style="color: #003366; font-weight: bold;">var</span> pointNewIndex <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
&nbsp;
			<span style="color: #000066; font-weight: bold;">for</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i<span style="color: #339933;">=</span><span style="color: #CC0000;">0</span><span style="color: #339933;">;</span>i<span style="color: #339933;">&amp;</span>lt<span style="color: #339933;">;</span>clusterIndices.<span style="color: #660066;">length</span><span style="color: #339933;">;</span>i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
			<span style="color: #009900;">&#123;</span>
				<span style="color: #003366; font-weight: bold;">var</span> poly <span style="color: #339933;">=</span> polygons.<span style="color: #000066; font-weight: bold;">item</span><span style="color: #009900;">&#40;</span>clusterIndices<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
				<span style="color: #003366; font-weight: bold;">var</span> pointIndexArray <span style="color: #339933;">=</span> poly.<span style="color: #660066;">points</span>.<span style="color: #660066;">indexArray</span>.<span style="color: #660066;">toArray</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">//(VBS to JScript conversion)</span>
&nbsp;
				<span style="color: #006600; font-style: italic;">// loop through all points and check if it they are used</span>
				<span style="color: #000066; font-weight: bold;">for</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> j<span style="color: #339933;">=</span><span style="color: #CC0000;">0</span><span style="color: #339933;">;</span>j<span style="color: #339933;">&amp;</span>lt<span style="color: #339933;">;</span>pointIndexArray.<span style="color: #660066;">length</span><span style="color: #339933;">;</span>j<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
				<span style="color: #009900;">&#123;</span>
					<span style="color: #003366; font-weight: bold;">var</span> index <span style="color: #339933;">=</span> pointIndexArray<span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
					<span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>pointUsed<span style="color: #009900;">&#91;</span>index<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span>
					<span style="color: #009900;">&#123;</span>
						pointNewIndex<span style="color: #009900;">&#91;</span>index<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> pointIndices.<span style="color: #660066;">length</span><span style="color: #339933;">;</span>
						pointIndices.<span style="color: #660066;">push</span><span style="color: #009900;">&#40;</span>index<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
						pointUsed<span style="color: #009900;">&#91;</span>index<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">;</span>	
					<span style="color: #009900;">&#125;</span>
				<span style="color: #009900;">&#125;</span>
			<span style="color: #009900;">&#125;</span>
&nbsp;
			<span style="color: #006600; font-style: italic;">// now, create the array of the positions of all points of this island</span>
			<span style="color: #003366; font-weight: bold;">var</span> islandPos <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
			<span style="color: #000066; font-weight: bold;">for</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i<span style="color: #339933;">=</span><span style="color: #CC0000;">0</span><span style="color: #339933;">;</span>i<span style="color: #339933;">&amp;</span>lt<span style="color: #339933;">;</span>pointIndices.<span style="color: #660066;">length</span><span style="color: #339933;">;</span>i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
			<span style="color: #009900;">&#123;</span>
				<span style="color: #003366; font-weight: bold;">var</span> point <span style="color: #339933;">=</span> geo.<span style="color: #660066;">points</span>.<span style="color: #000066; font-weight: bold;">item</span><span style="color: #009900;">&#40;</span>pointIndices<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
				islandPos.<span style="color: #660066;">push</span><span style="color: #009900;">&#40;</span>point.<span style="color: #660066;">position</span>.<span style="color: #660066;">x</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
				islandPos.<span style="color: #660066;">push</span><span style="color: #009900;">&#40;</span>point.<span style="color: #660066;">position</span>.<span style="color: #660066;">y</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
				islandPos.<span style="color: #660066;">push</span><span style="color: #009900;">&#40;</span>point.<span style="color: #660066;">position</span>.<span style="color: #660066;">z</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #009900;">&#125;</span>
&nbsp;
			<span style="color: #006600; font-style: italic;">// now we need to create the description of the polygons</span>
			<span style="color: #003366; font-weight: bold;">var</span> islandPoly <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
			<span style="color: #006600; font-style: italic;">// for that we loop over the polygons of the island again</span>
			<span style="color: #006600; font-style: italic;">// and record their pointindices, well, actually the remapped</span>
			<span style="color: #006600; font-style: italic;">// indices (given by the pointNewIndex hash array)</span>
			<span style="color: #000066; font-weight: bold;">for</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i<span style="color: #339933;">=</span><span style="color: #CC0000;">0</span><span style="color: #339933;">;</span>i<span style="color: #339933;">&amp;</span>lt<span style="color: #339933;">;</span>clusterIndices.<span style="color: #660066;">length</span><span style="color: #339933;">;</span>i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
			<span style="color: #009900;">&#123;</span>
				<span style="color: #003366; font-weight: bold;">var</span> poly <span style="color: #339933;">=</span> polygons.<span style="color: #000066; font-weight: bold;">item</span><span style="color: #009900;">&#40;</span>clusterIndices<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
				<span style="color: #003366; font-weight: bold;">var</span> pointIndexArray <span style="color: #339933;">=</span> poly.<span style="color: #660066;">points</span>.<span style="color: #660066;">indexArray</span>.<span style="color: #660066;">toArray</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">//(VBS to JScript conversion)</span>
&nbsp;
				<span style="color: #006600; font-style: italic;">// first add the number of points of this polygon </span>
				<span style="color: #006600; font-style: italic;">// to this polygon's description</span>
				islandPoly.<span style="color: #660066;">push</span><span style="color: #009900;">&#40;</span>pointIndexArray.<span style="color: #660066;">length</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
				<span style="color: #006600; font-style: italic;">// now add the remapped index for each point to the description</span>
				<span style="color: #000066; font-weight: bold;">for</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> j<span style="color: #339933;">=</span><span style="color: #CC0000;">0</span><span style="color: #339933;">;</span>j<span style="color: #339933;">&amp;</span>lt<span style="color: #339933;">;</span>pointIndexArray.<span style="color: #660066;">length</span><span style="color: #339933;">;</span>j<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
				<span style="color: #009900;">&#123;</span>
					<span style="color: #003366; font-weight: bold;">var</span> index <span style="color: #339933;">=</span> pointIndexArray<span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
					islandPoly.<span style="color: #660066;">push</span><span style="color: #009900;">&#40;</span>pointNewIndex<span style="color: #009900;">&#91;</span>index<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
				<span style="color: #009900;">&#125;</span>
			<span style="color: #009900;">&#125;</span>
&nbsp;
			obj.<span style="color: #660066;">Parent</span>.<span style="color: #660066;">AddPolygonMesh</span><span style="color: #009900;">&#40;</span>islandPos<span style="color: #339933;">,</span>islandPoly<span style="color: #339933;">,</span>obj.<span style="color: #000066;">name</span><span style="color: #339933;">+</span><span style="color: #3366CC;">&quot;_island&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			clusterIndices <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
&nbsp;
			<span style="color: #006600; font-style: italic;">// if there are no polyons left we can stop now</span>
			<span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>polygonsLeft <span style="color: #339933;">==</span> <span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span>
				<span style="color: #000066; font-weight: bold;">break</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
&nbsp;
		<span style="color: #006600; font-style: italic;">// loop over the polygons and try to find </span>
		<span style="color: #006600; font-style: italic;">// one which hasn't been visited yet</span>
		<span style="color: #000066; font-weight: bold;">for</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i<span style="color: #339933;">=</span><span style="color: #CC0000;">0</span><span style="color: #339933;">;</span>i<span style="color: #339933;">&amp;</span>lt<span style="color: #339933;">;</span>polygons.<span style="color: #660066;">Count</span><span style="color: #339933;">;</span>i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
		<span style="color: #009900;">&#123;</span>
			<span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>polygonVisited<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span> <span style="color: #339933;">==</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span>
			<span style="color: #009900;">&#123;</span>
				currentRow.<span style="color: #660066;">push</span><span style="color: #009900;">&#40;</span>i<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
				clusterIndices.<span style="color: #660066;">push</span><span style="color: #009900;">&#40;</span>i<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
				polygonVisited<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">;</span>
				polygonsLeft<span style="color: #339933;">--;</span>
				<span style="color: #000066; font-weight: bold;">break</span><span style="color: #339933;">;</span>
			<span style="color: #009900;">&#125;</span>
		<span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #006600; font-style: italic;">// define the nextrow after the current row</span>
	<span style="color: #003366; font-weight: bold;">var</span> nextRow <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #006600; font-style: italic;">// loop over all items in the current row</span>
	<span style="color: #000066; font-weight: bold;">for</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i<span style="color: #339933;">=</span><span style="color: #CC0000;">0</span><span style="color: #339933;">;</span>i<span style="color: #339933;">&amp;</span>lt<span style="color: #339933;">;</span>currentRow.<span style="color: #660066;">length</span><span style="color: #339933;">;</span>i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		<span style="color: #003366; font-weight: bold;">var</span> polygon <span style="color: #339933;">=</span> polygons.<span style="color: #000066; font-weight: bold;">item</span><span style="color: #009900;">&#40;</span>currentRow<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #003366; font-weight: bold;">var</span> neighbors <span style="color: #339933;">=</span> polygon.<span style="color: #660066;">NeighborPolygons</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
		<span style="color: #006600; font-style: italic;">// loop through all of the neighbors and add them to the nextRow</span>
		<span style="color: #000066; font-weight: bold;">for</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> j<span style="color: #339933;">=</span><span style="color: #CC0000;">0</span><span style="color: #339933;">;</span>j<span style="color: #339933;">&amp;</span>lt<span style="color: #339933;">;</span>neighbors.<span style="color: #660066;">count</span><span style="color: #339933;">;</span>j<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
		<span style="color: #009900;">&#123;</span>
			<span style="color: #006600; font-style: italic;">// check if the neighbor has been</span>
			<span style="color: #006600; font-style: italic;">// visited yet</span>
			<span style="color: #003366; font-weight: bold;">var</span> neighbor <span style="color: #339933;">=</span> neighbors.<span style="color: #000066; font-weight: bold;">item</span><span style="color: #009900;">&#40;</span>j<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">index</span><span style="color: #339933;">;</span>
			<span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>polygonVisited<span style="color: #009900;">&#91;</span>neighbor<span style="color: #009900;">&#93;</span><span style="color: #339933;">==</span><span style="color: #003366; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span>
			<span style="color: #009900;">&#123;</span>
				<span style="color: #006600; font-style: italic;">// add the neighbor to the next row</span>
				nextRow.<span style="color: #660066;">push</span><span style="color: #009900;">&#40;</span>neighbor<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
				clusterIndices.<span style="color: #660066;">push</span><span style="color: #009900;">&#40;</span>neighbor<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
				polygonVisited<span style="color: #009900;">&#91;</span>neighbor<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">;</span>
				polygonsLeft<span style="color: #339933;">--;</span>
				<span style="color: #000066; font-weight: bold;">break</span><span style="color: #339933;">;</span>
			<span style="color: #009900;">&#125;</span>
		<span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	currentRow <span style="color: #339933;">=</span> nextRow<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
selection.<span style="color: #660066;">SetAsText</span><span style="color: #009900;">&#40;</span>obj.<span style="color: #000066;">name</span><span style="color: #339933;">+</span><span style="color: #3366CC;">&quot;_island*&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<img src="http://www.softimageblog.com/?ak_action=api_record_view&id=260&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.softimageblog.com/archives/260/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>A Shortcut For Your Shortcuts</title>
		<link>http://www.softimageblog.com/archives/256#utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=a-shortcut-for-your-shortcuts</link>
		<comments>http://www.softimageblog.com/archives/256#comments</comments>
		<pubDate>Thu, 03 Apr 2008 02:56:02 +0000</pubDate>
		<dc:creator>Patrick Boucher</dc:creator>
				<category><![CDATA[Bablings and Ramblings]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.xsi-blog.com/?p=256</guid>
		<description><![CDATA[When working with XSI in a facility I often use Python modules to better package my code and allow easy reuse of key parts in the different tools that are developed. These modules I usually keep in a location on the main drive of the workstations, for example: C:\&#60;facilityName&#62;\libs\python.
I&#8217;ll also put in place a system [...]]]></description>
			<content:encoded><![CDATA[<p>When working with XSI in a facility I often use Python modules to better package my code and allow easy reuse of key parts in the different tools that are developed. These modules I usually keep in a location on the main drive of the workstations, for example: C:\&lt;facilityName&gt;\libs\python.</p>
<p>I&#8217;ll also put in place a system to push central library changes to the local computers and insert the library location in the PYTHONPATH environment variable.</p>
<p>The <a href="http://softimage.wiki.avid.com">XSI Wiki</a> has a great page on the pros and cons of <a href="http://softimage.wiki.avid.com/index.php/Python_Custom_Modules_(XSISDK)">the module approach</a>. One of the cons is that the <code>Application</code> global variable is only accessible in your script files and plugin files and not in your modules.</p>
<p><span id="more-256"></span>In the past I would put the following code at the top of my various modules:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> win32com
<span style="color: #ff7700;font-weight:bold;">from</span> win32com.<span style="color: black;">client</span> <span style="color: #ff7700;font-weight:bold;">import</span> constants <span style="color: #ff7700;font-weight:bold;">as</span> c
xsi = win32com.<span style="color: black;">client</span>.<span style="color: black;">Dispatch</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'XSI.Application'</span><span style="color: black;">&#41;</span>.<span style="color: black;">Application</span>
log = xsi.<span style="color: black;">Logmessage</span></pre></td></tr></table></div>

<p>Following this would be a bunch of other shortcuts and dispatch commands for XSIUtils, XSIUIToolkit, XSIMath, etc&#8230;</p>
<p>Being tired of inserting these lines at the header of every module and a subset of this code (for shortcuts) at every script or plugin, I decided to centralize them and move them to their own module.</p>
<p>The library structure looks like so:</p>
<pre>../libpath/
    vg/
        xsi/
            __init__.py
            xsiModule1.py
            xsiModule2.py
            [...]</pre>
<p>In the <code>__init__.py</code> file I put the following code:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> win32com
<span style="color: #ff7700;font-weight:bold;">from</span> win32com.<span style="color: black;">client</span> <span style="color: #ff7700;font-weight:bold;">import</span> constants <span style="color: #ff7700;font-weight:bold;">as</span> c
xsi = win32com.<span style="color: black;">client</span>.<span style="color: black;">Dispatch</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'XSI.Application'</span><span style="color: black;">&#41;</span>.<span style="color: black;">Application</span>
log = xsi.<span style="color: black;">Logmessage</span>
<span style="color: #808080; font-style: italic;"># [... more shortcuts and dispatch commands ...]</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> getShortcuts<span style="color: black;">&#40;</span>g<span style="color: black;">&#41;</span>:
    g<span style="color: black;">&#91;</span><span style="color: #483d8b;">'win32com'</span><span style="color: black;">&#93;</span> = win32com
    g<span style="color: black;">&#91;</span><span style="color: #483d8b;">'c'</span><span style="color: black;">&#93;</span> = c
    g<span style="color: black;">&#91;</span><span style="color: #483d8b;">'xsi'</span><span style="color: black;">&#93;</span> = xsi
    g<span style="color: black;">&#91;</span><span style="color: #483d8b;">'log'</span><span style="color: black;">&#93;</span> = log
    <span style="color: #808080; font-style: italic;"># [... more shortcuts and dispatch commands scope transfers...]</span></pre></td></tr></table></div>

<p>This allows me to benefit from the shortcuts in the rest of the <code>__init__.py</code> file where some general XSI functions are kept but also start my other modules, scripts and plugins with the following two lines:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> vg.<span style="color: black;">xsi</span> <span style="color: #ff7700;font-weight:bold;">as</span> vx
vx.<span style="color: black;">getShortcuts</span><span style="color: black;">&#40;</span><span style="color: #008000;">globals</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>By providing the <code>getShortcuts</code> function with a dict representing the global scope of my module, script or plugin, the function can edit the members of the scope and give me all the necessary symbols.</p>
<p>Another stupid trick rears it&#8217;s head! ;)<br />
Happy scripting!</p>
<img src="http://www.softimageblog.com/?ak_action=api_record_view&id=256&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.softimageblog.com/archives/256/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Steven Caron, OBJ Files, Sexy Bits and Waste</title>
		<link>http://www.softimageblog.com/archives/249#utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=steven-caron-obj-files-sexy-bits-and-waste</link>
		<comments>http://www.softimageblog.com/archives/249#comments</comments>
		<pubDate>Sat, 01 Mar 2008 20:25:45 +0000</pubDate>
		<dc:creator>Patrick Boucher</dc:creator>
				<category><![CDATA[Bablings and Ramblings]]></category>
		<category><![CDATA[Modeling]]></category>
		<category><![CDATA[Plugins]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.xsi-blog.com/archives/249</guid>
		<description><![CDATA[What do all these things have in common?
The weird wirings in my brain. That&#8217;s what.
Back to the beginning
At the end of last October Steven Caron sent me a plugin he wrote that allows an XSI user to drag and drop .obj files into the interface and have them import automatically according to settings in a [...]]]></description>
			<content:encoded><![CDATA[<p>What do all these things have in common?</p>
<p>The weird wirings in my brain. That&#8217;s what.</p>
<p><strong>Back to the beginning</strong></p>
<p>At the end of last October Steven Caron sent me a <a href="http://www.xsi-blog.com/userContent/scaron/ObjDnD.xsiaddon">plugin</a> he wrote that allows an XSI user to drag and drop .obj files into the interface and have them import automatically according to settings in a custom preference. I was a bit swamped at the time putting up the infrastructure for a new VFX department at my new workplace. And then I totally forgot about it&#8230; Sorry Steven.</p>
<p>This past week Steven politely reminded me of my omission so I ran back to my email archives and installed it. Neat piece of work.</p>
<p>I didn&#8217;t want to just post up the tool as I don&#8217;t really see this blog being about tool distribution but about how said tools work and the neat tricks they use. With that philosophy in mind I cracked open Steven&#8217;s tool to dig out some of its sexier bits and maybe demystify them for the audience.</p>
<p>To my surprise there weren&#8217;t any sexy bits. Please don&#8217;t get me wrong, the tool works superbly, how much more intuitive can you get than drag and drop. The tool is also extremely well written, concise and straightforward. There just aren&#8217;t any weird tricks or convoluted syntax or things that would generally have you scratching your head.</p>
<p>Then I noticed this in his version trapping code (yes folks, the drag and drop event is new in XSI 6.5):</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>27
28
29
30
31
32
33
34
35
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">int</span><span style="color: black;">&#40;</span> tXSIVersion<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span> <span style="color: black;">&#41;</span> <span style="color: #66cc66;">&lt;</span> <span style="color: #ff4500;">6</span>:
    xsiPrint<span style="color: black;">&#40;</span> xsi.<span style="color: black;">Version</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> + <span style="color: #483d8b;">&quot; doesn't support the 'siOnDragAndDrop' event!&quot;</span> <span style="color: black;">&#41;</span>
    xsi.<span style="color: black;">UnloadPlugin</span><span style="color: black;">&#40;</span> in_reg.<span style="color: black;">name</span>, <span style="color: #008000;">True</span> <span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">False</span>
<span style="color: #ff7700;font-weight:bold;">else</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">int</span><span style="color: black;">&#40;</span> tXSIVersion<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> <span style="color: black;">&#41;</span> <span style="color: #66cc66;">&lt;</span> <span style="color: #ff4500;">5</span>:
        xsiPrint<span style="color: black;">&#40;</span> xsi.<span style="color: black;">Version</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> + <span style="color: #483d8b;">&quot; doesn't support the 'siOnDragAndDrop' event!&quot;</span> <span style="color: black;">&#41;</span>
        xsi.<span style="color: black;">UnloadPlugin</span><span style="color: black;">&#40;</span> in_reg.<span style="color: black;">name</span>, <span style="color: #008000;">True</span> <span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">False</span></pre></td></tr></table></div>

<p><span id="more-249"></span><b>About the waste part</b></p>
<p>Bare with me&#8230;</p>
<p>Last week I was reading a really neat <a href="http://www.wired.com/techbiz/it/magazine/16-03/ff_free">article</a> in <a href="http://www.wired.com">Wired</a> by Chris Anderson entitled <i>&#8220;Free! Why $0.00 Is the Future of Business&#8221;</i>. I invite you to read it, especially the section beginning on page two: <i>Waste and Waste Again</i>.</p>
<p>&#8230;So if in the seventies you had to be really tight with your algorithms and optimizations because cpu cycles were so scarce, today I guess we can really waste them. Just the other day I setup an 8 core MacPro with BootCamp, XP x64 and XSI. Whatever I did to the machine, I swear, I could hear it yawn because it was bored.</p>
<p>Which brings me back to Steven&#8217;s code. Could it have been written like so:</p>
</pre>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>27
28
29
30
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">int</span><span style="color: black;">&#40;</span> tXSIVersion<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span> <span style="color: black;">&#41;</span> <span style="color: #66cc66;">&lt;</span> <span style="color: #ff4500;">6</span> <span style="color: #ff7700;font-weight:bold;">or</span> <span style="color: #008000;">int</span><span style="color: black;">&#40;</span> tXSIVersion<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> <span style="color: black;">&#41;</span> <span style="color: #66cc66;">&lt;</span> <span style="color: #ff4500;">5</span>:
    xsiPrint<span style="color: black;">&#40;</span> xsi.<span style="color: black;">Version</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> + <span style="color: #483d8b;">&quot; doesn't support the 'siOnDragAndDrop' event!&quot;</span> <span style="color: black;">&#41;</span>
    xsi.<span style="color: black;">UnloadPlugin</span><span style="color: black;">&#40;</span> in_reg.<span style="color: black;">name</span>, <span style="color: #008000;">True</span> <span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">False</span></pre></td></tr></table></div>

<p>Is it more or less readable by a programmer?<br />
It probably executes in a few cycles less but is it worth it?<br />
Python is interpreted so if the parser goes through this version quicker, is it worty of any mention?<br />
Is it more maintainable?</p>
<p>This example is really simple but in a bigger project, or with more complex cases, should we really be worrying if today transistors and cpu cycles are so cheap as to not even matter anymore</p>
<p>When I'm stuck on a piece of code or when I hit that time of the afternoon where most of my energy is diverted to digesting, I'll often reread my code and tighten it, remove redundancy, put in functions instead of copying a few lines in two locations, consolidate <i>if</i> statements, etc... One of my colleagues used to tell me that <i>"Premature optimization is the root of all evil."</i></p>
<p>Honestly, if I look back at a good proportion of the code I have written, it either executes in a blink of an eye on today's computers or it sits there waiting 90% of the time for user interaction. Should we, as technical XSI users, XSI scripters or TDs, even worry about optimization from a performance standpoint or a maintainability standpoint? What can be considered a good optimization and what should be considered a bad one?</p>
<p>And now that you're really wondering what I'm rambling about, I'll shut up and let you <a href="http://www.xsi-blog.com/userContent/scaron/ObjDnD.xsiaddon">download Steven's addon</a>.</p>
<p>Have a good weekend.</pre>
<img src="http://www.softimageblog.com/?ak_action=api_record_view&id=249&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.softimageblog.com/archives/249/feed</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
		<item>
		<title>Scripting shaders</title>
		<link>http://www.softimageblog.com/archives/245#utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=scripting-shaders</link>
		<comments>http://www.softimageblog.com/archives/245#comments</comments>
		<pubDate>Fri, 10 Aug 2007 20:43:56 +0000</pubDate>
		<dc:creator>Bernard Lebel</dc:creator>
				<category><![CDATA[Programming / Scripting]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Rendering]]></category>

		<guid isPermaLink="false">http://www.xsi-blog.com/archives/245</guid>
		<description><![CDATA[ABSTRACT
This article is sort of a tutorial-cookbook for scripting beginners. It discusses quick and simple techniques to script minor tasks related to shaders. We will try to focus more on Object Model techniques than Command Model ones. Please feel free to contribute to it if you know better!
SHADERS
Shader name spaces
Shaders live in name spaces. In [...]]]></description>
			<content:encoded><![CDATA[<p><strong>ABSTRACT</strong></p>
<p>This article is sort of a tutorial-cookbook for scripting beginners. It discusses quick and simple techniques to script minor tasks related to shaders. We will try to focus more on Object Model techniques than Command Model ones. Please feel free to contribute to it if you know better!</p>
<p><span id="more-245"></span><strong>SHADERS</strong></p>
<p><strong>Shader name spaces</strong><br />
Shaders live in name spaces. In a single name space, no two shaders can have the same name. A bit like objects under models. There are several name spaces available. The material, the override, the camera, the light and the pass are all name spaces. Some name spaces are easier to deal with than others, like materials and lights. We could probably group name spaces in two larger categories: the material type (materials, lights and overrides), and the stack type (passes and cameras). The material type is always easy to handle (well, overrides have some particularities, but we shall address them later). Stack types on the other hand a somewhat problematic, as the way they expose shaders differently depending on the context.</p>
<p>One more name space deserves few lines. This is the TransientObjectContainer. This space is an invisible location where unconnected pieces of data live, like unconnected shaders. Notice that when you create a new shader in the Render Tree and open its property page right away, it&#8217;s name is prefixed with &#8220;TransientObjectContainer&#8221;. As soon as you connect this shader, it is now prefixed with the material name (you may need to re-open the ppg to see the change). When a shader is disconnected from all inputs, it returns to the TransientObjectContainer space. If you close the Render Tree, the shader is destroyed.</p>
<p><a href='http://www.xsi-blog.com/userContent/upload/2007/08/sshaders_transientoc.jpg' title='The TransientObjectContainer Namespace'><img src='http://www.xsi-blog.com/userContent/upload/2007/08/sshaders_transientoc.thumbnail.jpg' alt='The TransientObjectContainer Namespace' /></a></p>
<p>One advantage of name spaces is that the shader name is garanteed to be unique within that name space. So if you know the name space of a shader, you can retreive it anyway you like and be sure it&#8217;s the right shader. When I talk about the name of a shader, I mean name as in the &#8220;Name&#8221; property.</p>
<p><strong>Shader fullnames</strong><br />
Dealing with the shader fullname (as in the &#8220;FullName&#8221; property) is somewhat problematic. Only a handful of shaders have a &#8220;unique&#8221; fullname, because the fullname of a shader depends entirely from where it is read. In other word, most shaders have multiple fullnames, which are potentially all valid. A shader fullname is like a path in the render tree to that shader. It includes the name of all shaders traversed to reach this shader.</p>
<p>Let&#8217;s do a quick exercice.<br />
Create an object. Create a Phong material for this object. Open the render tree for that material. Disconnect the Phong shader from the Shadow input of the material node.<br />
Create a cell shader. Plug it in the diffuse input of the Phong shader, and in the Photon input of the material node.</p>
<p>Then run this code, which prints the name of shader inputs in a render tree:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">xsi = Application
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> printShaderSources<span style="color: black;">&#40;</span> oShader <span style="color: black;">&#41;</span>:
&nbsp;
	<span style="color: #808080; font-style: italic;"># Loop parameters of the shader</span>
	<span style="color: #ff7700;font-weight:bold;">for</span> oParameter <span style="color: #ff7700;font-weight:bold;">in</span> oShader.<span style="color: black;">parameters</span>:
&nbsp;
		<span style="color: #808080; font-style: italic;"># Check if the parameter has a source</span>
		oSource = oParameter.<span style="color: black;">source</span>
		<span style="color: #ff7700;font-weight:bold;">if</span> oSource <span style="color: #66cc66;">!</span>= <span style="color: #008000;">None</span>:
&nbsp;
			<span style="color: #808080; font-style: italic;"># Check if classname of the source is a shader</span>
			sClassName = xsi.<span style="color: black;">classname</span><span style="color: black;">&#40;</span> oSource <span style="color: black;">&#41;</span>
			<span style="color: #ff7700;font-weight:bold;">if</span> sClassName == <span style="color: #483d8b;">'Shader'</span> <span style="color: #ff7700;font-weight:bold;">or</span> sClassName == <span style="color: #483d8b;">'Texture'</span>:
&nbsp;
				xsi.<span style="color: black;">logmessage</span><span style="color: black;">&#40;</span> oSource.<span style="color: black;">fullname</span> <span style="color: black;">&#41;</span>
&nbsp;
				<span style="color: #808080; font-style: italic;"># Parameter has a shader source,</span>
				<span style="color: #808080; font-style: italic;"># call function again with that source</span>
				printShaderSources<span style="color: black;">&#40;</span> oSource <span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Call the function using the selected object's material</span>
printShaderSources<span style="color: black;">&#40;</span> xsi.<span style="color: black;">selection</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>.<span style="color: black;">material</span> <span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>This should print:</p>
<pre># INFO : sphere.Material.Phong
# INFO : sphere.Material.Phong.Cell
# INFO : sphere.Material.Cell</pre>
<p>At line 16, we print the fullname of the shader currently visited. You can see in the output that we got two different values: sphere.Material.Phong.Cell and sphere.Material.Cell. They are both valid and could be used to retrieve the shader using a string. The first is the result of accessing the shader through the Phong shader, while the second one is because we read it from the material node.</p>
<p>The shaders that have a unique fullname are the material, the override, the light, and basically the root shaders in pass and camera shader stacks.</p>
<p><strong>Collecting shaders the hard way: recursive traversal of the render tree</strong><br />
Aka &#8220;walking&#8221; the render tree, traversing the render tree is a very common task. There are several ways to do it, it depends on what you want to do.</p>
<p>In &#8220;Shader fullnames&#8221;, we&#8217;ve seen one way of doing it. This way is not clever at all. Shaders will be evaluated as many times as the number of inputs they plug in. In complex render trees, this means lots of cpu cycles can be lost. Worse, if you&#8217;re doing things like shader replacement, you may end up replacing the same shader more than once.</p>
<p>The trick is to remember which shader was visited. For the following examples, we&#8217;ll use a similar test scene: create a Phong material, plug a Cell shader in in its diffuse input and in the shadow input of the material. But don&#8217;t disconnect anything.</p>
<p>If you traverse the render tree without checking if a shader has been visited, you&#8217;ll get the same shader printed sevaral times:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">xsi = Application
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> printShaderSources<span style="color: black;">&#40;</span> oShader <span style="color: black;">&#41;</span>:
&nbsp;
	<span style="color: #808080; font-style: italic;"># Loop parameters of the shader</span>
	<span style="color: #ff7700;font-weight:bold;">for</span> oParameter <span style="color: #ff7700;font-weight:bold;">in</span> oShader.<span style="color: black;">parameters</span>:
&nbsp;
		<span style="color: #808080; font-style: italic;"># Check if the parameter has a source</span>
		oSource = oParameter.<span style="color: black;">source</span>
		<span style="color: #ff7700;font-weight:bold;">if</span> oSource <span style="color: #66cc66;">!</span>= <span style="color: #008000;">None</span>:
&nbsp;
			<span style="color: #808080; font-style: italic;"># Check if classname of the source is a shader</span>
			sClassName = xsi.<span style="color: black;">classname</span><span style="color: black;">&#40;</span> oSource <span style="color: black;">&#41;</span>
			<span style="color: #ff7700;font-weight:bold;">if</span> sClassName == <span style="color: #483d8b;">'Shader'</span> <span style="color: #ff7700;font-weight:bold;">or</span> sClassName == <span style="color: #483d8b;">'Texture'</span>:
&nbsp;
				xsi.<span style="color: black;">logmessage</span><span style="color: black;">&#40;</span> oSource.<span style="color: black;">name</span> <span style="color: black;">&#41;</span>
&nbsp;
				<span style="color: #808080; font-style: italic;"># Parameter has a shader source,</span>
				<span style="color: #808080; font-style: italic;"># call function again with that source</span>
				printShaderSources<span style="color: black;">&#40;</span> oSource <span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Call the function using the selected object's material</span>
printShaderSources<span style="color: black;">&#40;</span> xsi.<span style="color: black;">selection</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>.<span style="color: black;">material</span> <span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Output:</p>
<pre># INFO : Phong
# INFO : Cell
# INFO : Phong
# INFO : Cell
# INFO : Cell</pre>
<p>The simplest way to prevent this is to have a list of all shader names. Each time you visit a shader, check if its name is in the list, if not, evaluate its parameters.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">xsi = Application
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> printShaderSources<span style="color: black;">&#40;</span> oShader <span style="color: black;">&#41;</span>:
&nbsp;
	<span style="color: #808080; font-style: italic;"># Loop parameters of the shader</span>
	<span style="color: #ff7700;font-weight:bold;">for</span> oParameter <span style="color: #ff7700;font-weight:bold;">in</span> oShader.<span style="color: black;">parameters</span>:
&nbsp;
		<span style="color: #808080; font-style: italic;"># Check if the parameter has a source</span>
		oSource = oParameter.<span style="color: black;">source</span>
		<span style="color: #ff7700;font-weight:bold;">if</span> oSource <span style="color: #66cc66;">!</span>= <span style="color: #008000;">None</span>:
&nbsp;
			<span style="color: #808080; font-style: italic;"># Check if classname of the source is a shader</span>
			sClassName = xsi.<span style="color: black;">classname</span><span style="color: black;">&#40;</span> oSource <span style="color: black;">&#41;</span>
			<span style="color: #ff7700;font-weight:bold;">if</span> sClassName == <span style="color: #483d8b;">'Shader'</span> <span style="color: #ff7700;font-weight:bold;">or</span> sClassName == <span style="color: #483d8b;">'Texture'</span>:
&nbsp;
				<span style="color: #808080; font-style: italic;"># Check if shader was already visited</span>
				<span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> oSource.<span style="color: black;">name</span> <span style="color: #ff7700;font-weight:bold;">in</span> aShaderNames:
&nbsp;
					xsi.<span style="color: black;">logmessage</span><span style="color: black;">&#40;</span> oSource.<span style="color: black;">name</span> <span style="color: black;">&#41;</span>
&nbsp;
					aShaderNames.<span style="color: black;">append</span><span style="color: black;">&#40;</span> oSource.<span style="color: black;">name</span> <span style="color: black;">&#41;</span>
&nbsp;
					<span style="color: #808080; font-style: italic;"># Parameter has a shader source,</span>
					<span style="color: #808080; font-style: italic;"># call function again with that source</span>
					printShaderSources<span style="color: black;">&#40;</span> oSource <span style="color: black;">&#41;</span>
&nbsp;
aShaderNames = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Call the function using the selected object's material</span>
printShaderSources<span style="color: black;">&#40;</span> xsi.<span style="color: black;">selection</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>.<span style="color: black;">material</span> <span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Output:</p>
<pre># INFO : Phong
# INFO : Cell</pre>
<p>This approach has one big problem. There is one big exception to the name space rule: in a material, one shader can have the same name as the material. So if you collected the material name before all else and another shader has the same name, it will be skipped. You can deal with this in a plenty of ways, but they all come down to what to do if a name already exists. My suggestion is to simply rename the shader if it&#8217;s not of the material type. Append a 1 to its name. So all names are garanteed to be unique.</p>
<p>A very different approach to render tree traversal is to store all shaders in a collection that has the Unique flag enabled. You don&#8217;t even have to check if the name exists.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> win32com
xsi = Application
xsifactory = win32com.<span style="color: black;">client</span>.<span style="color: black;">Dispatch</span><span style="color: black;">&#40;</span> <span style="color: #483d8b;">'XSI.Factory'</span> <span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> getShaderSources<span style="color: black;">&#40;</span> oShader <span style="color: black;">&#41;</span>:
&nbsp;
	<span style="color: #808080; font-style: italic;"># Add shader right away to the collection</span>
	oShaders.<span style="color: black;">add</span><span style="color: black;">&#40;</span> oShader <span style="color: black;">&#41;</span>
&nbsp;
	<span style="color: #808080; font-style: italic;"># Loop parameters of the shader</span>
	<span style="color: #ff7700;font-weight:bold;">for</span> oParameter <span style="color: #ff7700;font-weight:bold;">in</span> oShader.<span style="color: black;">parameters</span>:
&nbsp;
		<span style="color: #808080; font-style: italic;"># Check if the parameter has a source</span>
		oSource = oParameter.<span style="color: black;">source</span>
		<span style="color: #ff7700;font-weight:bold;">if</span> oSource <span style="color: #66cc66;">!</span>= <span style="color: #008000;">None</span>:
&nbsp;
			<span style="color: #808080; font-style: italic;"># Check if classname of the source is a shader</span>
			sClassName = xsi.<span style="color: black;">classname</span><span style="color: black;">&#40;</span> oSource <span style="color: black;">&#41;</span>
			<span style="color: #ff7700;font-weight:bold;">if</span> sClassName == <span style="color: #483d8b;">'Shader'</span> <span style="color: #ff7700;font-weight:bold;">or</span> sClassName == <span style="color: #483d8b;">'Texture'</span>:
&nbsp;
				<span style="color: #808080; font-style: italic;"># Parameter has a shader source,</span>
				<span style="color: #808080; font-style: italic;"># call function again with that source</span>
				getShaderSources<span style="color: black;">&#40;</span> oSource <span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Create collection to store shaders of a material</span>
oShaders = xsifactory.<span style="color: black;">createobject</span><span style="color: black;">&#40;</span> <span style="color: #483d8b;">'XSI.Collection'</span> <span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Enable the Unique flag of the collection,</span>
<span style="color: #808080; font-style: italic;"># which means no shader can be stored twice</span>
oShaders.<span style="color: black;">unique</span> = <span style="color: #008000;">True</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Call the function using the selected object's material</span>
getShaderSources<span style="color: black;">&#40;</span> xsi.<span style="color: black;">selection</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>.<span style="color: black;">material</span> <span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Finally, print all shader names</span>
<span style="color: #ff7700;font-weight:bold;">for</span> oShader <span style="color: #ff7700;font-weight:bold;">in</span> oShaders:
	xsi.<span style="color: black;">logmessage</span><span style="color: black;">&#40;</span> oShader.<span style="color: black;">name</span> <span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Output:</p>
<pre># INFO : Material
# INFO : Phong
# INFO : Cell</pre>
<p><strong>Collecting shaders the easy way: FindShaders()</strong><br />
Materials, lights and cameras implemente the FindShaders() method. It allows you to collect all shaders as a flat collection and then get them by name or index, or you can loop over the collection items.</p>
<p>The example in the FindShaders (Material) entry of the documentation is pretty clear on this matter. This method is an alternative to recursively traverse the render tree. I have not tested performance, though.</p>
<p><strong>Storing a material&#8217;s render tree into a data structure</strong><br />
This is an expansion of the previous topic. If you ever have to do complex shader replacement, render tree export, or render tree reconstruction, storing the render tree in your own data structure will be essential. In this structure you will store the shaders, as well as the connections that exists between them. The following techniques I propose are based on my experience in this area, it is by no mean an absolute way of doing things.</p>
<p>First, each shader must be uniquely identified. That can be done using their name, although you must make sure that there is no name collision with the material. Personally I prefer to use an integer. The reason is that if you ever have to rename a shader, you may end up having to update the structure to reflect the name change. With an integer you don&#8217;t bother about this at all. For the remainder of this topic, I&#8217;ll use an integer as the master key for shaders. I&#8217;ll refer to this master key as the shader ID.</p>
<p>Using that ID, you&#8217;ll be able to store masses of information. You want to record the shader name, the shader object, the parameters that have a shader input, and the ID of the input shaders. The map will look like this:</p>
<pre>dShadersByID
{
	id (integer) :
	{
		'name' : shader name (string),
		'object' : shader object (instance),
		'parameters' (dictionary) :
		{
			'parameter name' : shader id,
			'parameter name' : shader id,
			...
		}
	},
	id (integer) :
	{
		'name'  : shader name (string),
		'object' : shader object (instance),
		'parameters' (dictionary) :
		{
			'parameter name' : shader id,
			'parameter name' : shader id,
			...
		}
	},
	...
}</pre>
<p>Let&#8217;s talk about how to populate this structure. Aside from the actual main structure, I&#8217;d have another map, where the the shader name is the key, and its ID is the value. It will be a lot easier to retreive the ID of an existing shader when one is encountered.</p>
<p>When a new shader is visited, each parameter is tested for the presence of a shader source. If one is found, it must be checked if the source has been evaluated already, if so, retreive its ID, and write for that parameter. Otherwise, visit that new shader.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> win32com
c = win32com.<span style="color: black;">client</span>.<span style="color: black;">constants</span>
xsi = Application
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> getShaderSources<span style="color: black;">&#40;</span> oShader <span style="color: black;">&#41;</span>:
&nbsp;
	<span style="color: #483d8b;">&quot;&quot;&quot;
	We assume that when this function is called,
	the passed shader has never been visited.
&nbsp;
	The function doesn't know if the passed
	shader is just a shader or the material.
	&quot;&quot;&quot;</span>
&nbsp;
	<span style="color: #808080; font-style: italic;"># Get new ID for this shader</span>
	<span style="color: #ff7700;font-weight:bold;">global</span> iID
	iID += <span style="color: #ff4500;">1</span>
	iShaderID = iID
&nbsp;
	<span style="color: #808080; font-style: italic;"># Map the ID to the shader name</span>
	dShadersByName<span style="color: black;">&#91;</span>oShader.<span style="color: black;">name</span><span style="color: black;">&#93;</span> = iID
&nbsp;
	<span style="color: #808080; font-style: italic;"># Store this shader in the main shader structure</span>
	dShadersByID<span style="color: black;">&#91;</span>iID<span style="color: black;">&#93;</span> = <span style="color: black;">&#123;</span>
		<span style="color: #483d8b;">'name'</span>: oShader.<span style="color: black;">name</span>,
		<span style="color: #483d8b;">'object'</span>: oShader,
		<span style="color: #483d8b;">'parameters'</span>: <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span>
	<span style="color: black;">&#125;</span>
&nbsp;
	<span style="color: #808080; font-style: italic;"># Loop parameters of the shader</span>
	<span style="color: #ff7700;font-weight:bold;">for</span> oParameter <span style="color: #ff7700;font-weight:bold;">in</span> oShader.<span style="color: black;">parameters</span>:
&nbsp;
		<span style="color: #808080; font-style: italic;"># Check if the parameter has a source</span>
		oSource = oParameter.<span style="color: black;">source</span>
		<span style="color: #ff7700;font-weight:bold;">if</span> oSource <span style="color: #66cc66;">!</span>= <span style="color: #008000;">None</span>:
&nbsp;
			<span style="color: #808080; font-style: italic;"># Check if classname of the source is a shader</span>
			sClassName = xsi.<span style="color: black;">classname</span><span style="color: black;">&#40;</span> oSource <span style="color: black;">&#41;</span>
			<span style="color: #ff7700;font-weight:bold;">if</span> sClassName == <span style="color: #483d8b;">'Shader'</span> <span style="color: #ff7700;font-weight:bold;">or</span> sClassName == <span style="color: #483d8b;">'Texture'</span>:
&nbsp;
				<span style="color: #808080; font-style: italic;"># Check if the source is the material and has the same name as the material</span>
				<span style="color: #ff7700;font-weight:bold;">if</span> oSource.<span style="color: #008000;">type</span> <span style="color: #66cc66;">!</span>= c.<span style="color: black;">siMaterialType</span> <span style="color: #ff7700;font-weight:bold;">and</span> oSource.<span style="color: black;">name</span> == oMAT.<span style="color: black;">name</span>:
&nbsp;
					<span style="color: #808080; font-style: italic;"># Rename source</span>
					oSource.<span style="color: black;">name</span> = <span style="color: #483d8b;">'%s1'</span> <span style="color: #66cc66;">%</span> oSource.<span style="color: black;">name</span>
&nbsp;
				<span style="color: #808080; font-style: italic;"># Check if that source shader has already been visited</span>
				<span style="color: #ff7700;font-weight:bold;">if</span> oSource.<span style="color: black;">name</span> <span style="color: #ff7700;font-weight:bold;">in</span> dShadersByName:
&nbsp;
					<span style="color: #808080; font-style: italic;"># Get the source ID</span>
					iSourceID = dShadersByName<span style="color: black;">&#91;</span>oSource.<span style="color: black;">name</span><span style="color: black;">&#93;</span>
&nbsp;
					<span style="color: #808080; font-style: italic;"># Store the source ID for this parameter</span>
					dShadersByID<span style="color: black;">&#91;</span>iShaderID<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'parameters'</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>oParameter.<span style="color: black;">scriptname</span><span style="color: black;">&#93;</span> = iSourceID
&nbsp;
				<span style="color: #ff7700;font-weight:bold;">else</span>:
					<span style="color: #808080; font-style: italic;"># Source shader has never been visited</span>
					<span style="color: #808080; font-style: italic;"># Visit it, and map its ID to the current parameter</span>
					dShadersByID<span style="color: black;">&#91;</span>iShaderID<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'parameters'</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>oParameter.<span style="color: black;">scriptname</span><span style="color: black;">&#93;</span> = getShaderSources<span style="color: black;">&#40;</span> oSource <span style="color: black;">&#41;</span>
&nbsp;
	<span style="color: #808080; font-style: italic;"># Return the shader ID to the caller</span>
	<span style="color: #ff7700;font-weight:bold;">return</span> iShaderID
&nbsp;
&nbsp;
&nbsp;
<span style="color: #808080; font-style: italic;"># Main data structure</span>
dShadersByID = <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># ID mapped to the shader name</span>
dShadersByName = <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Starting ID</span>
iID = -<span style="color: #ff4500;">1</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Constants to indicate which shader is the material</span>
oMAT = xsi.<span style="color: black;">selection</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>.<span style="color: black;">material</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Call the function using the selected object's material</span>
getShaderSources<span style="color: black;">&#40;</span> oMAT <span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>To verify the dShadersByID structure, you can simply convert it to string and print it:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">xsi.<span style="color: black;">logmessage</span><span style="color: black;">&#40;</span> <span style="color: #008000;">str</span><span style="color: black;">&#40;</span>dShadersByID<span style="color: black;">&#41;</span> <span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Using our example of the Cell shader, the output should be like this (I formatted it so it&#8217;s easier to read):</p>
<pre>{
	0:
	{
		'object': "COMObject "unknown""(3),
		'name': u'Material',
		'parameters':
		{
			u'shadow': 1,
			u'Photon': 2,
			u'surface': 1
		}
	},

	1:
	{
		'object': "COMObject "unknown""(3),
		'name': u'Phong',
		'parameters':
		{
			u'diffuse': 2
		}
	},

	2:
	{
		'object': "COMObject "unknown""(3),
		'name': u'Cell',
		'parameters': {}
	}
}</pre>
<p>So we got our map of the render tree. We can then use to navigate the render tree and do any operation we want without risking loosing relationships. For instance, if you wanted to replace the Phong shader, you know you have to look for ID 1. Once replaced, you can find in other shaders to which inputs is the phong connected, and perform the connections. You also know, looking at the phong entry, that ID 2 is connected into its diffuse parameter.</p>
<p>The next topics should help you tackle these operations.</p>
<p><strong>Creating a shader</strong><br />
You can create a &#8220;floating&#8221; shader, that is, a shader object not connected to anything, by using the CreateObjectFromPreset() command.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">oShader = xsi.<span style="color: black;">createobjectfrompreset</span><span style="color: black;">&#40;</span> <span style="color: #483d8b;">&quot;shaders/material/blinn.preset&quot;</span> <span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>To find out what string you should use as the first parameter, just create the shader in the Render Tree. This will give you the path of the preset file, and this is all you need to create the shader.<br />
The command also accepts a second argument, for its name. Usually I don&#8217;t specify a name unless I&#8217;m creating trees that enforce the project standards.</p>
<p>The command returns the shader object. This object lives in the TransientObjectContainer, it&#8217;s not connected to anything. The cool thing is that contrary to unconnected shaders in the Render Tree, which are destroyed when the Render Tree is closed, TransientObjectContainer shaders created by script remain there as long as you don&#8217;t create a new scene or explicitely remove them. Remember however that because the shader is not connected, it may hard to retrieve if you destroy the variable that holds the command return value.</p>
<p><strong>Connecting a shader</strong><br />
Once you have a shader, you may connect it into a texturable parameter. You can use the SIConnectShaderToCnxPoint() command, but personnally I find the Connect() method of the parameter object to be faster and cleaner. All you need is to have the input parameter as an object.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">oParameter.<span style="color: black;">connect</span><span style="color: black;">&#40;</span> oShader <span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>What I usually do when building shader trees in script is to create all the shaders in one phase (using the CreateObjectFromPreset() command), and then perform all the connections in another phase.</p>
<p>If you are connecting the shader in a rather large amount of parameters, then perhaps using the SIConnectShaderToCnxPoint() command might be faster, as it allows you to pass a list of input parameters:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">sPhong = <span style="color: #483d8b;">'Sources.Materials.DefaultLib.Scene_Material.Phong'</span>
&nbsp;
xsi.<span style="color: black;">siconnectshadertocnxpoint</span><span style="color: black;">&#40;</span>
   oShader.<span style="color: black;">fullname</span>,
    <span style="color: #483d8b;">','</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span> <span style="color: black;">&#91;</span>
        <span style="color: #483d8b;">'%s.diffuse'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>sPhong,<span style="color: black;">&#41;</span>,
        <span style="color: #483d8b;">'%s.ambient'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>sPhong,<span style="color: black;">&#41;</span>,
        <span style="color: #483d8b;">'%s.specular'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>sPhong,<span style="color: black;">&#41;</span>
    <span style="color: black;">&#93;</span> <span style="color: black;">&#41;</span>,
    <span style="color: #008000;">False</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p><strong>Disconnecting a shader</strong><br />
As with connecting shaders, there are two ways to disconnect shaders. The first one is the RemoveShaderFromCnxPoint() command, which works like SIConnectShaderToCnxPoint() command.</p>
<p>The other way is to use the Disconnect() method on the parameter you want to remove the connected shader from.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">oParameter.<span style="color: black;">disconnect</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Now you have to be very careful: if you disconnect the shader and the shader is no longer connected to any parameter, it is destroyed!</p>
<p><strong>Getting the &#8220;sub-parameters&#8221; after a disconnection</strong><br />
If you have a compound parameter, like a color or a vector, and you disconnect a shader from it, you won&#8217;t be able to access its sub-parameters (like red or x) right away, for some reason. If you try to read or write to the red parameter, for example, you&#8217;ll raise an exception.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">oDiffuse.<span style="color: black;">disconnect</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
xsi.<span style="color: black;">logmessage</span><span style="color: black;">&#40;</span> oDiffuse.<span style="color: black;">parameters</span><span style="color: black;">&#40;</span> <span style="color: #483d8b;">'red'</span> <span style="color: black;">&#41;</span>.<span style="color: black;">value</span> <span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Output:</p>
<pre># ERROR : Traceback (most recent call last):
#   File "", line 14, in ?
#     xsi.logmessage( oDiffuse.parameters( 'red' ).value )
# AttributeError: 'NoneType' object has no attribute 'value'
#  - [line 14]</pre>
<p>The solution is to &#8220;rebind&#8221; the variable to the disconnected parameter.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">oDiffuse.<span style="color: black;">disconnect</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Rebind parameter and variable</span>
oDiffuse = oDiffuse.<span style="color: black;">parent</span>.<span style="color: black;">parameters</span><span style="color: black;">&#40;</span> <span style="color: #483d8b;">'diffuse'</span> <span style="color: black;">&#41;</span>
&nbsp;
xsi.<span style="color: black;">logmessage</span><span style="color: black;">&#40;</span> oDiffuse.<span style="color: black;">parameters</span><span style="color: black;">&#40;</span> <span style="color: #483d8b;">'red'</span> <span style="color: black;">&#41;</span>.<span style="color: black;">value</span> <span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Output:</p>
<pre># INFO : 0.699999988079071</pre>
<p>Thanks to François Painchaud for this one.</p>
<p><strong>Getting all shaders of a same kind</strong><br />
A common task is to change the value of a shader parameter globally. For example, you may want to enable elliptical filtering in all image shaders. Materials may have varying render trees, so using overrides would be prove very tedious.</p>
<p>To get all shader instances of a same kind, you can run the command FindObjects(). This is very fast and reliable.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">oBlinns = xsi.<span style="color: black;">findobjects</span><span style="color: black;">&#40;</span> <span style="color: #008000;">None</span>, <span style="color: #483d8b;">'{8FAC63AC-E392-11D1-804C-00A0C906835D}'</span> <span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>This will return a XSICollection containing all shader instances as objects. The first argument is always null or None. The second argument is a shader ClassID</p>
<p><strong>Getting the ClassID of a shader</strong><br />
To know the ClassID of a shader, you can create it in the Render Tree, open its property page, right-click on the space next to the shader name, and choose Edit.</p>
<p><a href='http://www.xsi-blog.com/userContent/upload/2007/08/sshaders_classid.jpg' title='Shader classid'><img src='http://www.xsi-blog.com/userContent/upload/2007/08/sshaders_classid.thumbnail.jpg' alt='Shader classid' /></a></p>
<p>A text page will open either in the script editor or in a floating text editor. The ClassID is generally located at the third line, it starts with Reference.</p>
<pre>Reference = "{8FAC63AC-E392-11D1-804C-00A0C906835D}";</pre>
<p>If you already have the shader object in your script and want to find out its ClassID, you can use the GetIdentifier() method of the DataRepository object.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">sClassID = oRepository.<span style="color: black;">getidentifier</span><span style="color: black;">&#40;</span> oShader, c.<span style="color: black;">siObjectCLSID</span> <span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>To create a DataRepository instance in Python:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> win32com
xsiutils = win32com.<span style="color: black;">client</span>.<span style="color: black;">Dispatch</span><span style="color: black;">&#40;</span> <span style="color: #483d8b;">'XSI.Utils'</span> <span style="color: black;">&#41;</span>
oRepository = xsiutils.<span style="color: black;">datarepository</span></pre></td></tr></table></div>

<p><strong>Finding a specific kind of shader in a render tree</strong><br />
We&#8217;ve seen pretty much all means of getting and identifying shaders. But you might be looking for shaders of a specific type inside a shader name space. There are several ways to do that:</p>
<p>The first approach is to run FindObjects(). Since it works globally, you&#8217;ll have to loop each shader and check if its Root property matches the one we&#8217;re looking for. Remember that the Root property suffers from an important limitation that we hinted at in <strong>Shader fullnames</strong> and shall discuss more in <strong>PASSES</strong>.</p>
<p>The second approach is to use FindShaders() or recursive traversal of the render tree to collect shaders. Remember however that those last techniques also suffer from certain limitations. FindShaders() works only on materials, cameras and lights, and recursive traversal of the render tree (as it has been presented in this article so far) will work only on materials, lights and overrides. For traversal of other trees you&#8217;ll have to make important modifications to your code. More on that in <strong>PASSES</strong>.</p>
<p>No matter how you collect shaders, you must test their class id against the one you&#8217;re looking for.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> win32com
&nbsp;
c = win32com.<span style="color: black;">client</span>.<span style="color: black;">constants</span>
xsi = Application
xsiutils = win32com.<span style="color: black;">client</span>.<span style="color: black;">Dispatch</span><span style="color: black;">&#40;</span> <span style="color: #483d8b;">'XSI.Utils'</span> <span style="color: black;">&#41;</span>
oRepository = xsiutils.<span style="color: black;">datarepository</span>
&nbsp;
sPhongCLSID = <span style="color: #483d8b;">'{67120BBE-C98C-11D1-9723-00A0243E3672}'</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Get shaders of the selected material</span>
oShaders = xsi.<span style="color: black;">selection</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>.<span style="color: black;">findshaders</span><span style="color: black;">&#40;</span> c.<span style="color: black;">siShaderFilter</span> <span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Iterate shaders</span>
<span style="color: #ff7700;font-weight:bold;">for</span> oShader <span style="color: #ff7700;font-weight:bold;">in</span> oShaders:
&nbsp;
	<span style="color: #808080; font-style: italic;"># Get current shader classid</span>
	sShaderCLSID = oRepository.<span style="color: black;">getidentifier</span><span style="color: black;">&#40;</span> oShader, c.<span style="color: black;">siObjectCLSID</span> <span style="color: black;">&#41;</span>
&nbsp;
	<span style="color: #808080; font-style: italic;"># Compare classids</span>
	<span style="color: #ff7700;font-weight:bold;">if</span> sShaderCLSID == sPhongCLSID:
&nbsp;
		xsi.<span style="color: black;">logmessage</span><span style="color: black;">&#40;</span> oShader.<span style="color: black;">fullname</span> <span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p><strong>Dealing with texture projections, tangents, and similar shader parameters</strong><br />
Shader parameters that point to scene objects like texture projections, tangent properties, color at vertices, weight maps and the likes, deserve special attention. They are not dealt with using the typical means of evaluating and setting parameters, and may get you stuck easily. Let&#8217;s look at how to use each option.</p>
<p>The HasInstanceValue property allows you to know if you&#8217;re dealing with that kind of parameter. So if you use very generic code that handle any kind of parameter, that should be the first thing to check.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">if</span> oParameter.<span style="color: black;">hasinstancevalue</span>:
	<span style="color: #808080; font-style: italic;"># do something</span></pre></td></tr></table></div>

<p>The next thing to do is to find out to which scene object is this parameter pointing to. This is where it gets nasty. The SDK doesn&#8217;t provide any form of relationship between such parameters and the objects they point to. You have to tests every friggin object you suspect might be used!</p>
<p>What you can do, if you work with a material, is to use its UsedBy property get the objects using that material. Then, you have to find the appropriate cluster properties on those objects. Finally, you can test if those cluster properties are used by the parameter.</p>
<p>Let&#8217;s imagine we want to know the texture projections used by a shader parameter named oParameter.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Get objects using this material</span>
oUsers = oMat.<span style="color: black;">usedby</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Loop objects using this material</span>
<span style="color: #ff7700;font-weight:bold;">for</span> oUser <span style="color: #ff7700;font-weight:bold;">in</span> oUsers:
&nbsp;
	<span style="color: #808080; font-style: italic;"># Loop its clusters</span>
	<span style="color: #ff7700;font-weight:bold;">for</span> oCluster <span style="color: #ff7700;font-weight:bold;">in</span> oUser.<span style="color: black;">activeprimitive</span>.<span style="color: black;">geometry</span>.<span style="color: black;">clusters</span>:
&nbsp;
		<span style="color: #808080; font-style: italic;"># Check if the cluster is a sample cluster</span>
		<span style="color: #ff7700;font-weight:bold;">if</span> oCluster.<span style="color: #008000;">type</span> == <span style="color: #483d8b;">'sample'</span>:
&nbsp;
			<span style="color: #808080; font-style: italic;"># Loop the cluster properties of the current cluster</span>
			<span style="color: #ff7700;font-weight:bold;">for</span> oClusterProp <span style="color: #ff7700;font-weight:bold;">in</span> oCluster.<span style="color: black;">localproperties</span>:
&nbsp;
				<span style="color: #808080; font-style: italic;"># Check if the cluster property is a texture projection</span>
				<span style="color: #ff7700;font-weight:bold;">if</span> oClusterProp.<span style="color: #008000;">type</span> == <span style="color: #483d8b;">'uvspace'</span>:
&nbsp;
					<span style="color: #808080; font-style: italic;"># Test if the parameter points to this object</span>
					sInstanceValue = oParameter.<span style="color: black;">getinstancevalue</span><span style="color: black;">&#40;</span> oProjection <span style="color: black;">&#41;</span>
&nbsp;
					<span style="color: #808080; font-style: italic;"># If returns empty string, it means it does NOT point to that object</span>
					<span style="color: #ff7700;font-weight:bold;">if</span> sInstanceValue <span style="color: #66cc66;">!</span>= <span style="color: #483d8b;">''</span>:
						<span style="color: #808080; font-style: italic;"># do something</span></pre></td></tr></table></div>

<p>Be careful. The GetInstanceValue() method has a significant limitation: it allows you to test against properties of X3DObjects only. If you pass objects like groups or partitions to the GetInstanceValue() method, it will fail. You may pass the members of those objects for the method to succeed.</p>
<p>Setting the parameter to point to cluster properties is done exactly the same way. You have to know in advance what cluster property to use, and then run the SetInstanceValue() method.</p>
<p>The last SDK doc entries worthy of mentioning are IsSupportedInstanceValue (which allows you find out what kind of cluster property does the parameter supports).</p>
<p><strong>MATERIAL LIBRARIES</strong></p>
<p>We can&#8217;t talk of materials without talking about material libraries. The two go together. Let&#8217;s look at few ways to deal with those.</p>
<p><strong>Getting all material libraries</strong><br />
The object model way:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">oLibs = xsi.<span style="color: black;">activeproject</span>.<span style="color: black;">activescene</span>.<span style="color: black;">materiallibraries</span></pre></td></tr></table></div>

<p>The command model way:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">oLibs = xsi.<span style="color: black;">findobjects</span><span style="color: black;">&#40;</span> <span style="color: #008000;">None</span>, <span style="color: #483d8b;">&quot;{61782E14-9177-412e-BF9B-2B44B9A668DD}&quot;</span> <span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Now be careful with the command model way. It may return an extra library that apparently lives in the TransientObjectContainer. If you run this:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">xsi = Application
oLibs = xsi.<span style="color: black;">findobjects</span><span style="color: black;">&#40;</span> <span style="color: #008000;">None</span>, <span style="color: #483d8b;">&quot;{61782E14-9177-412e-BF9B-2B44B9A668DD}&quot;</span> <span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">for</span> oLib <span style="color: #ff7700;font-weight:bold;">in</span> oLibs:
	xsi.<span style="color: black;">logmessage</span><span style="color: black;">&#40;</span> oLib.<span style="color: black;">fullname</span> <span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>It may print:</p>
<pre># INFO : Sources.Materials.DefaultLib
# INFO : library_source</pre>
<p>I suspect that the second one is an instance of the first, to be used as a pointer to the current library. But what do I know ;-)</p>
<p><strong>Getting a material&#8217;s library</strong><br />
If you need to get the library object from the material, simply use the Library property of the material object.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">oLib = oMaterial.<span style="color: black;">library</span></pre></td></tr></table></div>

<p><strong>Looping materials from libraries</strong><br />
It&#8217;s very straightforward:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Loop over all matlibs</span>
<span style="color: #ff7700;font-weight:bold;">for</span> oLib <span style="color: #ff7700;font-weight:bold;">in</span> xsi.<span style="color: black;">activeproject</span>.<span style="color: black;">activescene</span>.<span style="color: black;">materiallibraries</span>:
&nbsp;
	<span style="color: #808080; font-style: italic;"># Loop materials in the current library</span>
	<span style="color: #ff7700;font-weight:bold;">for</span> oMat <span style="color: #ff7700;font-weight:bold;">in</span> oLib.<span style="color: black;">items</span>:
&nbsp;
		<span style="color: #808080; font-style: italic;"># do something</span></pre></td></tr></table></div>

<p><strong>MATERIALS</strong></p>
<p>The majority of the work done with shaders will probably be done through materials.</p>
<p><strong>Creating materials</strong><br />
As usual, there are several means for creating materials. If you want to create a material on an object, you can use the ApplyShader() command. This, unfortunately, doesn&#8217;t give you control the library the material is created in, it&#8217;s always the current library. Alternatively, you could use the AddMaterial() method. Since it&#8217;s the Object Model approach, it&#8217;s probably going to be faster, especially if the creation is done in a loop.</p>
<p>Personally, I prefer to create the material in a library, and then assign it to the target object. The SICreateMaterial() command allows you not only to specify the library, but also the objects that shall use this material. But it depends a lot on performance, I usually favor the fastest execution.</p>
<p><strong>Assigning materials</strong><br />
If you don&#8217;t use the SICreateMaterial() command, you could use SIAssignMaterial() (which is a low-level version of AssignMaterial). You could also use the CopyPaste() command (which is printed when you drag and drop a material onto an object, but personally I prefer more explicit approaches.</p>
<p><strong>Unassigning materials</strong><br />
There is no other way than to use the UnAssignMaterial() and SIUnAssignMaterial() commands.</p>
<p><strong>Getting the material of an object</strong><br />
It may seem very straightforward to do that, but there are a few things to talk about. The first and foremost way to get an object&#8217;s material is to use the Material property.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">oMat = oObject.<span style="color: black;">material</span></pre></td></tr></table></div>

<p>This will work on X3DObjects, polygon clusters, groups, layers and partitions. Basically anything that supports material assignment. However, there is a chance the object it returns is not the one you&#8217;re looking for. The Material property returns the &#8220;current&#8221; material, or that is, the inherited material. If an object is in a group that has a material, the Material property will return the group material, not the object one.</p>
<p>If you&#8217;re looking to get the actual material of the object and ignore inheritance, you&#8217;ll have to go through the local properties of the object.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> win32com
c = win32com.<span style="color: black;">client</span>.<span style="color: black;">constants</span>
xsi = Application
&nbsp;
<span style="color: #ff7700;font-weight:bold;">for</span> oProp <span style="color: #ff7700;font-weight:bold;">in</span> xsi.<span style="color: black;">selection</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>.<span style="color: black;">localproperties</span>:
	<span style="color: #ff7700;font-weight:bold;">if</span> oProp.<span style="color: #008000;">type</span> == c.<span style="color: black;">siMaterialType</span>:
		xsi.<span style="color: black;">logmessage</span><span style="color: black;">&#40;</span> oProp.<span style="color: black;">fullname</span> <span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>The LocalProperties approach will also work on any object that supports material assignment.</p>
<p><strong>Getting the objects using a material</strong><br />
A material has the UsedBy property, which returns all objects using that material.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">xsi.<span style="color: black;">logmessage</span><span style="color: black;">&#40;</span> oMat.<span style="color: black;">UsedBy</span>.<span style="color: black;">getastext</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>The UsedBy property, however, has always suffered from severe limitations. In the past, it would return only X3DObjects. Now it also returns polygon clusters. However, it won&#8217;t return groups, layers and partitions using that material. Instead, it will print the X3DObjects and clusters that have inherited the material from the group/layer/partition.</p>
<p>If you want to find the groups/layers/partitions using that material, you&#8217;ll have to look the owners of the material. The first owner is always the material library. The other owners are the objects using this material. In the case of a material assigned to a group:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">oMat = xsi.<span style="color: black;">selection</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">for</span> oOwner <span style="color: #ff7700;font-weight:bold;">in</span> oMat.<span style="color: black;">owners</span>:
	xsi.<span style="color: black;">logmessage</span><span style="color: black;">&#40;</span> <span style="color: #483d8b;">'%s - %s'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>oOwner.<span style="color: black;">fullname</span>, oOwner.<span style="color: #008000;">type</span><span style="color: black;">&#41;</span> <span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Output:</p>
<pre># INFO : Sources.Materials.MatLib - library_source
# INFO : Group - #Group</pre>
<p><strong>Deleting materials</strong><br />
To my knowledge, there is no other way to delete a material than to use the DeleteObj() command.</p>
<p><strong>Shotcuts to access material components</strong><br />
The object model offers a few shortcuts to retrieve data of a material. You should read the Material and Shader entries of the documentation to find out about those.</p>
<p><strong>PASSES</strong></p>
<p>Passes are special. They support shaders through their stacks. However, passes cannot be dealt like with like materials. Two situations come to mind, both being somewhat related.</p>
<p>In the first situation, if you take the script presented in &#8220;Storing the render tree into a data structure&#8221;, it will fail if you supply the pass object as the starting value for the function. Passes do not allow accessing shaders through its Parameters, unlike materials. So you have to do clever things to get stack shaders from the stack.</p>
<p>The second situation is the opposite: if you use the Root property of a shader to get to the, well, shader tree root, you&#8217;ll get the pass object. This is wrong, for the very same reason as the preceding examples, that is, passes do not expose shaders through their Parameters.</p>
<p>To make things worse, if you open the render tree with a pass selected, it looks like the pass is a materials and shaders plug directly into them. This is a lie. And to seal the deal, the render tree view shows only the first shader of each stack, even though the stacks support multiple shaders at the top level. Another lie. Fortunately, the Object Model helps solving those problems.</p>
<p><strong>Accessing shader stacks from passes</strong><br />
There is no shortcut to access a pass stack. You have lookup the pass&#8217;s NestedObjects, using the stack name. Once you get the stack object, you can check its NestedObjects to see if there are shaders. This will return a collection of the &#8220;top&#8221; shaders of the stack.</p>
<p>Create a pass with an environment shader, selected that pass, and run this:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">xsi = Application
&nbsp;
aStackNames = <span style="color: black;">&#91;</span>
	<span style="color: #483d8b;">'Environment Shader Stack'</span>,
	<span style="color: #483d8b;">'Output Shader Stack'</span>,
	<span style="color: #483d8b;">'Volume Shader Stack'</span>
<span style="color: black;">&#93;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Get selected pass</span>
oPass = xsi.<span style="color: black;">selection</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Iterate pass stacks</span>
<span style="color: #ff7700;font-weight:bold;">for</span> sStackName <span style="color: #ff7700;font-weight:bold;">in</span> aStackNames:
&nbsp;
	<span style="color: #808080; font-style: italic;"># Get the stack object</span>
	oStack = oPass.<span style="color: black;">nestedobjects</span><span style="color: black;">&#40;</span> sStackName <span style="color: black;">&#41;</span>
&nbsp;
	<span style="color: #808080; font-style: italic;"># Check if the stack has shaders</span>
	<span style="color: #ff7700;font-weight:bold;">if</span> oStack.<span style="color: black;">nestedobjects</span>.<span style="color: black;">count</span> <span style="color: #66cc66;">&amp;</span>gt<span style="color: #66cc66;">;</span> <span style="color: #ff4500;">0</span>:
&nbsp;
		<span style="color: #808080; font-style: italic;"># Iterate root shaders of this stack</span>
		<span style="color: #ff7700;font-weight:bold;">for</span> oStackShader <span style="color: #ff7700;font-weight:bold;">in</span> oStack.<span style="color: black;">nestedobjects</span>:
&nbsp;
			xsi.<span style="color: black;">logmessage</span><span style="color: black;">&#40;</span> oStackShader.<span style="color: black;">fullname</span> <span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Unfortunately, you cannot use reliable string searching. Select the Environment shader you created. It should print this line in the History Log:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">Application.<span style="color: black;">SelectObj</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Passes.Default_Pass.Environment&quot;</span>, <span style="color: #483d8b;">&quot;&quot;</span>, <span style="color: #483d8b;">&quot;&quot;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Now, rename the shader to something already in use in that pass, like &#8220;Background_Objects_Partition&#8221;. Select the shader again. It should print this:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">Application.<span style="color: black;">SelectObj</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Passes.Default_Pass.EnvironmentShaderStack.Background_Objects_Partition&quot;</span>, <span style="color: #483d8b;">&quot;&quot;</span>, <span style="color: #483d8b;">&quot;&quot;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>So now you got the stack name, probably to avoid name collisions in the pass name space. Because this behavior is not constant, how can you reliably use strings to find pass shaders? If Softimage reads this, I politely invite you to correct this by putting the stack name as at all times. That will save us, poor coders, lots of trouble.</p>
<p><strong>Getting the &#8220;root&#8221; shader from a shader</strong><br />
As previously mentioned, the Root property of a shader returns the pass object, which can be incorrect depending on how close to reality you want the information to be. To me this is very incorrect. In this case, the &#8220;root&#8221; shader is a shader visible in the stack. Because you can put multiple shaders in a stack, it means that there can be an infinite amount of root shaders for the the pass.</p>
<p>Walking down the render tree (down being &#8220;away from the root shader&#8221;) is easy, but walking up is not so. I don&#8217;t know any fast, clever, or elegant way of doing this. The only constant is that no two shaders can be named the same way in the pass name space(1).</p>
<p>For the following chunk of code, do this:</p>
<ul>
<li>Put an Environment shader on the default pass.</li>
<li>Open the render tree, and connect a Cell shader into the tex input of the Environment shader.</li>
<li>Then, create a _2D_background_color shader (output shader)</li>
<li>Create another Cell shader, and plug it in the bg input of the _2D_background_color shader(2). Normally, the second Cell shader should have been renamed Cell1.</li>
</ul>
<p>To find the root shader for a given shader, I&#8217;ve written a sort of state machine that remembers in which stack and root shader it is walking down. Run this code:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> win32com
&nbsp;
c = win32com.<span style="color: black;">client</span>.<span style="color: black;">constants</span>
xsi = Application
xsifactory = win32com.<span style="color: black;">client</span>.<span style="color: black;">Dispatch</span><span style="color: black;">&#40;</span> <span style="color: #483d8b;">'XSI.Factory'</span> <span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> PassShaderState:
&nbsp;
	<span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span> <span style="color: #008000;">self</span>, sPassName, sShaderName <span style="color: black;">&#41;</span>:
&nbsp;
		<span style="color: #808080; font-style: italic;"># CONSTANTS</span>
&nbsp;
		<span style="color: #808080; font-style: italic;"># Name of the shader we're looking for</span>
		<span style="color: #008000;">self</span>.<span style="color: black;">passname</span> = sPassName
		<span style="color: #008000;">self</span>.<span style="color: black;">shadername</span> = sShaderName
&nbsp;
		<span style="color: #808080; font-style: italic;"># Stack names</span>
		<span style="color: #008000;">self</span>.<span style="color: black;">stacknames</span> = <span style="color: black;">&#91;</span>
			<span style="color: #483d8b;">'Environment'</span>,
			<span style="color: #483d8b;">'Output'</span>,
			<span style="color: #483d8b;">'Volume'</span>
		<span style="color: black;">&#93;</span>
&nbsp;
&nbsp;
		<span style="color: #808080; font-style: italic;"># VARIABLES</span>
&nbsp;
		<span style="color: #808080; font-style: italic;"># Shader identification</span>
		<span style="color: #808080; font-style: italic;"># All point to scene objects</span>
		<span style="color: #008000;">self</span>.<span style="color: black;">currentstack</span> = <span style="color: #008000;">None</span>
		<span style="color: #008000;">self</span>.<span style="color: black;">currentroot</span> = <span style="color: #008000;">None</span>
		<span style="color: #008000;">self</span>.<span style="color: black;">currentshader</span> = <span style="color: #008000;">None</span>
&nbsp;
&nbsp;
&nbsp;
&nbsp;
	<span style="color: #ff7700;font-weight:bold;">def</span> getroot<span style="color: black;">&#40;</span> <span style="color: #008000;">self</span> <span style="color: black;">&#41;</span>:
&nbsp;
		<span style="color: #808080; font-style: italic;"># Get the pass object</span>
		oColl = xsifactory.<span style="color: black;">createobject</span><span style="color: black;">&#40;</span> <span style="color: #483d8b;">'XSI.Collection'</span> <span style="color: black;">&#41;</span>
		oColl.<span style="color: black;">items</span> = <span style="color: #483d8b;">'Passes.%s'</span> <span style="color: #66cc66;">%</span> <span style="color: #008000;">self</span>.<span style="color: black;">passname</span>
&nbsp;
		<span style="color: #808080; font-style: italic;"># Did we find the pass</span>
		<span style="color: #ff7700;font-weight:bold;">if</span> oColl.<span style="color: black;">count</span></pre></td></tr></table></div>

<p>  Storing the pass shaders into a data structure<br />
We&#8217;ve seen already how to store a material&#8217;s render tree into a data structure. The presented approach cannot be used without modifications for pass shaders, again because of the foggy relationship that exists between the pass object, its stacks and its root shaders. Here I will not present code to achieve this task (as my solution is extremely elaborate), but rather explain what approach I use to do it. My goal was to have the ability to re-create the pass shaders simply by reading a flat XML list of shaders.</p>
<p>With a material it&#8217;s simple: when you get to the material, you can create anything you want the same way, and plug anything you want. With shader stacks it&#8217;s different.</p>
<p>The data structure I presented above works, but will need extra informations. Each shader will have to be flagged as being a stack root shader or not. The reason is that creating stack root shaders requires can only be done through the SIApplyShaderToCnxPoint() command, while creating the shaders underneath use the CreateObjectFromPreset() command, presented earlier.</p>
<p>Root shaders should state to which stack they belong (including the pass name, of course). When creating shaders with SIApplyShaderToCnxPoint(), you must specify the shader stack. Having this information already available as a string will make it easy. Btw, in the data structure, store the Type property of the stack, not its Name.</p>
<p><strong>CAMERAS</strong></p>
<p>The camera is similar to the pass, with a significant difference: it has only one stack. Once the camera shader stack is accessed, code that handles pass shader stacks should work with the camera shader stack. A word of advice: while I&#8217;m not aware of any such plans from Softimage, it would be a good idea to design your code to assume that there might be more than one stack in a camera. Let&#8217;s imagine Softimage, in some near future, adds a new stack to the camera&#8230;&#8230;.</p>
<p><strong>LIGHTS</strong></p>
<p>Lights can be handled pretty much like a material. For instance, you can traverse the light&#8217;s render tree using the same code we used with the material one, but pass it the light&#8217;s primitive:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">xsi = Application
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> printShaderSources<span style="color: black;">&#40;</span> oShader <span style="color: black;">&#41;</span>:
&nbsp;
	<span style="color: #808080; font-style: italic;"># Loop parameters of the shader</span>
	<span style="color: #ff7700;font-weight:bold;">for</span> oParameter <span style="color: #ff7700;font-weight:bold;">in</span> oShader.<span style="color: black;">parameters</span>:
&nbsp;
		<span style="color: #808080; font-style: italic;"># Check if the parameter has a source</span>
		oSource = oParameter.<span style="color: black;">source</span>
		<span style="color: #ff7700;font-weight:bold;">if</span> oSource <span style="color: #66cc66;">!</span>= <span style="color: #008000;">None</span>:
&nbsp;
			<span style="color: #808080; font-style: italic;"># Check if classname of the source is a shader</span>
			sClassName = xsi.<span style="color: black;">classname</span><span style="color: black;">&#40;</span> oSource <span style="color: black;">&#41;</span>
			<span style="color: #ff7700;font-weight:bold;">if</span> sClassName == <span style="color: #483d8b;">'Shader'</span> <span style="color: #ff7700;font-weight:bold;">or</span> sClassName == <span style="color: #483d8b;">'Texture'</span>:
&nbsp;
				xsi.<span style="color: black;">logmessage</span><span style="color: black;">&#40;</span> oSource.<span style="color: black;">name</span> <span style="color: black;">&#41;</span>
&nbsp;
				<span style="color: #808080; font-style: italic;"># Parameter has a shader source,</span>
				<span style="color: #808080; font-style: italic;"># call function again with that source</span>
				printShaderSources<span style="color: black;">&#40;</span> oSource <span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Call the function using the selected light's primitive</span>
printShaderSources<span style="color: black;">&#40;</span> xsi.<span style="color: black;">selection</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>.<span style="color: black;">activeprimitive</span> <span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Output:</p>
<pre># INFO : soft_light
# INFO : soft_light</pre>
<p>Additionnally, the light object (not the primitive) have a Shaders property. This will access the shaders connected into the primitive. If you want to access the soft_light shader (or any shader connected into the light&#8217;s primitive), use:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">xsi.<span style="color: black;">logmessage</span><span style="color: black;">&#40;</span> xsi.<span style="color: black;">selection</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>.<span style="color: black;">shaders</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>.<span style="color: black;">fullname</span> <span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p><strong>OVERRIDES</strong></p>
<p>Overrides are another beast. Their implementation looks and behaves similarly to other shader implementations in XSI, although there are several differences that need to be taken care of. Here we&#8217;ll talk about creating overrides by script.</p>
<p><strong>Shader overrides</strong><br />
You&#8217;ve probably noticed that shader overrides use strings separated by dashes. I suspect this is because the dot character is reserved to namespace notation, having it in a parameter script name would break things. Also you deal with relative names, where the material name is kind of masked by &#8220;material&#8221;. For instance, if you override the Surface input of a material, the created parameter looks like &#8220;material-surface&#8221;.</p>
<p>If you want to re-create a shader parameter in an override, you&#8217;ll have to format that string a little.<br />
First, replace the dashes by dots, obviously.<br />
Second, you&#8217;ll have to find a material among the group/layer/partition members that has the parameter you want to override, and use the material name in replacement of &#8220;material&#8221;. So &#8220;material-surface&#8221; become something like &#8220;cylinder.Material.surface&#8221;.</p>
<p><strong>Absence of members</strong><br />
The #1 problem, in my opinion, is that you can&#8217;t create an override group/layer/partition doesn&#8217;t expose the parameter you want to override. This makes re-creating overrides by script very difficult. I know 3 solutions to this:</p>
<ul>
<li>Save a preset of the override. Probably the most reliable way to do it, however it requires that you create the override at least once and store a preset. Another big advantage is that this approach works even if the group/layer/partition has no members to override.</li>
<li>Create temporary objects. This is easy if you have to overrides parameters such as visibility or geometry approximation, but for shaders it can become extremely elaborate. Definitely consider other solutions.</li>
<li>Wait for the group/layer/partition to be populated before attempting to create the override parameters. Better than #2, but still not 100% reliable.</li>
</ul>
<p><strong>Refresh issues</strong><br />
Another problem is that when you manage to create a parameter in an override, that parameter is not always immediately available through the object model. For reasons I don&#8217;t have a clue about, there are situations where if you try to reach the created parameter through the Parameters property of the override, it would fail:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">xsi = Application
&nbsp;
<span style="color: #808080; font-style: italic;"># Get the selected override</span>
oOverride = xsi.<span style="color: black;">selection</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Define parameter to override</span>
sParameterName = <span style="color: #483d8b;">'viewvis'</span>
sParameterFullName = <span style="color: #483d8b;">'cube.visibility.%s'</span> <span style="color: #66cc66;">%</span> sParameterName
&nbsp;
<span style="color: #808080; font-style: italic;"># Create the override entry</span>
xsi.<span style="color: black;">SIAddEntryToOverride</span><span style="color: black;">&#40;</span> oOverride, sParameterFullName <span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Get the created override</span>
oOverride.<span style="color: black;">parameters</span><span style="color: black;">&#40;</span> sParameterName <span style="color: black;">&#41;</span>.<span style="color: black;">value</span> = <span style="color: #008000;">True</span></pre></td></tr></table></div>

<p>The solution is that once the parameter is created, use a string to retrieve it:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">xsi = Application
&nbsp;
<span style="color: #808080; font-style: italic;"># Get the selected override</span>
oOverride = xsi.<span style="color: black;">selection</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Define parameter to override</span>
sParameterName = <span style="color: #483d8b;">'viewvis'</span>
sParameterFullName = <span style="color: #483d8b;">'cube.visibility.%s'</span> <span style="color: #66cc66;">%</span> sParameterName
&nbsp;
<span style="color: #808080; font-style: italic;"># Create the override entry</span>
xsi.<span style="color: black;">SIAddEntryToOverride</span><span style="color: black;">&#40;</span> oOverride, sParameterFullName <span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Get the created override</span>
oColl = xsifactory.<span style="color: black;">createobject</span><span style="color: black;">&#40;</span> <span style="color: #483d8b;">'XSI.Collection'</span> <span style="color: black;">&#41;</span>
oColl.<span style="color: black;">items</span> = <span style="color: #483d8b;">'%s.%s'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span> oOverride.<span style="color: black;">fullname</span>, sParameterName <span style="color: black;">&#41;</span>
oParameter = oColl<span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
oParameter.<span style="color: black;">value</span> = <span style="color: #008000;">True</span></pre></td></tr></table></div>

<p><strong>FURTHER SCRIPTING</strong></p>
<p>There are many more topics we could cover, including texture layers, OGLTextures, shader input type, the ProgID, etc. These are all things I&#8217;m not deeply familiar with so I&#8217;ll leave it to you to learn about those.</p>
<p><strong>NOTES</strong></p>
<p>(1) XSI 6.01 had this nasty bug. If you select the pass, open the render tree and start connecting shaders all over the place, they would all have a unique name. So far so good. But if you selected one of the stack shaders, open the render tree and connected shaders from there, you could name a shader the same as in another stack. In the end, it means that several shaders could have the same name in the pass name space. This was corrected in XSI 6.02.<br />
(2) If your _2D_background_shader doesn&#8217;t expose a bg input, you can modify the spdl. Simply enable the texturable flag.<br />
(3) The real value is &#8220;COMObject &#8220;unknown&#8221;", where &#8221; are replaced by &#8220;smaller than&#8221; and &#8220;greater than&#8221; tags.</p>
<img src="http://www.softimageblog.com/?ak_action=api_record_view&id=245&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.softimageblog.com/archives/245/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>About exporting shaders</title>
		<link>http://www.softimageblog.com/archives/243#utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=about-exporting-shaders</link>
		<comments>http://www.softimageblog.com/archives/243#comments</comments>
		<pubDate>Mon, 09 Jul 2007 01:33:00 +0000</pubDate>
		<dc:creator>Bernard Lebel</dc:creator>
				<category><![CDATA[Programming / Scripting]]></category>
		<category><![CDATA[Rendering]]></category>
		<category><![CDATA[XML]]></category>

		<guid isPermaLink="false">http://www.xsi-blog.com/archives/243</guid>
		<description><![CDATA[ABSTRACT
This article discusses some of the problems and solutions involved in exporting shaders from XSI, using custom tools and custom file formats.
THE INITIAL GOALS
At Big Bang I wanted the ability to write materials to XML files (and read them back, of course). This would serve two major purposes. First, it would offer a granular set [...]]]></description>
			<content:encoded><![CDATA[<p><strong>ABSTRACT</strong></p>
<p>This article discusses some of the problems and solutions involved in exporting shaders from XSI, using custom tools and custom file formats.</p>
<p><strong>THE INITIAL GOALS</strong></p>
<p>At Big Bang I wanted the ability to write materials to XML files (and read them back, of course). This would serve two major purposes. First, it would offer a granular set of data, which could be re-used in different contexts. I could have used preset file instead of a XML file, but the second major purpose of the project prevented that: I wanted to be able to not only read the file, but also to make modifications in it if there was ever such a need.</p>
<p>To be honest I was quite disappointed that after I spent so much time and effort into this project, it turned out I needed to make such edits to material files only for about 20 of them (as of this writing, there are about 3,800 such material files in the pipeline). I could have also used the XML file at other things, like building templates for standard materials, using it for the approval of shading tasks, etc. But in the end that did not happen. However, the work I did for exporting materials could be used for other things.</p>
<p><span id="more-243"></span><strong>THE CHALLENGES OF MATERIAL EXPORT</strong></p>
<p>It didn&#8217;t take too long until I felt that exporting materials can be a rocky business. At first glance it seems very straightforward: select an object, run a script to export its material. In the material file, I wanted not only the entire material described, but I also wanted to list the image clips and the image sources used by this material. Plus, I wanted to know which scene objects are using this material, including geometry, clusters, groups and partitions. So that when I import the material, I could re-create it, as well as its image clips and sources, and apply it to objects using it if they are in the scene.</p>
<p>Next, I wanted the code to handle inputs that consisted of more than one object. For instance, given an input of objects (either geometry, partitions, clusters, or even materials), the code had to figure out what to export and do it right. I didn&#8217;t want the script to attempt to export the material of a chain, for example. Given that input management allowed many objects to be visited, and that some of these objects could use the same material, I had to keep track of which material had already been exported.</p>
<p>On top of the material, the image sources, the image clips and the objects using this material, I had to write the actual shaders to the file. Afterall the goal was to be able to re-create the material from an XML file, so I needed the list of shaders. One may think that to write shaders to a file, all that is needed is to recursively walk down the material&#8217;s Render Tree and, well, write the shaders as they are visited.</p>
<p>Not quite. Some shaders are connected into several other inputs. Unaware recursive traversal of the Render Tree meant that entire branches could end up being written several times. That was a waste of space and CPU cycles. Plus, if many branches are being repeated, how would the importing code know that it&#8217;s actually the same branch?</p>
<p>So I had to find a way to organise shaders with a unique &#8220;key&#8221;. At first I considered using their FullName. I was in for a big surprise.</p>
<p>In the Explorer, switch to Scene Root scope. If you iterate the Properties/LocalProperties of an object, find a material, and print its FullName, it will return the name of the material with the object&#8217;s FullName prefixed. Same if you select the material under the object. However, switch the Explorer&#8217;s scope to Materials. If you select the same material and print its FullName, then you get the name of the material prefixed with the library&#8217;s FullName, which is garanteed to be unique.</p>
<p>I call this last one the material&#8217;s &#8220;AbsoluteName&#8221;. There might be better terms for this, however I thought of it as browsing the file system, where there can be no two absolute file name for the same file (well, it&#8217;s possible, but let&#8217;s not get carried away).</p>
<p>It&#8217;s easy to work out the AbsoluteName of a material, even when you get the material from the objects owning it instead of the library. But to my knowledge, it&#8217;s impossible to use the same approach for shaders under this material. The FullName of a shader changes depending on the parameter it is being read from. For example, if you have an Image shader connected into an input of a Blinn shader and the input of an another shader, logging the Image&#8217;s FullName when traversing the Render Tree will return ..Blinn.Image and &#8230;Image.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">xsi = Application
&nbsp;
<span style="color: #808080; font-style: italic;"># Get selected object</span>
oSel = xsi.<span style="color: black;">selection</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Get selected object's material</span>
oMat = oSel.<span style="color: black;">material</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> walk<span style="color: black;">&#40;</span> oShader <span style="color: black;">&#41;</span>:
	xsi.<span style="color: black;">logmessage</span><span style="color: black;">&#40;</span> oShader.<span style="color: black;">fullname</span> <span style="color: black;">&#41;</span>
&nbsp;
	<span style="color: #808080; font-style: italic;"># Iterate the shader parameters</span>
	<span style="color: #ff7700;font-weight:bold;">for</span> oParameter <span style="color: #ff7700;font-weight:bold;">in</span> oShader.<span style="color: black;">parameters</span>:
&nbsp;
		<span style="color: #808080; font-style: italic;"># Get the parameter source</span>
		oSource = oParameter.<span style="color: black;">source</span>
&nbsp;
		<span style="color: #808080; font-style: italic;"># Check if we got a source</span>
		<span style="color: #ff7700;font-weight:bold;">if</span> oSource <span style="color: #66cc66;">!</span>= <span style="color: #008000;">None</span>:
&nbsp;
			<span style="color: #808080; font-style: italic;"># Get the classname of the source</span>
			sClassName = xsi.<span style="color: black;">classname</span><span style="color: black;">&#40;</span> oSource <span style="color: black;">&#41;</span>
&nbsp;
			<span style="color: #808080; font-style: italic;"># Check if the classname is a shader</span>
			<span style="color: #ff7700;font-weight:bold;">if</span> sClassName == <span style="color: #483d8b;">'Shader'</span> <span style="color: #ff7700;font-weight:bold;">or</span> sClassName == <span style="color: #483d8b;">'Texture'</span>:
				walk<span style="color: black;">&#40;</span> oSource <span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Loop over material parameters</span>
walk<span style="color: black;">&#40;</span> oMat <span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Prints:</p>
<pre># INFO : sphere.Material
# INFO : sphere.Material.Blinn
# INFO : sphere.Material.Blinn.Image
# INFO : sphere.Material.Blinn.Image
# INFO : sphere.Material.Blinn
# INFO : sphere.Material.Blinn.Image
# INFO : sphere.Material.Blinn.Image
# INFO : sphere.Material.Cell
# INFO : sphere.Material.Cell.Image</pre>
<p>So this means you can&#8217;t use the shader FullName as a unique key. If you can&#8217;t rely on the shader&#8217;s FullName, then how can you make sure that you have not visited this shader already? You could possibly use the shader&#8217;s Name. Afterall, in a material, all shaders have a unique name.</p>
<p>But instead of using the names as the key, I preferred to give them a unique ID number (unsigned integer). Image clips would also receive such an ID. When writing the shader parameters to the file, if they had a shader or an image clip connected, it would use the previously defined ID of the shader/image clip. This meant that before writing anything to the XML file, all shaders and image clips would need to be visited. Ultimately, a map of all shaders, based on their ID and their name, could be established.</p>
<p>This resulted in somewhat complex dictionaries and lists, which were hard to maintain and debug. Nonetheless, I managed to make the material export work reliably. It was slow (since it&#8217;s uncompiled code), but it was totally reliable.</p>
<p>I should add that handling parameters such as texture projection pointers posed a challenge worthy of talking about. Those parameters are not like other parameters, they require a different handling. Of course all that is needed is available in the SDK, still, I thought I&#8217;d mention it to those attempting at writing shaders to file.</p>
<p><strong>BEYOND MATERIALS</strong></p>
<p>All went smooth for many many months, until we started looking into lighting and rendering. Then it occured to me that I needed the ability to export passes, so they could be re-created later on. I thought that since I had code that could write shaders to file, then surely I could reuse this code for other things than materials: overrides and pass shader stacks. Well, that&#8217;s what I thought. But my code was built entirely around the material export, so I could hardly use it for overrides and pass stacks without making drastic modifications.</p>
<p><strong>Pass shader stacks</strong><br />
There are two major problems with pass shader stacks.</p>
<p>The first problem is that from all practical purposes, passes have the appearance of materials. If you select a pass and open the Render Tree, you&#8217;ll see the pass object being displayed as if it was a material. In reality, that is not quite right.</p>
<p>For instance, you can iterate the parameters of material, and effectively traverse the Render Tree from there. That is not happening with passes. First, passes do not have a Parameters property, and second, they do not expose shaders in any way. So the Render Tree display is highly misleading, and I had to write code to handle passes differently than materials. In short, I did not find any quick and easy way to get the stack shaders. This is illustrated by this stripped down method that collects the stack &#8220;root&#8221; shaders (see next paragraph):</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> addpass<span style="color: black;">&#40;</span> <span style="color: #008000;">self</span>, oPass <span style="color: black;">&#41;</span>:
&nbsp;
	aStacks = <span style="color: black;">&#91;</span>
		<span style="color: #483d8b;">'Environment Shader Stack'</span>,
		<span style="color: #483d8b;">'Output Shader Stack'</span>,
		<span style="color: #483d8b;">'Volume Shader Stack'</span>
	<span style="color: black;">&#93;</span>
&nbsp;
	<span style="color: #808080; font-style: italic;"># Iterate pass stacks</span>
	<span style="color: #ff7700;font-weight:bold;">for</span> sStack <span style="color: #ff7700;font-weight:bold;">in</span> aStacks:
&nbsp;
		<span style="color: #808080; font-style: italic;"># Get the stack object</span>
		oStack = oPass.<span style="color: black;">nestedobjects</span><span style="color: black;">&#40;</span> sStack <span style="color: black;">&#41;</span>
&nbsp;
		<span style="color: #808080; font-style: italic;"># Check if the stack has shaders</span>
		<span style="color: #ff7700;font-weight:bold;">if</span> oStack.<span style="color: black;">nestedobjects</span>.<span style="color: black;">count</span> <span style="color: #66cc66;">&amp;</span>gt<span style="color: #66cc66;">;</span> <span style="color: #ff4500;">0</span>:
&nbsp;
			<span style="color: #808080; font-style: italic;"># Iterate root shaders of this stack</span>
			<span style="color: #ff7700;font-weight:bold;">for</span> oStackShader <span style="color: #ff7700;font-weight:bold;">in</span> oStack.<span style="color: black;">nestedobjects</span>:
&nbsp;
				<span style="color: #808080; font-style: italic;"># do something with shader</span></pre></td></tr></table></div>

<p>The second problem is that in a pass, there can be multiple shaders living at the top-level of a stack (which I shall call &#8220;root&#8221; shaders). For instance, if you apply two volume shaders to a pass and then open the Render Tree of that pass, you&#8217;ll only see the latest volume shader. That&#8217;s another misleading aspect of the pass&#8217;s Render Tree. So it can be assumed a pass shader stack can have multiple &#8220;root&#8221; shaders, and each of them is entirely valid and must be exported if you want to fully export the pass shader stacks. The upshot is that the pass object act as a name space, just as a material: among all the shader stacks of a pass, no two shaders can share the same name. This is great, but that doesn&#8217;t solve our problem of multiple root shaders for a same stack.</p>
<p>Also, when importing a pass shader stack, using the typical ways of creating shaders and plugging them afterward worked for all but the &#8220;root&#8221; shaders. To import pass shader stacks, each shader had to have a &#8220;stackroot&#8221; flag in the XML file. When meeting such a flag, the script would not simply create the shader and plug it later, it would have to run the command that creates root shaders in stacks. This command is the only way to not destroy other existing root shaders!</p>
<p><strong>Overrides</strong><br />
Overrides pose an entirely different set of problems.</p>
<p>They are not materials, and they are not pass shader stacks, yet they can host complex networks of shaders. There also can be more than one override per partition! An override could not be handled as a material nor a pass. Materials, in my framework, were meant to be exported as single files, overrides needed to be exported in a pass file, along the shader stacks, partitions and render options. An override doesn&#8217;t have things like the material&#8217;s UsedBy property, it is a partition property.</p>
<p>Also, overrides on partitions are visible only in the current pass. I thought that this was case only in the GUI, but found out that this extends to the scripting interface. If you iterate the properties of a partition not of the current pass, you&#8217;ll never catch that partition&#8217;s overrides. The only solution was to use a low-level command such as FindObjects() to collect all overrides, which works, and then organise them by pass and by partition, to later write them to file along the partition that&#8217;s being written.</p>
<p>Using FindObjects() to collect overrides returned a lot more overrides that what I expected. All these overrides were named VisibilityOverrideXX (&#8220;XX&#8221; being a number). I basically found out that group objects (groups, layers, partitions) implement the parameter inheritance via an override. This override is created when a parameter of the group object is not set to &#8220;no effect on members&#8221;, but remain invisible at all times, except to commands like FindObjects(). This can be tricky, because you don&#8217;t want to export this override. However you never know when a user will create an override to disable a parameter like &#8220;viewvis&#8221;, and name this override &#8220;VisibilityOverride&#8221;. The only solution when such an override name is encountered is to check that the partition parameters all set to &#8220;no effect on members&#8221;.</p>
<p>But the biggest problem with overrides came with the import. This article is not about shader import (which may be covered in another article), but few things are worth mentioning.</p>
<p>You can&#8217;t add a parameter to an override if the parameter cannot be found in the partition members. The only way to add a parameter to an override is to use SIAddEntryToOverride(), which requires a parameter FullName string. My solution was not very elegant, and is not garanteed. Basically the code tries to find the parameter among the partition members. If find its, then good, the entry can be added. Otherwise, you&#8217;re out of luck. Materials are also tricky because the override parameter name doesn&#8217;t exactly reflect the real shader parameter FullName that has to be overridden. With elaborate string manipulation this can all be worked out, but this is slow and like I said, not very reliable.</p>
<p>Another annoying thing is that an entry added to an override cannot be accessed right away via the object model. At least that was the case in XSI 5.11 (I tried in 6.01 and it seems to work). For instance, the following code would raise an error:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">xsi = Application
&nbsp;
<span style="color: #808080; font-style: italic;"># Get the selected override</span>
oOverride = xsi.<span style="color: black;">selection</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
&nbsp;
sParameterName = <span style="color: #483d8b;">'viewvis'</span>
sParameterFullName = <span style="color: #483d8b;">'cube.visibility.%s'</span> <span style="color: #66cc66;">%</span> sParameterName
&nbsp;
xsi.<span style="color: black;">SIAddEntryToOverride</span><span style="color: black;">&#40;</span> oOverride, sParameterFullName <span style="color: black;">&#41;</span>
&nbsp;
oOverride.<span style="color: black;">parameters</span><span style="color: black;">&#40;</span> sParameterName <span style="color: black;">&#41;</span>.<span style="color: black;">value</span> = <span style="color: #008000;">True</span></pre></td></tr></table></div>

<p>So to get back the added parameters I had to use strings.</p>
<p><strong>Cameras and lights</strong><br />
I have not talked about cameras and lights so far, simply because as the time of this writing, the need to export their shaders never arose.</p>
<p>In our pipeline, cameras and lights are exported as full-fledge models. Their importance is rather low compared to other models (like characters, for instance), so that exporting their network of shaders was not felt as a necessity. Also, cameras and lights are very light-weight compared to other models, so managing them always as models posed no particular problem.</p>
<p>My belief is that lights can be handled not too differently than materials. The catch word is &#8220;too&#8221;. The light primitive is a bit like a material, it has inputs for connecting shaders. But a light is not a material, and I&#8217;m affraid that handling lights would require yet another dedicated wrapper to hide the real nature of the light.</p>
<p>In the case of camera shaders, my guess is that they behave in a similar fashion as pass shader stacks do. The camera shader stack lives right under the camera primitive, and appears to be accessible only through the NestedObjects property. Just as a pass shader stack, the camera shader stacks accepts multiple shaders at its top level, but when you open the Render Tree, it shows only the first shader of the stack.</p>
<p><strong>THE SHADER NAME SPACE</strong></p>
<p>Obviously, trying to adapt the existing material export code to also export pass shader stacks and overrides turned out to be very tedious. So I had to make drastic changes to the framework, and implement a new interface: the shader name space.</p>
<p>I consider the material, the override and the pass shader stack to be shader name spaces. That is, a space where a collection of shader names live. A material, a pass and an override as all shader name spaces. Lights and cameras are also shader name spaces. As of this writing, however, my framework does not include anything to export and import lights and cameras.</p>
<p>The object used as the shader name space is not necessarily the &#8220;root&#8221; shader, that is, the shader of the tree where all others ultimately plug in. Materials and overrides are both name space and root, but in the case of pass shader stacks, each &#8220;root&#8221; shader of a stack is a shader name space root. So a shader name space can have multiple roots. In the shader name space, the exact nature of the name space is not really important, as it is hidden by the shader name space interface.</p>
<p>Treating data that way made things far more easier to work with. Low-level functions would write to file without knowing the context of use, while wrappers would handle all the specificities of the name space.</p>
<p><strong>PROPOSITION OF IMPROVEMENT FOR MATERIALS</strong></p>
<p>All of this hassle with shader export and shader name space made me think about how it could have been a lot easier. I had to write code to handle all types of shader name space, which resulted in significant amounts of code and increased opportunities for bugs to make it through. The shader name space is in fact an attempt at implementing something that, I believe, should be in XSI: new kinds of materials.</p>
<p>Lights, passes and cameras should implement a material. I don&#8217;t see any reason why not.</p>
<p>- Imagine if light, pass, and camera materials could be managed from the Explorer, just like other materials. Light materials could use an orange color, while pass materials could be green and camera materials could use a gray color. The color is not important, but this mean they could a lot easier to manage, especially in large amounts. They could be organised in libraries, exported, and referenced.</p>
<p>- The mess of pass and camera shader stacks would not be visible anymore.</p>
<p>- Sharing materials among lights, passes and cameras would be a breeze. Increased reusability.</p>
<p>- Programming-wise, they would make the process very homogenous. No matter if you select a light, geometry, or a pass, you can always use its Material property to access the material. Simple, straightforward and consistent.</p>
<p>I don&#8217;t really see where overrides would fit in this design. Perhaps they could be left as they are, but at least it&#8217;s only one special case to handle, not every case.</p>
<p>I&#8217;m strongly against the idea of having a &#8220;super&#8221; material. For instance this material could be applied to anything, however it would expose only parameters suitable for the context it&#8217;s being used in. When applied to different kinds of objects, I hardly see how it would be easy to work with. It would make scripting very inconsistent and require the same kind of tedious handling I have been discussing in this article.</p>
<p>Get a material and a passes file here: <a href='http://www.xsi-blog.com/userContent/upload/2007/07/xml.zip' title='Material and passes XML files'>Material and passes XML files</a></p>
<p><strong>ABOUT DATA INPUT MANAGEMENT IN MATERIAL EXPORT</strong></p>
<p>If you think that this section title sounds redundant, you are right. I have written an article on XSI-Blog about this very subject. I talk again about it because it really is during the development of this project that the importance of data input management struck me. I think that the data input management is one of the most fundamental aspects of any larger programming project.</p>
<p>I wanted the material export to be easy for the user. I wanted the interactive input to be simple and predictable. Users tend to favor the simplest ways of doing things. Given a model, they would expect to export everything related to this model. They don&#8217;t really care about the details, but they know that if all components of character lives under a unique model, then they have to be able to do things by simply handing the model to the script (via selection or picking, for example). However, exporting everything under a model can generate lots of data and take considerable time, so I wanted to give the users the ability to &#8220;focus&#8221; the export: given a selected object, it would export only the object&#8217;s material(s). Or the user could even select the material and export it. Painless, fast and predictable.</p>
<p>But giving the users various ways of exporting things meant that I had to write considerable code to manage the data input. The code that wrote to XML files was dumb, but lives below thick wrappers that would manage all the data input from the user. When the materials to export would reach the actual exporting functions, it would have to be guaranteed to be adequate.</p>
<p>Here is a little chart to show the framework design to cope with this task.</p>
<p>- call from the user<br />
    &#8211; user data input management (objects, materials&#8230;)<br />
        &#8211; final data input management (by type of data)<br />
            &#8211; export of shader name spaces<br />
                &#8211; fetch data from structures<br />
                    &#8211; write to file</p>
<p>The difference between &#8220;user data input management&#8221; and &#8220;final data input management&#8221; is that they used a different interface. Both interface would handle data, but with different purposes in mind. Ultimately, they would end up populating data structures that, too, served specific puroses.</p>
<p>The first layer of input management handled the data provided by the user to make sure it was acceptable for the export and/or the import. For example, it ould make sure that only materials, overrides and passes could make it through for an export. The interface used to perform this task is an interface used throughout the entire framework to take care of all initial data inputs.</p>
<p>That interface, that I called the &#8220;Chapter&#8221; (as in a chapter in the biker world) would know everything about the context: is the user exporting or importing, is he exporting/importing in a shot or in an element, things like that. Through a system of promotion and demotion, the Chapter would store &#8220;suitable&#8221; primary data into structures that could be later accessed by everyone else.</p>
<p>The second layer of input management, &#8220;final data input management&#8221;, as well as &#8220;fetch data from structures&#8221;, used a more specialized interface, dedicated to shader export. Its job would be to hide all the complexities in the differences that exist between materials, overrides and shader stacks.</p>
<p>In &#8220;final data input management&#8221;, it would extract the final data from the &#8220;suitable&#8221; primary data coming from the Chapter, and store it in data structures. In &#8220;fetch data from structures&#8221;, it would read this final data on-demand as the script goes on. The interface would make the storing and reading of that data completely homogenous, no matter if dealing with a material, a pass, or an override. While resulting in very long code (the entire interface is implemented as nested classes), it made the overall data handling incredibly easy.</p>
<img src="http://www.softimageblog.com/?ak_action=api_record_view&id=243&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.softimageblog.com/archives/243/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Facial Animation, The Static KineState, and Dorritos?</title>
		<link>http://www.softimageblog.com/archives/209#utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=facial-animation-the-static-kinestate-and-dorritos</link>
		<comments>http://www.softimageblog.com/archives/209#comments</comments>
		<pubDate>Thu, 24 May 2007 03:12:35 +0000</pubDate>
		<dc:creator>Steven Caron</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Rigging]]></category>

		<guid isPermaLink="false">http://www.xsi-blog.com/archives/209</guid>
		<description><![CDATA[This is my first post at XSIBlog, so I want to thank Patrick and the other authors for keeping this going. I have always wanted to share but time is always against me not to mention having something worthy of sharing.
PLEASE NOTE: The following python scripts require this procedure to work properly.
Facial Animation
A thread started [...]]]></description>
			<content:encoded><![CDATA[<p>This is my first post at XSIBlog, so I want to thank Patrick and the other authors for keeping this going. I have always wanted to share but time is always against me not to mention having something worthy of sharing.</p>
<p><strong>PLEASE NOTE</strong>: The following python scripts require <a href="/?p=24">this procedure</a> to work properly.</p>
<p><strong>Facial Animation</strong></p>
<p>A thread started at <a href="http://www.xsibase.com/">XSI Base</a> simply named, <a href="http://www.xsibase.com/forum/index.php?board=11;action=display;threadid=29757">facial animation (questions)</a>, many facial rigging and animation concepts were shared. The two concepts discussed mostly were your traditional shape animation controlled by in scene controllers (a la Osipa) and also using Control Splines or curves with many complex rig elements that give you the desired motion. At the end of the day shape animation gets you pretty far with many character types ( realistic and stylized ) and setup time is pretty fast. The setup time is also important here, Softimage considers this a feature for FaceRobot that they market and rightfully so. Time is money, producers know this as should you! So if you will hear me out I am going to explain a way for you to continue to use shape animation and still get the low level control over subtle face movements.</p>
<p><span id="more-209"></span><strong>The Static KineState</strong></p>
<p>What is the Static KineState? I am sure anyone spending any amount of time rigging knows something about it. So lets define it for those that don&#8217;t.</p>
<p>The <a href="http://softimage.wiki.avid.com/xsidocs/skel.htm">Static KineState</a> indicates that an envelope is applied to the skeleton element. The StaticKineState is the initial position of the skeleton when the envelope was applied, and is used for envelope calculations.</p>
<p>If this property is storing these initial values then I must be able to change them. This is the gem that makes this rig work.</p>
<p><strong>Dorritos</strong></p>
<p>Now we are going to make the rig. This is not intended to be a tutorial so I apologize if I miss steps, all the project files are included at the bottom. So lets go over the rig!</p>
<p>I am starting with Primitive>Character>Face Man and I first made a quick &#8220;smile&#8221; shape, followed by a typical neck, head, and jaw for the character. I used nulls instead of joints for simplicity sake.</p>
<p><img src='http://www.xsi-blog.com/userContent/upload/2007/05/rignsmile.gif' alt='rignsmile.gif' /></p>
<p>Now I am going to make a clone of this enveloped head and immediately remove the duplicated shape cluster, envelope cluster, and the &#8220;ShapeWeights&#8221; property. The clone uses the &#8220;CopyOp&#8221;, with this we get all the deformations from the first head which include the envelope deform and shape deform. Now we need to setup the local deformers for the cloned mesh.</p>
<p><img src='http://www.xsi-blog.com/userContent/upload/2007/05/exploreclone.jpg' alt='exploreclone.jpg' /></p>
<p>These local deformers use an &#8220;Object To Cluster&#8221; constraint. I like to use edge clusters but you could use any SubComponent you choose. So I picked an edge in the corner of the mouth and ran this handy script that creates the cluster, the object, constrains them, and makes the local deformer. You need to select a component on the original head, and run the script.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">#imports</span>
<span style="color: #ff7700;font-weight:bold;">import</span> win32com.<span style="color: black;">client</span>
<span style="color: #ff7700;font-weight:bold;">from</span> win32com.<span style="color: black;">client</span> <span style="color: #ff7700;font-weight:bold;">import</span> constants
&nbsp;
<span style="color: #808080; font-style: italic;">#globals</span>
xsi	= win32com.<span style="color: black;">client</span>.<span style="color: black;">Dispatch</span><span style="color: black;">&#40;</span> <span style="color: #483d8b;">&quot;XSI.Application&quot;</span> <span style="color: black;">&#41;</span>.<span style="color: black;">Application</span>
xsiPrint = xsi.<span style="color: black;">LogMessage</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> setupDorrito<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
	<span style="color: #ff7700;font-weight:bold;">if</span> xsi.<span style="color: black;">Selection</span> <span style="color: #66cc66;">&lt;</span> <span style="color: #ff4500;">1</span>:
		xsiPrint<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Select an component!&quot;</span>,constants.<span style="color: black;">siError</span><span style="color: black;">&#41;</span>
		<span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">False</span>
&nbsp;
	root = xsi.<span style="color: black;">ActiveSceneRoot</span>
&nbsp;
	<span style="color: #808080; font-style: italic;">#create cluster constrained null, setup its look</span>
	clsCnsNull = root.<span style="color: black;">AddNull</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;clsCnsNull&quot;</span><span style="color: black;">&#41;</span>
	clsCnsNull.<span style="color: black;">primary_icon</span>.<span style="color: black;">value</span> = <span style="color: #ff4500;">0</span>
	clsCnsNull.<span style="color: black;">size</span>.<span style="color: black;">value</span> = <span style="color: #ff4500;">0.1</span>
	clsCnsNull.<span style="color: black;">shadow_icon</span>.<span style="color: black;">value</span> = <span style="color: #ff4500;">7</span>
	clsCnsNull.<span style="color: black;">shadow_colour_custom</span>.<span style="color: black;">value</span> = <span style="color: #ff4500;">1</span>
	clsCnsNull.<span style="color: black;">B</span>.<span style="color: black;">value</span> = <span style="color: #ff4500;">1</span>
	clsCnsNull.<span style="color: black;">G</span>.<span style="color: black;">value</span> = <span style="color: #ff4500;">0.5</span>
&nbsp;
	<span style="color: #808080; font-style: italic;">#make cluster from selection</span>
	subComponent = xsi.<span style="color: black;">Selection</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>.<span style="color: black;">subComponent</span>
	cnsCls = subComponent.<span style="color: black;">CreateCluster</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;cnsCls&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
	<span style="color: #808080; font-style: italic;">#constrain object to cluster</span>
	cns = clsCnsNull.<span style="color: black;">Kinematics</span>.<span style="color: black;">AddConstraint</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;ObjectToCluster&quot;</span>,cnsCls<span style="color: black;">&#41;</span>
	cns.<span style="color: black;">tangent</span>.<span style="color: black;">value</span> = <span style="color: #ff4500;">1</span>
	cns.<span style="color: black;">dirx</span>.<span style="color: black;">value</span> = <span style="color: #ff4500;">0</span>
	cns.<span style="color: black;">diry</span>.<span style="color: black;">value</span> = -<span style="color: #ff4500;">1</span>
	cns.<span style="color: black;">upvct_active</span>.<span style="color: black;">value</span> = <span style="color: #ff4500;">1</span>
	cns.<span style="color: black;">upx</span>.<span style="color: black;">value</span> = <span style="color: #ff4500;">1</span>
	cns.<span style="color: black;">upy</span>.<span style="color: black;">value</span> = <span style="color: #ff4500;">0</span>
&nbsp;
	<span style="color: #808080; font-style: italic;">#make dorrito</span>
	dorrito = root.<span style="color: black;">AddNull</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;dorrito&quot;</span><span style="color: black;">&#41;</span>
	dorrito.<span style="color: black;">primary_icon</span>.<span style="color: black;">value</span> = <span style="color: #ff4500;">0</span>
	dorrito.<span style="color: black;">size</span>.<span style="color: black;">value</span> = <span style="color: #ff4500;">0.2</span>
	dorrito.<span style="color: black;">shadow_icon</span>.<span style="color: black;">value</span> = <span style="color: #ff4500;">8</span>
	dorrito.<span style="color: black;">shadow_colour_custom</span>.<span style="color: black;">value</span> = <span style="color: #ff4500;">1</span>
	dorrito.<span style="color: black;">G</span>.<span style="color: black;">value</span> = <span style="color: #ff4500;">1</span>
	dorrito.<span style="color: black;">shadow_offsetX</span>.<span style="color: black;">value</span> = <span style="color: #ff4500;">0.1</span>
	dorrito.<span style="color: black;">shadow_scaleX</span>.<span style="color: black;">value</span> = <span style="color: #ff4500;">0</span>
&nbsp;
	clsCnsNull.<span style="color: black;">AddChild</span><span style="color: black;">&#40;</span>dorrito<span style="color: black;">&#41;</span>
	dorrito.<span style="color: black;">kinematics</span>.<span style="color: black;">local</span>.<span style="color: black;">transform</span> = XSIMath.<span style="color: black;">CreateTransform</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
setupDorrito<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>The result&#8230;</p>
<p><img src='http://www.xsi-blog.com/userContent/upload/2007/05/setupdorrito.jpg' alt='setupdorrito.jpg' /></p>
<p>At work we call this controller a &#8220;Dorrito&#8221; because when the first &#8220;on the face&#8221; rig came out, one of our animators, Jason Taylor, started calling it that and it stuck. So my controller is a flat pyramid that looks like a Dorrito, so I suggest you do the same :) Now I will add an envelope to the cloned mesh and choose this Dorrito as a deformer. I now need to paint the cloned mesh&#8217;s envelope. The way I do this is add another deformer to the deformer list, set all the points to 100 % of this new deformer, and then choose the Dorrito and paint it&#8217;s influence. Once I am happy with the deformation I just remove the extra deformer from the envelope and I get zero weights except for where I painted the Dorrito&#8217;s influence. This deformer moves with the cluster constrained null, but it causes this nasty double transform when I rotate the head!</p>
<p><img src='http://www.xsi-blog.com/userContent/upload/2007/05/doubletransform.jpg' alt='doubletransform.jpg' /></p>
<p>Why is this happening? Because you have the first envelope on the original head which is deforming the points based on the transformation of the deformers (neck, head, and jaw). Then you have a &#8220;CopyOp&#8221; and another envelope above that is getting transformed by the same movement so XSI just does it twice! What you want to do is subtract that first envelope transformation from the second envelope transformation. The Static KineState gives you access to that intial position. If you take your deformer&#8217;s Static KineState property and set it&#8217;s parameters equal to the global transform parameters of your cluster constrained null you will effectively be constantly reseting the deformer&#8217;s initial position. Here is a script to setup the expressions between the cluster constrained null and the local deformer. Just select cluster constrained null first, then the Dorrito.</p>
</pre>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">#imports</span>
<span style="color: #ff7700;font-weight:bold;">import</span> win32com.<span style="color: black;">client</span>
<span style="color: #ff7700;font-weight:bold;">from</span> win32com.<span style="color: black;">client</span> <span style="color: #ff7700;font-weight:bold;">import</span> constants
&nbsp;
<span style="color: #808080; font-style: italic;">#globals</span>
xsi	= win32com.<span style="color: black;">client</span>.<span style="color: black;">Dispatch</span><span style="color: black;">&#40;</span> <span style="color: #483d8b;">&quot;XSI.Application&quot;</span> <span style="color: black;">&#41;</span>.<span style="color: black;">Application</span>
xsiPrint = xsi.<span style="color: black;">LogMessage</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> setupStaticState<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
	defList = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
	clsList = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
	<span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>,<span style="color: #008000;">len</span><span style="color: black;">&#40;</span>xsi.<span style="color: black;">Selection</span><span style="color: black;">&#41;</span>,<span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>:
		clsList.<span style="color: black;">append</span><span style="color: black;">&#40;</span>xsi.<span style="color: black;">Selection</span><span style="color: black;">&#40;</span>i<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
		defList.<span style="color: black;">append</span><span style="color: black;">&#40;</span>xsi.<span style="color: black;">Selection</span><span style="color: black;">&#40;</span>i+<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
	<span style="color: #ff7700;font-weight:bold;">for</span> a,b <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">zip</span><span style="color: black;">&#40;</span>defList,clsList<span style="color: black;">&#41;</span>:
		defKineState = a.<span style="color: black;">Properties</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Static KineState&quot;</span><span style="color: black;">&#41;</span>
		clsKine = b.<span style="color: black;">Properties</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Kinematics&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
		defKineState.<span style="color: black;">orix</span>.<span style="color: black;">AddExpression</span><span style="color: black;">&#40;</span>clsKine.<span style="color: black;">FullName</span> + <span style="color: #483d8b;">&quot;.global.rotx&quot;</span><span style="color: black;">&#41;</span>
		defKineState.<span style="color: black;">oriy</span>.<span style="color: black;">AddExpression</span><span style="color: black;">&#40;</span>clsKine.<span style="color: black;">FullName</span> + <span style="color: #483d8b;">&quot;.global.roty&quot;</span><span style="color: black;">&#41;</span>
		defKineState.<span style="color: black;">oriz</span>.<span style="color: black;">AddExpression</span><span style="color: black;">&#40;</span>clsKine.<span style="color: black;">FullName</span> + <span style="color: #483d8b;">&quot;.global.rotz&quot;</span><span style="color: black;">&#41;</span>
		defKineState.<span style="color: black;">posx</span>.<span style="color: black;">AddExpression</span><span style="color: black;">&#40;</span>clsKine.<span style="color: black;">FullName</span> + <span style="color: #483d8b;">&quot;.global.posx&quot;</span><span style="color: black;">&#41;</span>
		defKineState.<span style="color: black;">posy</span>.<span style="color: black;">AddExpression</span><span style="color: black;">&#40;</span>clsKine.<span style="color: black;">FullName</span> + <span style="color: #483d8b;">&quot;.global.posy&quot;</span><span style="color: black;">&#41;</span>
		defKineState.<span style="color: black;">posz</span>.<span style="color: black;">AddExpression</span><span style="color: black;">&#40;</span>clsKine.<span style="color: black;">FullName</span> + <span style="color: #483d8b;">&quot;.global.posz&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
setupStaticState<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Now you can rotate the head or jaw and the deformer just rides the mesh, you can even use shape animation and the deformer just rides on top of that with no double transform.</p>
<p><img src='http://www.xsi-blog.com/userContent/upload/2007/05/nodoubletransform.jpg' alt='nodoubletransform.jpg' /><br />
<a href='http://www.xsi-blog.com/userContent/upload/2007/05/dorritocap.mov' title='dorritocap.mov'>Viewport Capture</a></p>
<p><strong>Closing</strong></p>
<p>There are many ways to rig a face and none should be discarded from any rigger's toolbox. I hope other riggers will get some use out of this technique and will share their work with us. Before I go, I want to thank my rigging supervisor Remi McGill for suggesting the usage of the Static KineState and <a href="http://www.blur.com/">Blur</a> for allowing me to share with the community. Below are the project files which includes the scripts. Thanks for reading!</p>
<p><a href='http://www.xsi-blog.com/userContent/upload/2007/05/dorritoproject.zip' title='dorritoproject.zip'>Project Files</a></p>
<img src="http://www.softimageblog.com/?ak_action=api_record_view&id=209&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.softimageblog.com/archives/209/feed</wfw:commentRss>
		<slash:comments>21</slash:comments>
<enclosure url="http://www.xsi-blog.com/userContent/upload/2007/05/dorritocap.mov" length="254200" type="video/quicktime" />
		</item>
		<item>
		<title>FCurves As Shading Tools&#8230;</title>
		<link>http://www.softimageblog.com/archives/200#utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=fcurves-as-shaders</link>
		<comments>http://www.softimageblog.com/archives/200#comments</comments>
		<pubDate>Fri, 30 Mar 2007 04:33:35 +0000</pubDate>
		<dc:creator>Stefano Jannuzzo</dc:creator>
				<category><![CDATA[JScript]]></category>
		<category><![CDATA[Rendering]]></category>

		<guid isPermaLink="false">http://www.xsi-blog.com/archives/200</guid>
		<description><![CDATA[Let&#8217;s look at a short technique that will allow you to export any custom function curve or scripting math function to a texturable node to be used in the rendertree.
Let&#8217;s get a curve
We start by taking a poly strip, with a 100&#215;1 subdivisions. This will be our &#8220;drawing&#8221; table. We then make a cluster of [...]]]></description>
			<content:encoded><![CDATA[<p>Let&#8217;s look at a short technique that will allow you to export any custom function curve or scripting math function to a texturable node to be used in the rendertree.</p>
<p><strong>Let&#8217;s get a curve</strong></p>
<p>We start by taking a poly strip, with a 100&#215;1 subdivisions. This will be our &#8220;drawing&#8221; table. We then make a cluster of the whole set of points, and give it a weightmap. The range for the weights is set as wide as possible (-100, 100) to allow for both large positive and negative values. We then apply to the grid a custom property with a profile function curve, which you can then shape as you wish.</p>
<p>Here is a script that will do the steps mentioned above.</p>
<p><span id="more-200"></span></p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
</pre></td><td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">function</span> CreateGrid<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #006600; font-style: italic;">//create a poly strand, 100x1</span>
    <span style="color: #003366; font-weight: bold;">var</span> grid <span style="color: #339933;">=</span> CreatePrim<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;Grid&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;MeshSurface&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">null</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    SetValue<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;grid.grid.ulength&quot;</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">10</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    SetValue<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;grid.grid.vlength&quot;</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    SetValue<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;grid.polymsh.geom.subdivu&quot;</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">100</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    SetValue<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;grid.polymsh.geom.subdivv&quot;</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #006600; font-style: italic;">//create the cluster</span>
    SelectGeometryComponents<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;grid.pnt[*]&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    CreateCluster<span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #006600; font-style: italic;">//apply a weightmap</span>
    CreateWeightMap<span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">null</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">null</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;Weight_Map&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">null</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    SetValue<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;grid.polymsh.cls.Point.Weight_Map.red&quot;</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    SetValue<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;grid.polymsh.cls.Point.Weight_Map.blue&quot;</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    SetValue<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;grid.polymsh.cls.Point.Weight_Map.green&quot;</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #006600; font-style: italic;">//allow for large min and max weights</span>
    SetValue<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;grid.polymsh.cls.Point.Weight_Map.weightmapop.wmin&quot;</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">100</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    SetValue<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;grid.polymsh.cls.Point.Weight_Map.weightmapop.wmax&quot;</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">100</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000066; font-weight: bold;">return</span> grid<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
&nbsp;
<span style="color: #003366; font-weight: bold;">function</span> ApplyProfile<span style="color: #009900;">&#40;</span>grid<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #003366; font-weight: bold;">var</span> oCPSet <span style="color: #339933;">=</span> grid.<span style="color: #660066;">AddProperty</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;CustomProperty&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;ProfilePSet&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #003366; font-weight: bold;">var</span> oFCParam <span style="color: #339933;">=</span> oCPSet.<span style="color: #660066;">AddFCurveParameter</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;ProfileFC&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #003366; font-weight: bold;">var</span> oFCurve <span style="color: #339933;">=</span> oFCParam.<span style="color: #660066;">Value</span><span style="color: #339933;">;</span>
&nbsp;
    oFCurve.<span style="color: #660066;">SetKeys</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">new</span> Array<span style="color: #009900;">&#40;</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">0.25</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">0.5</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">0.5</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">0.75</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">0.8</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #003366; font-weight: bold;">var</span> grid <span style="color: #339933;">=</span> CreateGrid<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
ApplyProfile<span style="color: #009900;">&#40;</span>grid<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p><a href='/userContent/upload/2007/03/fm1.jpg' title='fm1.jpg'><img src='/userContent/upload/2007/03/fm1.jpg' alt='fm1.jpg' width='600' /></a></p>
<p><strong>Sampling the curve</strong></p>
<p>This is done by the following script.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
</pre></td><td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">function</span> SampleFunction<span style="color: #009900;">&#40;</span>pSet<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #003366; font-weight: bold;">var</span> par <span style="color: #339933;">=</span> pSet.<span style="color: #660066;">NestedObjects</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #003366; font-weight: bold;">var</span> fC <span style="color: #339933;">=</span> par.<span style="color: #660066;">value</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #003366; font-weight: bold;">var</span> pArray <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
    <span style="color: #003366; font-weight: bold;">var</span> vArray <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #006600; font-style: italic;">//fcurve min and max range</span>
    <span style="color: #003366; font-weight: bold;">var</span> rangeMin <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span>
    <span style="color: #003366; font-weight: bold;">var</span> rangeMax <span style="color: #339933;">=</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #003366; font-weight: bold;">var</span> range <span style="color: #339933;">=</span> rangeMax <span style="color: #339933;">-</span> rangeMin<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #003366; font-weight: bold;">var</span> x<span style="color: #339933;">,</span> y<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #006600; font-style: italic;">//number of samples, equal to the grid number of points along x</span>
    <span style="color: #003366; font-weight: bold;">var</span> nbSamples <span style="color: #339933;">=</span> <span style="color: #CC0000;">100</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span>i<span style="color: #339933;">=</span><span style="color: #CC0000;">0</span><span style="color: #339933;">;</span> i<span style="color: #339933;">&lt;</span> <span style="color: #339933;">=</span>nbSamples<span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #006600; font-style: italic;">//i-th column of points</span>
        pArray<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> i<span style="color: #339933;">*</span><span style="color: #CC0000;">2</span><span style="color: #339933;">;</span>
        pArray<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> i<span style="color: #339933;">*</span><span style="color: #CC0000;">2</span> <span style="color: #339933;">+</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">;</span>
&nbsp;
        x <span style="color: #339933;">=</span> rangeMin <span style="color: #339933;">+</span> range <span style="color: #339933;">*</span> <span style="color: #009900;">&#40;</span>i<span style="color: #339933;">/</span>nbSamples<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        y <span style="color: #339933;">=</span> fC.<span style="color: #000066; font-weight: bold;">Eval</span><span style="color: #009900;">&#40;</span>x<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">//value of the function at x</span>
&nbsp;
        vArray<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> vArray<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> y<span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">//values for the weight map</span>
&nbsp;
        <span style="color: #006600; font-style: italic;">//set the weights for the i-th column of points</span>
        PaintWeights<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;grid.polymsh.cls.Point.Weight_Map&quot;</span><span style="color: #339933;">,</span> pArray<span style="color: #339933;">,</span> vArray<span style="color: #339933;">,</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">//select the ProfilePSet first</span>
<span style="color: #003366; font-weight: bold;">var</span> profilePSet <span style="color: #339933;">=</span> selection<span style="color: #009900;">&#40;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
SampleFunction<span style="color: #009900;">&#40;</span>profilePSet<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>You just have to take care of setting the current range min and max correctly and then run it with the ProfilePSet. The script will simply sample the curve with the same rate as the grid subdivisions along x. The grid has 101 column of points along the x. We take the corresponding function values and stick them on the weightmap. Note that we&#8217;re using 100 samples, but we could have used much more for both the grid and the sampling rate.</p>
<p><strong>Plotting the weightmap</strong></p>
<p><a href='/userContent/upload/2007/03/fm2.jpg' title='fm2.jpg'><img src='/userContent/upload/2007/03/fm2.jpg' alt='fm2.jpg' width='600'/></a></p>
<p>We apply a color sampler lightmap shader. The input color to be sampled comes from a scalar lookup of the weightmap.</p>
<p>The writable map must be a hdr one (float .ct is my choice), in order to allow for large positive and negative values to be stored. Only the X resolution matters, since we are basically plotting a mono dimensional texture. The map is applied with a xz projection over the grid. You now just need to fire a tiny render region to have the lighmap written.</p>
<p><strong>Reusing the map</strong></p>
<p>As said, the map is one dimensional, so only the u matters when you look it up. So, if you pick a share vector node and connect it to an image lookup, the x coordinate of the vector acts as the input you are remapping by the original function curve. In this example, the lookup feeds the displacement, being the value to be remapped coming from a standard uv projection over the new grid.</p>
<p><a href='/userContent/upload/2007/03/fm3.jpg' title='fm3.jpg'><img src='/userContent/upload/2007/03/fm3.jpg' alt='fm3.jpg' width='600'/></a></p>
<p>What is important is to remember the range the function was originally sampled over, that must match the expected range of the value (the u coordinate in this example) you are going to remap.</p>
<p><strong>Sampling a scripting function</strong></p>
<p>As mentioned, you can also use this approach to paint any math function provided by your scripting function. Instead of using a function curve, you can simply loop and evaluate the desired function.</p>
<p>For instance, this is how you sample and weight paint a sin function in the -pi +pi range:</p>
</pre>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
</pre></td><td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">function</span> SampleSin<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #003366; font-weight: bold;">var</span> pArray <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
    <span style="color: #003366; font-weight: bold;">var</span> vArray <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #003366; font-weight: bold;">var</span> rangeMin <span style="color: #339933;">=</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">3.14159</span><span style="color: #339933;">;</span>
    <span style="color: #003366; font-weight: bold;">var</span> rangeMax <span style="color: #339933;">=</span> <span style="color: #CC0000;">3.14159</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #003366; font-weight: bold;">var</span> range <span style="color: #339933;">=</span> rangeMax <span style="color: #339933;">-</span> rangeMin<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #003366; font-weight: bold;">var</span> x<span style="color: #339933;">,</span> y<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #003366; font-weight: bold;">var</span> nbSamples <span style="color: #339933;">=</span> <span style="color: #CC0000;">100</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span>i<span style="color: #339933;">=</span><span style="color: #CC0000;">0</span><span style="color: #339933;">;</span> i<span style="color: #339933;">&lt;</span> <span style="color: #339933;">=</span>nbSamples<span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        pArray<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> i<span style="color: #339933;">*</span><span style="color: #CC0000;">2</span><span style="color: #339933;">;</span>
        pArray<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> i<span style="color: #339933;">*</span><span style="color: #CC0000;">2</span> <span style="color: #339933;">+</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">;</span>
&nbsp;
        x <span style="color: #339933;">=</span> rangeMin <span style="color: #339933;">+</span> range <span style="color: #339933;">*</span> <span style="color: #009900;">&#40;</span>i<span style="color: #339933;">/</span>nbSamples<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        y <span style="color: #339933;">=</span> Math.<span style="color: #660066;">sin</span><span style="color: #009900;">&#40;</span>x<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">//value of the function at x</span>
&nbsp;
        vArray<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> vArray<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> y<span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">//values for the weight map</span>
&nbsp;
        PaintWeights<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;grid.polymsh.cls.Point.Weight_Map&quot;</span><span style="color: #339933;">,</span> pArray<span style="color: #339933;">,</span> vArray<span style="color: #339933;">,</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

</pre>
<img src="http://www.softimageblog.com/?ak_action=api_record_view&id=200&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.softimageblog.com/archives/200/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
