<?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>Tommaso Sanguigni - Technical Director</title>
	<atom:link href="http://www.tommasosanguigni.it/blog/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://www.tommasosanguigni.it/blog</link>
	<description>Programming, 3d, visual effects</description>
	<lastBuildDate>Thu, 15 Sep 2011 10:22:36 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>tsPoseSpaceDeformer demo</title>
		<link>http://www.tommasosanguigni.it/blog/?p=118</link>
		<comments>http://www.tommasosanguigni.it/blog/?p=118#comments</comments>
		<pubDate>Thu, 15 Sep 2011 10:22:36 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.tommasosanguigni.it/blog/?p=118</guid>
		<description><![CDATA[This is a demo of one of my latest tools. It is inspired to the Michael Comet&#8217;s pose space deformer plugin, but with a substantial difference: no extra plugin is needed. The pose space deformation is realized by creating a corrective blendshape target driven by a node network. Here is how it works: - Select [...]]]></description>
			<content:encoded><![CDATA[
    <object type="application/x-shockwave-flash" data="http://www.youtube.com/v/hZxHHpsl2H8&rel=0&fs=1" width="720"  height="480">
    	<param name="movie" value="http://www.youtube.com/v/hZxHHpsl2H8&rel=0&fs=1" />
    	<param name="quality" value="high" />
    	<param name="allowFullScreen" value="true" />
    	<param name="allowScriptAccess" value="always" />
    	<param name="pluginspage" value="http://www.macromedia.com/go/getflashplayer" />
    	<param name="autoplay" value="false" />
    	<param name="autostart" value="false" />
			<embed src="http://www.youtube.com/v/hZxHHpsl2H8&rel=0&fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="720" height="480"></embed>
    	</object>
<p>This is a demo of one of my latest tools. It is inspired to the Michael Comet&#8217;s pose space deformer plugin, but with a substantial difference: no extra plugin is needed.<br />
The pose space deformation is realized by creating a corrective blendshape target driven by a node network.<br />
Here is how it works:</p>
<p>- Select your mesh in the binding pose. The tool will store the character pose as base pose;<br />
- Put your character in a problematic pose and press &#8216;Start sculpting&#8217;. A proxy mesh (the green one) is generated and lets you correct the mesh geometry to the desired shape. Once finished hit &#8216;Finalize scuplting&#8217;;<br />
- The next phase is connecting the corrective shape to your pose. You can choose between 3 different ways: (Attribute) Expression, (Attribute) Node network, (Joint) Radial distance.<br />
The first two work basically in the same way, except the first is a combination of an expression and a node network, while the second one is fully network based. Each attribute determining the pose<br />
is considered as a coordinate in a hyperspace. The blendtarget weight is the result of the normalized projection of the current pose vector on the &#8220;target pose &#8211; base pose&#8221; vector.<br />
The third way, instead working on the single attributes, it works on influence basis. The blendshape weight is the result of a combination of the radial distance between the base pose and the target pose for each influence determining the pose.<br />
- You can choose wich attributes/influences determine the pose on the Attribute list tab. The tool automatically proposes the influences that changed their coordinates from the base pose to the current pose.<br />
- There is an option for pruning the blendshape weights (You can see the auto pruned target maps in the video): very useful if you end up creating tons of corrective shapes and you don&#8217;t want to loose performance;<br />
- From the mirror frame, you can enable/disable the creation of the mirror blendshape;<br />
- Finally, to connect the blendshape and its mirror, just click on &#8220;Create corrective blendshape&#8221;.<br />
- Once finished, you can tweak the weights of your targets along the deformation by editing the ramp shaders driving them.</p>
<p>Future developments: </p>
<p>- High res sculpting for displacement map generation and driving.</p>
<p>Thanks for watching</p>
<p>Tommaso</p>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://www.tommasosanguigni.it/blog/?feed=rss2&amp;p=118</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Cover illustration, Cinema 4d bookazine</title>
		<link>http://www.tommasosanguigni.it/blog/?p=114</link>
		<comments>http://www.tommasosanguigni.it/blog/?p=114#comments</comments>
		<pubDate>Thu, 08 Sep 2011 13:14:40 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.tommasosanguigni.it/blog/?p=114</guid>
		<description><![CDATA[My &#8220;Mech Chameleon&#8221; illustration has been chosen as cover image for the Cinema 4d bookazine. You can check it out here: Cinema4D essentials]]></description>
			<content:encoded><![CDATA[<p>My &#8220;Mech Chameleon&#8221; illustration has been chosen as cover image for the Cinema 4d bookazine.<br />
You can check it out here:</p>
<p><a href="http://www.myfavouritemagazines.co.uk/design-bookazines/Cinema-4D-Essentials.html"></p>
<p><img src="http://www.tommasosanguigni.it/blog/uploads/2011/09/CBZ75.tommaso-232x300.jpg" alt="" title="CBZ75.tommaso" width="232" height="300" class="aligncenter size-medium wp-image-115" /></p>
<p>
Cinema4D essentials</p>
<p></a></p>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://www.tommasosanguigni.it/blog/?feed=rss2&amp;p=114</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>tsFrameBlendshapes tool</title>
		<link>http://www.tommasosanguigni.it/blog/?p=111</link>
		<comments>http://www.tommasosanguigni.it/blog/?p=111#comments</comments>
		<pubDate>Fri, 02 Sep 2011 11:29:32 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Maya Tools]]></category>
		<category><![CDATA[Python scripting]]></category>

		<guid isPermaLink="false">http://www.tommasosanguigni.it/blog/?p=111</guid>
		<description><![CDATA[This tool is part of my personal toolset. It let&#8217;s you easily create, connect and animate animation based corrective blendshapes,. Just go to the frame you want to correct/deform, hit &#8220;Sculpt&#8221; and edit the shape of your mesh. The cool thing is that the script works on pose: you can sculpt the corrective shape in [...]]]></description>
			<content:encoded><![CDATA[<p>This tool is part of my personal toolset.<br />
It let&#8217;s you easily create, connect and animate animation based corrective blendshapes,.<br />
Just go to the frame you want to correct/deform, hit &#8220;Sculpt&#8221; and edit the shape of your mesh. The cool thing is that the script works on pose: you can sculpt the corrective shape in any pose, then the script will bring back your deformed mesh in base pose automatically to create your corrective shape.<br />
Coded in python.</p>

    <object type="application/x-shockwave-flash" data="http://www.youtube.com/v/QWEi-9tkO-Q&rel=0&fs=1" width="720"  height="480">
    	<param name="movie" value="http://www.youtube.com/v/QWEi-9tkO-Q&rel=0&fs=1" />
    	<param name="quality" value="high" />
    	<param name="allowFullScreen" value="true" />
    	<param name="allowScriptAccess" value="always" />
    	<param name="pluginspage" value="http://www.macromedia.com/go/getflashplayer" />
    	<param name="autoplay" value="false" />
    	<param name="autostart" value="false" />
			<embed src="http://www.youtube.com/v/QWEi-9tkO-Q&rel=0&fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="720" height="480"></embed>
    	</object>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://www.tommasosanguigni.it/blog/?feed=rss2&amp;p=111</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Instancing random objects preserving frequency</title>
		<link>http://www.tommasosanguigni.it/blog/?p=105</link>
		<comments>http://www.tommasosanguigni.it/blog/?p=105#comments</comments>
		<pubDate>Sun, 06 Mar 2011 08:55:46 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python scripting]]></category>
		<category><![CDATA[R&D]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.tommasosanguigni.it/blog/?p=105</guid>
		<description><![CDATA[Hi all. After the post talking about the math involving frequency for procedural animation, it is now time to talk about the randomness. During the production in studio we had to deal with the following question: instantiate some base objects along particles randomly to form a crowd, using the Maya Instancer, but having the control [...]]]></description>
			<content:encoded><![CDATA[<p>Hi all. After the <a href="http://www.tommasosanguigni.it/blog/?p=40">post</a> talking about the math involving frequency for procedural animation, it is now time to talk about the randomness.</p>
<p>During the production in studio we had to deal with the following question: instantiate some base objects along particles randomly to form a crowd, using the Maya Instancer, but having the control over the count of the instances for each object (to have some characters less frequent than others).</p>
<p><strong>The Gaussian approach</strong></p>
<p>The most natural attempt would be using a <a href="http://en.wikipedia.org/wiki/Gaussian_distribution">Gaussian distribution</a> (or Normal distribution), which results in a non-uniform distribution of the samples, being more dense around the <strong>mean</strong> value, having the <strong>variance</strong> as measure of the width of  distribution.<br />
<img class="aligncenter size-medium wp-image-106" title="The Gaussian distribution" src="http://www.tommasosanguigni.it/blog/uploads/2011/03/350px-Normal_Distribution_PDF.svg_-300x192.png" alt="" width="300" height="192" /></p>
<p>Following the Gaussian approach, we can use the result of a random.gauss() function as the index of the element extracted from the list of our objects to instance:</p>
<pre class="brush: python; title: ;">

import random

numObjs =10
numSamples=600
dev=2

random.seed(2233)
l= range(numObjs)
count = [0 for x in l]

for i in range(numSamples-1):
    while True:
        v = int (abs(random.gauss(0,dev)))
        if v &lt; len(l):
            count[v] +=1
            break
print count
</pre>
<p>The list &#8220;l&#8221; contains the objects we want to instance (for the sake of simplicity, I filled it out with numbers as [0, 1, .... numObjs] ), wile numSamples reprents the numbers of object we want to instance (i.e. the number of <em>extractions</em>).<br />
To get stable results, I initialized the seed of the random function (!Important).<br />
What we are doing in the two nested loops is extracting #numSamples times a random value from the Gaussian distribution, having as mean value 0 (the bell centered at origin) and dev as the width of the bell curve. Since we are using the result of the extraction as index for the list containing our elements, the result must be an integer value and equal or greater than zero. Because our list has fixed size (equal to len(l) ) and the bell goes from -infinite to infinite, we repeat the estraction in case the resulting value is out of the list indices range.<br />
The code above produce the following count:</p>
<p>[209, 175, 112, 61, 37, 3, 2, 0, 0, 0]</p>
<p>As we can see, the values on the left are extracted more frequently than the one on the right.<br />
Because we are instancing objects, it would be nice to get some instances for each object.<br />
To achieve this, we can enlarge the width of the bell curve by increasing <strong>dev</strong>:</p>
<p>dev=3: [141, 126, 117, 82, 53, 38, 27, 12, 1, 2]</p>
<p>dev=5: [92, 94, 78, 86, 68, 64, 36, 35, 25, 21]</p>
<p>dev=10: [67, 69, 63, 65, 67, 52, 61, 59, 43, 53]</p>
<p>As the numbers above suggests, the higher the deviation, the more the values tend to be uniform. By playing with the dev value, we have a certain amount of freedom on driving the extraction frequency of each sample, thus the frequency of instancing of each object.<br />
Even if this approach is mathematically correct, it lacks on control over the real count (you can try to change the seed and you will easily get different values) plus it gives unpredictable results when the population (the number of base object) is numerically comparable to the number of extractions (the object to instance).<br />
For example, let&#8217;s see this case:</p>
<p>numObjs= 20, numSamples=30, dev=2:</p>
<p>[13, 7, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]</p>
<p>We see that the bell is not large enough to give at least one instance to the last elements. Let&#8217;s try to increase dev:</p>
<p>dev=10: [3, 6, 1, 2, 1, 2, 1, 0, 2, 2, 2, 1, 1, 0, 0, 0, 0, 1, 1, 3]</p>
<p>Now we get a more even distribution, but we see some 0s around: that means some objects will be never instanced and we can even see that the higher number is the second (while we expect to be the first one): that means the element we want to be more frequent is less frequent than the second one, by changing the seed, we could be more lucky, but for sure we don&#8217;t have full control of what&#8217;s going on.</p>
<p><strong>The Modulo approach</strong></p>
<p>Let&#8217;s follow another approach, using the <a href="http://en.wikipedia.org/wiki/Modulo_operation">Modulo operation</a>.<br />
If we want evenly distribute some objects extracted from a list, we can exctract the element at index:</p>
<p>index = #numObjs <strong>mod</strong> n</p>
<p>Where n represents the number of the current extraction:</p>
<pre class="brush: python; title: ;">

import random

l = [&quot;Obj1&quot;, &quot;Obj2&quot;, &quot;Obj3&quot;, &quot;Obj4&quot;, &quot;Obj5&quot;]
count = [0,0,0,0,0]

numInstances = 10

for i in range(numInstances):
    index = i %len(l)

    #instance object l[index]
    #...

    print l[index]
    count[index] +=1

print count
</pre>
<p>This code produces the following extractions: Obj1, Obj2, .., Obj5, Obj1, Obj2, .. and obviously the count would be equal for all objects (where the number of extractions is a multiple of the number of elements).<br />
To get a random and numerically stable extraction, we can shuffle our list:</p>
<pre class="brush: python; title: ;">

import random

random.seed(10)
l = [&quot;Obj1&quot;, &quot;Obj2&quot;, &quot;Obj3&quot;, &quot;Obj4&quot;, &quot;Obj5&quot;]
random.shuffle(l)
count = [0,0,0,0,0]

numInstances = 10

for i in range(numInstances):
    index = i %len(l)

    #instance object l[index]
    #...

    print l[index]
    count[index] +=1
</pre>
<p>The last step is adding the information about the frequency.<br />
Let&#8217;s set the frequency for each element and rebuild the list l by adding each element # times as much as its frequency. For instance:</p>
<p>f['Obj1'] = 3<br />
f['Obj2'] = 1<br />
f['Obj3'] = 2</p>
<p>Our list would be: l=['Obj1', 'Obj1', 'Obj1', 'Obj2', 'Obj3', 'Obj3']<br />
Now by shuffling this list, we can use the modulo function for the estraction, preserving the frequencies set above:</p>
<pre class="brush: python; title: ;">

import random

random.seed(10)

f=dict()

f[&quot;Obj1&quot;] = 3
f[&quot;Obj2&quot;] = 1
f[&quot;Obj3&quot;] = 2

l = list()

for k, v in f.items():
    for i in range(v):
        l.append(k)

print &quot;Base list: &quot;, l

random.shuffle(l)

print &quot;Shuffled list: &quot;, l

count = dict()

count[&quot;Obj1&quot;] = 0
count[&quot;Obj2&quot;] = 0
count[&quot;Obj3&quot;] = 0

numInstances = 6

for i in range(numInstances):
    index = i %len(l)

    #instance object l[index]
    #...

    count[l[index]] +=1

print &quot;Objects count: &quot;, count
</pre>
<p>The above code produces the following output:</p>
<p>Base list:  ['Obj1', 'Obj1', 'Obj1', 'Obj3', 'Obj3', 'Obj2']<br />
Shuffled list:  ['Obj2', 'Obj1', 'Obj1', 'Obj3', 'Obj1', 'Obj3']<br />
Objects count:  {&#8216;Obj1&#8242;: 3, &#8216;Obj3&#8242;: 2, &#8216;Obj2&#8242;: 1}</p>
<p>Let&#8217;s raise the number of instances (numInstances=600):</p>
<p>Objects count:  {&#8216;Obj1&#8242;: 300, &#8216;Obj3&#8242;: 200, &#8216;Obj2&#8242;: 100}</p>
<p>We can see that the frequency is preserved. Everything works so far, except one last thing: we are getting a pseudo-random extractions that repeats the sequence everytime we visit the whole list l.<br />
To get a more random behaviour, we can shuffle the list everytime we restart by extracting the first element, i.e.: index == 0:</p>
<pre class="brush: python; title: ;">

import random

random.seed(10)

f=dict()

f[&quot;Obj1&quot;] = 3
f[&quot;Obj2&quot;] = 1
f[&quot;Obj3&quot;] = 2

l = list()

for k, v in f.items():
    for i in range(v):
        l.append(k)

print &quot;Base list: &quot;, l

random.shuffle(l)

print &quot;Shuffled list: &quot;, l

count = dict()

count[&quot;Obj1&quot;] = 0
count[&quot;Obj2&quot;] = 0
count[&quot;Obj3&quot;] = 0

numInstances = 12

for i in range(numInstances):
    index = i %len(l)
    if index == 0:
        random.seed(i)
        random.shuffle(l)

    #instance object l[index]
    #...
    print l[index]
    count[l[index]] +=1

print &quot;Objects count: &quot;, count
</pre>
<p>And don&#8217;t forget to change your seed before the shuffle() operation, or you&#8217;ll get the same list over and over.<br />
The code above produces the following sequence: </p>
<p>Obj1, Obj1, Obj2, Obj1, Obj3, Obj3, Obj1, Obj2, Obj1, Obj1, Obj3, Obj3</p>
<p>With Objects count:  {&#8216;Obj1&#8242;: 6, &#8216;Obj3&#8242;: 4, &#8216;Obj2&#8242;: 2}.</p>
<p>Finally we got a way to instantiate objects randomly but preserving control over their frequency.<br />
I suggest to use the Gaussian approach only in case our base population is not numerically comparable to the number of instances.</p>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://www.tommasosanguigni.it/blog/?feed=rss2&amp;p=105</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>keyBaker tool</title>
		<link>http://www.tommasosanguigni.it/blog/?p=90</link>
		<comments>http://www.tommasosanguigni.it/blog/?p=90#comments</comments>
		<pubDate>Mon, 17 Jan 2011 20:46:48 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Maya Tools]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python scripting]]></category>

		<guid isPermaLink="false">http://www.tommasosanguigni.it/blog/?p=90</guid>
		<description><![CDATA[Download it here: Key Baker Purpose: This plugin bakes the animation on the selected objects and save the bake on a file. You can then import and apply the baked animation just by browsing the bake file in the Import tab. How it works: For each selected object, the script saves the values of each [...]]]></description>
			<content:encoded><![CDATA[<p>Download it here: <a href='http://www.tommasosanguigni.it/blog/uploads/2011/01/keyBaker.pyc.zip'>Key Baker</a></p>
<p><strong>Purpose:</strong><br />
	This plugin bakes the animation on the selected objects and save the bake on a file.<br />
	You can then import and apply the baked animation just by browsing the bake file in the Import tab.<br />
	<div id="attachment_92" class="wp-caption aligncenter" style="width: 310px"><img src="http://www.tommasosanguigni.it/blog/uploads/2011/01/Screen-shot-2011-01-17-at-12.31.33-PM-300x298.png" alt="" title="The export interface" width="300" height="298" class="size-medium wp-image-92" /><p class="wp-caption-text">The export interface</p></div><br />
<div id="attachment_94" class="wp-caption aligncenter" style="width: 308px"><img src="http://www.tommasosanguigni.it/blog/uploads/2011/01/Screen-shot-2011-01-17-at-12.33.09-PM-298x300.png" alt="" title="The import interface" width="298" height="300" class="size-medium wp-image-94" /><p class="wp-caption-text">The import interface</p></div></p>
<p><strong>How it works:</strong></p>
<p>	For each selected object, the script saves the values of each published and keyable attribute for each frame in the selected interval.<br />
When you apply the cache, the script simply looks for each object in the bake and keys the relative attributes to the values saved in the bake. </p>
<p>Be careful that applying the animation bake will destroy any keyframed animation currently set to your objects. Thus, the right way to go would be caching the animation and then applying the cache to a clean copy of the scene, with no keys, expressions or constraints that might control the published attributes.</p>
<p>Installation:<br />
	Copy the file keyBaker.pyc into your script folder, source the file and call the main() function, as shown here:</p>
<pre class="brush: python; title: ;">

import keyBaker
keyBaker.main()
</pre>
<p>For any suggestion, bug report or question, you are free to contact me.</p>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://www.tommasosanguigni.it/blog/?feed=rss2&amp;p=90</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Featured on Ballistic Publishing Exposè #8</title>
		<link>http://www.tommasosanguigni.it/blog/?p=84</link>
		<comments>http://www.tommasosanguigni.it/blog/?p=84#comments</comments>
		<pubDate>Mon, 10 Jan 2011 05:47:59 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.tommasosanguigni.it/blog/?p=84</guid>
		<description><![CDATA[Hi, My face is around the big artists over the globe, thanks to Ballistic publishing Exposè, issue #8. On the background the town where I grew up, Fondi (ITALY). href=&#8221;http://www.ballisticpublishing.com/books/expose/expose_8/artists.php]]></description>
			<content:encoded><![CDATA[<p>Hi,<br />
My face is around the big artists over the globe, thanks to Ballistic publishing Exposè, issue #8.<br />
On the background the town where I grew up, Fondi (ITALY).</p>
<p><a href="http://www.ballisticpublishing.com/books/expose/expose_8/artists.php"> href=&#8221;http://www.ballisticpublishing.com/books/expose/expose_8/artists.php</a></p>
<p><a href="http://www.tommasosanguigni.it/blog/?attachment_id=85" rel="attachment wp-att-85"><img src="http://www.tommasosanguigni.it/blog/uploads/2011/01/tomm_w-300x300.jpg" alt="" title="tomm_w" width="300" height="300" class="aligncenter size-medium wp-image-85" /></a></p>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://www.tommasosanguigni.it/blog/?feed=rss2&amp;p=84</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>OBJ flow exporter</title>
		<link>http://www.tommasosanguigni.it/blog/?p=77</link>
		<comments>http://www.tommasosanguigni.it/blog/?p=77#comments</comments>
		<pubDate>Thu, 16 Dec 2010 07:32:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Maya Tools]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python scripting]]></category>

		<guid isPermaLink="false">http://www.tommasosanguigni.it/blog/?p=77</guid>
		<description><![CDATA[This tool allows to export and import a mesh as a flow of OBJ files, driven by an expression, written in python. It is based on the standard Maya exporter plugin. Watch the preview here: It is a bit raw, but it does its work pretty well. We used it in production for managing a [...]]]></description>
			<content:encoded><![CDATA[<p>This tool allows to export and import a mesh as a flow of OBJ files, driven by an expression, written in python.<br />
It is based on the standard Maya exporter plugin.</p>
<p>Watch the preview here: 
    <object type="application/x-shockwave-flash" data="http://www.youtube.com/v/oFQLzl1PzIg&rel=0&fs=1" width="400"  height="385">
    	<param name="movie" value="http://www.youtube.com/v/oFQLzl1PzIg&rel=0&fs=1" />
    	<param name="quality" value="high" />
    	<param name="allowFullScreen" value="true" />
    	<param name="allowScriptAccess" value="always" />
    	<param name="pluginspage" value="http://www.macromedia.com/go/getflashplayer" />
    	<param name="autoplay" value="false" />
    	<param name="autostart" value="false" />
			<embed src="http://www.youtube.com/v/oFQLzl1PzIg&rel=0&fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="400" height="385"></embed>
    	</object></p>
<p>It is a bit raw, but it does its work pretty well. We used it in production for managing a metaball lava flow and it worked very fast.</p>
<p><strong>Installation</strong></p>
<p>Copy the .py file into your Maya scripts folder;</p>
<p>Import the script;</p>
<p>Call these functions:</p>
<p>displayExportUI(): for the exporting tool;</p>
<p>displayImportUI(): for the importing tool.</p>
<p>After the job is done, you can tweak the animation of your OBJ flow just by editing the expression created by the script.</p>
<p>You can download it here: <a rel="attachment wp-att-78" href="http://www.tommasosanguigni.it/blog/?attachment_id=78">bakeToObj.py.zip</a></p>
<p>Feel free to edit and improve the code and I&#8217;d like to keep updated for any improvement.</p>
<p><strong>Please note that once you import an obj flow, you have effectively separate meshes, that means you can&#8217;t for example use motion blur, since at each frame the visible mesh changes.</strong></p>
<p>Have fun!</p>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://www.tommasosanguigni.it/blog/?feed=rss2&amp;p=77</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Function createFollicle()</title>
		<link>http://www.tommasosanguigni.it/blog/?p=73</link>
		<comments>http://www.tommasosanguigni.it/blog/?p=73#comments</comments>
		<pubDate>Thu, 16 Dec 2010 04:05:18 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Code chunks]]></category>
		<category><![CDATA[Python scripting]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.tommasosanguigni.it/blog/?p=73</guid>
		<description><![CDATA[This function I wrote in python is very useful to create Follicles on surfaces and polygons, without the need of creating Hairs and then deleting the Hair System and the curves just to keep the follicles. Plus, of course, is a good chance to code something and to have a function you can use in [...]]]></description>
			<content:encoded><![CDATA[<p>This function I wrote in python is very useful to create Follicles on surfaces and polygons, without the need of creating Hairs and then deleting the Hair System and the curves just to keep the follicles.<br />
Plus, of course, is a good chance to code something and to have a function you can use in your scripts.</p>
<p><strong>How does it works..</strong></p>
<p>The function requires as parameters a list of 3 elements, named pos for a point position in 3d space and a nurbs surface OR a poly surface.</p>
<p>The follicle is located on the polygon/surface by finding the closest point on it from the given position.</p>
<p>I have included a second function, named createFollicles(), where you can pass an array of 3d points instead just one point. It will create multiple follicles.</p>
<p><strong>Here&#8217;s a quick example..</strong></p>
<p>I create a torus polygon, select some vertices, get their positions and create follicles on the vertices..</p>
<pre class="brush: python; title: ;">

torus = cmds.polyTorus()
cmds.select(torus[0]+&quot;.vtx[10]&quot;, torus[0]+&quot;.vtx[20]&quot;, torus[0]+&quot;.vtx[30]&quot;)
sel = cmds.ls(sl=1, fl=1)

for obj in sel:
	pos = cmds.pointPosition(obj, w=1)
	follicle = createFollicle(pos, poly_surface = torus[0])
	print follicle
</pre>
<p>Here&#8217;s the function code:</p>
<pre class="brush: python; title: ;">
import maya.cmds as cmds
import maya.OpenMaya as OpenMaya

def createFollicle (pos=[0, 0, 0], nurbs_surface=None, poly_surface=None):

	if (nurbs_surface==None and poly_surface==None):
		OpenMaya.displayError(&quot;Function createFollicle() needs a nurbs surface or poly surface&quot;)
		return

	transform_node = cmds.createNode(&quot;transform&quot;)
	cmds.setAttr((transform_node +&quot;.tx&quot;), pos[0])
	cmds.setAttr((transform_node +&quot;.ty&quot;), pos[1])
	cmds.setAttr((transform_node +&quot;.tz&quot;), pos[2])

	#make vector product nodes to get correct rotation of the transform node
	vector_product = cmds.createNode(&quot;vectorProduct&quot;)
	cmds.setAttr((vector_product+&quot;.operation&quot;), 4)
	cmds.connectAttr( (transform_node+&quot;.worldMatrix&quot;), (vector_product+&quot;.matrix&quot;), f=1)
	cmds.connectAttr( (transform_node+&quot;.rotatePivot&quot;), (vector_product+&quot;.input1&quot;), f=1)

	#connect the correct position to a closest point on surface node created
	if nurbs_surface:
		closest_position = cmds.createNode(&quot;closestPointOnSurface&quot;, n=(transform_node+&quot;_CPOS&quot;))
		cmds.connectAttr( (nurbs_surface+&quot;.ws&quot;), (closest_position+&quot;.is&quot;), f=1)
		cmds.connectAttr( (vector_product+&quot;.output&quot;), (closest_position+&quot;.inPosition&quot;), f=1)

	if poly_surface:
		closest_position = cmds.createNode(&quot;closestPointOnMesh&quot;, n=(transform_node+&quot;_CPOS&quot;))
		cmds.connectAttr( (poly_surface+&quot;.outMesh&quot;), (closest_position+&quot;.im&quot;), f=1)
		cmds.connectAttr( (vector_product+&quot;.output&quot;), (closest_position+&quot;.inPosition&quot;), f=1)

	#create a follicle node and connect it
	follicle_transform = cmds.createNode(&quot;transform&quot;, n=(transform_node+&quot;follicle&quot;))
	follicle = cmds.createNode(&quot;follicle&quot;, n=(transform_node+&quot;follicleShape&quot;), p=follicle_transform)
	cmds.connectAttr((follicle+&quot;.outTranslate&quot;), (follicle_transform+&quot;.translate&quot;), f=1)
	cmds.connectAttr((follicle+&quot;.outRotate&quot;), (follicle_transform+&quot;.rotate&quot;), f=1)
	if nurbs_surface:
		cmds.connectAttr((nurbs_surface+&quot;.local&quot;), (follicle+&quot;.is&quot;), f=1)
		cmds.connectAttr((nurbs_surface+&quot;.worldMatrix[0]&quot;), (follicle+&quot;.inputWorldMatrix&quot;), f=1)
	if poly_surface:
		cmds.connectAttr((poly_surface+&quot;.outMesh&quot;), (follicle+&quot;.inm&quot;), f=1)
		cmds.connectAttr((poly_surface+&quot;.worldMatrix[0]&quot;), (follicle+&quot;.inputWorldMatrix&quot;), f=1)

	cmds.setAttr((follicle+&quot;.parameterU&quot;), cmds.getAttr (closest_position+&quot;.parameterU&quot;))
	cmds.setAttr((follicle+&quot;.parameterV&quot;), cmds.getAttr (closest_position+&quot;.parameterV&quot;))

	#return strings
	cmds.delete(transform_node)
	return [follicle_transform, follicle, closest_position]

def createFollicles  (follicle_positions=[[0,0,0]], nurbs_surface=None, poly_surface=None):

	out_follicles=list()

	if (nurbs_surface==None and poly_surface==None):
		OpenMaya.displayError(&quot;Function createFollicles() needs a nurbs surface or poly surface&quot;)
		return

	for pos in follicle_positions:
		lst = createFollicle(pos, nurbs_surface, poly_surface)
		out_follicles.append(lst)
	return out_follicles
</pre>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://www.tommasosanguigni.it/blog/?feed=rss2&amp;p=73</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Function resolveName()</title>
		<link>http://www.tommasosanguigni.it/blog/?p=62</link>
		<comments>http://www.tommasosanguigni.it/blog/?p=62#comments</comments>
		<pubDate>Sun, 12 Dec 2010 04:34:49 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Code chunks]]></category>
		<category><![CDATA[MEL scripting]]></category>
		<category><![CDATA[Python scripting]]></category>

		<guid isPermaLink="false">http://www.tommasosanguigni.it/blog/?p=62</guid>
		<description><![CDATA[When you call this function, it gives you back a unique name in the Maya scene. Very useful when creating objects programmatically and you want to keep unique names in your scene (Essential when dealing with maya scripts). If the string passed as parameter is not assigned yet, then the function returns the string itself, [...]]]></description>
			<content:encoded><![CDATA[<p>When you call this function, it gives you back a unique name in the Maya scene. Very useful when creating objects programmatically and you want to keep unique names in your scene (Essential when dealing with maya scripts).</p>
<p>If the string passed as parameter is not assigned yet, then the function returns the string itself, else it will return the string plus &#8220;_#&#8221;.</p>
<p>Python code:</p>
<pre class="brush: python; title: ;">

def resolveName(n):
	name = n
	if cmds.objExists(n):
		i = 1
		while cmds.objExists(str(n) + &quot;_&quot; + str(i)):
			i+=1
		name = str(n) + &quot;_&quot; + str(i)
		print &quot;Warning: Object named &quot; + n + &quot; already exists. Used &quot; + name + &quot; instead.&quot;
	return name
</pre>
<p>MEL code:</p>
<pre class="brush: cpp; title: ;">
proc string resolveName(string $n){
	string $name = $n;
	if (`objExists $n`){
		int $i = 1;
		while (`objExists ($n + &quot;_&quot; + string($i))`){
			$i+=1;
		}
		$name = $n + &quot;_&quot; + string($i);
		print (&quot;Warning: Object named &quot; + $n + &quot; already exists. Used &quot; + $name + &quot; instead.&quot;);
	}
	return $name;
}
</pre>
<p><strong>Examples:</strong></p>
<p>Suppose you want to create a series of objects using the same name. By calling the function before the name you don&#8217;t have to worry about naming conflicts:</p>
<pre class="brush: python; title: ;">

import maya.cmds as cmds

num_spheres = 10
sphere_list = list()

for i in range(numspheres):
     new_sphere = cmds.sphere(n=resolveName(&quot;mySphere&quot;))
     sphere_list.append(new_sphere)
</pre>
<p>This will create the spheres mySphere, mySphere_1, mySphere_2 and so on.<br />
If you recall the function again, the numbering will start from the first available name.</p>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://www.tommasosanguigni.it/blog/?feed=rss2&amp;p=62</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Dealing with frequency in procedural animation</title>
		<link>http://www.tommasosanguigni.it/blog/?p=40</link>
		<comments>http://www.tommasosanguigni.it/blog/?p=40#comments</comments>
		<pubDate>Sun, 28 Nov 2010 03:05:11 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[R&D]]></category>

		<guid isPermaLink="false">http://www.tommasosanguigni.it/blog/?p=40</guid>
		<description><![CDATA[Back to the bouncing ball.. In the last days we had to deal with a procedural animation for the wings of a thinkerbell. The final animation consisted in having the wings flapping very fast and changing the speed along the animation. Easy task, isn&#8217;t it? To have a continuous animation, we could drive some parameters [...]]]></description>
			<content:encoded><![CDATA[<p>Back to the bouncing ball..</p>
<p>In the last days we had to deal with a procedural animation for the wings of a thinkerbell. The final animation consisted in having the wings flapping very fast and changing the speed along the animation.<br />
Easy task, isn&#8217;t it?<br />
To have a continuous animation, we could drive some parameters of our object by using a trigonometric function, i.e.:</p>
<p><a rel="attachment wp-att-46" href="http://www.tommasosanguigni.it/blog/?attachment_id=46"><img class="aligncenter size-medium wp-image-46" title="freq_0002_Background" src="http://www.tommasosanguigni.it/blog/uploads/2010/11/freq_0002_Background-300x158.jpg" alt="" width="300" height="158" /></a></p>
<p>But what if we animate the frequency value along time? Here&#8217;s what we may get:</p>
<p><a rel="attachment wp-att-47" href="http://www.tommasosanguigni.it/blog/?attachment_id=47"><img class="aligncenter size-medium wp-image-47" title="freq_0001_frequency f3" src="http://www.tommasosanguigni.it/blog/uploads/2010/11/freq_0001_frequency-f3-300x158.jpg" alt="" width="300" height="158" /></a></p>
<p>This translates into the motion of our 3d object as instantaneous jumps and changes of direction. The reason why this behaviour is that by changing the frequency of the sinus curve, we are squashing/stretching its base period, but the instantaneous phase is not kept, i.e. at the same instant we &#8216;see&#8217; different angles between the two curves.  Thus, to fix the problem, we have to impose that when we are changing the frequency, we keep the same instantaneous phases, i.e.:</p>
<p><a rel="attachment wp-att-41" href="http://www.tommasosanguigni.it/blog/?attachment_id=41"><img class="aligncenter size-medium wp-image-41" title="Eq phases" src="http://www.tommasosanguigni.it/blog/uploads/2010/11/eqphases1-300x165.jpg" alt="" width="300" height="165" /></a></p>
<p>As we can see, the new instantaneous phase brings an additional phase term p1, coming from the previous phase. This term must keep the same propery of the new instantaneous phase:</p>
<p><a rel="attachment wp-att-42" href="http://www.tommasosanguigni.it/blog/?attachment_id=42"><img class="aligncenter size-medium wp-image-42" title="eqphases2" src="http://www.tommasosanguigni.it/blog/uploads/2010/11/eqphases2-300x70.jpg" alt="" width="300" height="70" /></a></p>
<p>Please note that t is not the same between the first and the second term.</p>
<p>In general, to keep the continuity at each time t (in a discrete time, e.g. our frames), the instantaneous phase for t=tn can be written as:</p>
<p><a rel="attachment wp-att-43" href="http://www.tommasosanguigni.it/blog/?attachment_id=43"><img class="aligncenter size-medium wp-image-43" title="eqphases3" src="http://www.tommasosanguigni.it/blog/uploads/2010/11/eqphases3-300x70.jpg" alt="" width="300" height="70" /></a>Here&#8217;s how our final sinusioid will look like:</p>
<p><a rel="attachment wp-att-44" href="http://www.tommasosanguigni.it/blog/?attachment_id=44"><img class="aligncenter size-medium wp-image-44" title="eqphases4" src="http://www.tommasosanguigni.it/blog/uploads/2010/11/eqphases4-300x108.jpg" alt="" width="300" height="108" /></a>And here&#8217;s our example with the new formula applied:</p>
<p><a rel="attachment wp-att-48" href="http://www.tommasosanguigni.it/blog/?attachment_id=48"><img class="aligncenter size-medium wp-image-48" title="freq_0000_Layer 2" src="http://www.tommasosanguigni.it/blog/uploads/2010/11/freq_0000_Layer-21-300x158.jpg" alt="" width="300" height="158" /></a></p>
<p>Note in this case the curve has &#8216;broken tangents&#8217; at the points changing frequency. This because the resulting function is not continuous in C1, ie. for it&#8217;s derivate. To have smoother transitions, simply avoid instantaneus changes of frequency.</p>
<p>We can use this formula into an expression. Because the iterative sum, a smart way to evaluate the expression would be storing the partial sums along the playback of the animation:</p>
<p><a rel="attachment wp-att-49" href="http://www.tommasosanguigni.it/blog/?attachment_id=49"><img class="aligncenter size-medium wp-image-49" title="freq_ss1" src="http://www.tommasosanguigni.it/blog/uploads/2010/11/freq_ss1-300x175.jpg" alt="" width="300" height="175" /></a></p>
<p><a rel="attachment wp-att-49" href="http://www.tommasosanguigni.it/blog/?attachment_id=49"></a>Though this method is very efficient, it has some limitations. The partial sum is calculated according the previous expression evaluation, that means, if we scroll the timeline or jump back and forth during the playback (as usually animator do while working), we loose the exact counting of the partial sum and the result is wrong.  To fix that, at each expression evaluation we have to recalculate the whole sum, so the expression becomes state-independent:</p>
<p><a rel="attachment wp-att-50" href="http://www.tommasosanguigni.it/blog/?attachment_id=50"><img class="aligncenter size-medium wp-image-50" title="freq_ss2" src="http://www.tommasosanguigni.it/blog/uploads/2010/11/freq_ss2-300x175.jpg" alt="" width="300" height="175" /></a></p>
<p>So far so good&#8230; for now.</p>
<p>What about setting high frequencies? We might experiment ugly animations, jumps and even&#8230; no animation.</p>
<p>The reason is due to the downsampling of the motion described by our high frequency sinusoid and the frame rate chosen to playback in our animation, that usually is set as 24 fps.</p>
<p>Let&#8217;s consider this case:</p>
<p><a rel="attachment wp-att-51" href="http://www.tommasosanguigni.it/blog/?attachment_id=51"><img class="aligncenter size-medium wp-image-51" title="fsampling1" src="http://www.tommasosanguigni.it/blog/uploads/2010/11/fsampling1-300x257.jpg" alt="" width="300" height="257" /></a></p>
<p>Where the blue curve is our expression, the vertical red lines marks the frames and the red circles are the result of computation of the expression at each frame.</p>
<p>In this case it is easy to understand the movement of our object. Now let&#8217;s increase progressively the sinus frequence:</p>
<p><a rel="attachment wp-att-52" href="http://www.tommasosanguigni.it/blog/?attachment_id=52"><img class="aligncenter size-medium wp-image-52" title="fsampling2" src="http://www.tommasosanguigni.it/blog/uploads/2010/11/fsampling2-300x257.jpg" alt="" width="300" height="257" /></a></p>
<p><a rel="attachment wp-att-52" href="http://www.tommasosanguigni.it/blog/?attachment_id=52"></a>The jumps between the frames are slightly more marked but we can still perceive the motion. Keep increasing the frequence:</p>
<p><a rel="attachment wp-att-53" href="http://www.tommasosanguigni.it/blog/?attachment_id=53"><img class="aligncenter size-medium wp-image-53" title="fsampling3" src="http://www.tommasosanguigni.it/blog/uploads/2010/11/fsampling3-300x257.jpg" alt="" width="300" height="257" /></a></p>
<p>The movement starts to become fuzzy..</p>
<p><a rel="attachment wp-att-54" href="http://www.tommasosanguigni.it/blog/?attachment_id=54"><img class="aligncenter size-medium wp-image-54" title="fsampling4" src="http://www.tommasosanguigni.it/blog/uploads/2010/11/fsampling4-300x257.jpg" alt="" width="300" height="257" /></a></p>
<p><a rel="attachment wp-att-54" href="http://www.tommasosanguigni.it/blog/?attachment_id=54"></a>In this case the period of the sinusiod equals the time between 2 frames. Even if the expression describes a movement, the final result after sampling is no movement. The same effect verifies if we have the period equals to 2 fotograms.</p>
<p>Keep increasing the frequency:</p>
<p><a rel="attachment wp-att-55" href="http://www.tommasosanguigni.it/blog/?attachment_id=55"><img class="aligncenter size-medium wp-image-55" title="fsampling5" src="http://www.tommasosanguigni.it/blog/uploads/2010/11/fsampling5-300x257.jpg" alt="" width="300" height="257" /></a></p>
<p><a rel="attachment wp-att-55" href="http://www.tommasosanguigni.it/blog/?attachment_id=55"></a>In this case the movement can be perceived as a lower frequency signal, i.e. we perceive the object as it is slowing down.</p>
<p>All these effects are well known in signal theory, and as anticipated, is the result of the wrong sampling of the equation describing the motion. They can be also seen in the classic inverse wheel rotation effect.</p>
<p>Now the question is, what is our maximum frequency bound?</p>
<p>According the <a href="http://en.wikipedia.org/wiki/Nyquist%E2%80%93Shannon_sampling_theorem" target="_blank">Nyquist-Shannon theorem</a>, the maximum frequency we can have for a certain fs (sampling frequency, in our case is the fps) cannot be higher than fs/2. i.e., if we animate our object at a frequency higher than 12 sampling at 24 fps, we perceive a distorted motion.</p>
<p>A higher range of action in the computer graphics is given by the vector motion blur algorithm. In this case, even if the object &#8216;jumps&#8217; too much between adjacent frames, the blurring helps the viewer to perceive the motion.  Moreover the subsampling method of this algorithm captures the motion inbetween frames.</p>
<p>But even motion blur sumbsampling has its bounds. If the frequency of our object is higher than ( scene fps/2) * #subsamples, the algorithm perceives in input wrong motion, exactly as aforementioned.</p>
<p>In visual effects industry for extreme frequencies unreachable by the renderer even by using motion blur subsampling, a common technique consists in animating multiple copies of the object with lower frequencies and different phases and compositing the copies in post production.</p>
<p>A more accurate but computationally expensive way to sove the problem would be &#8216;supersampling&#8217; the frames, e.g. rendering at 48 fps and &#8216;downsampling&#8217; in post production.</p>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://www.tommasosanguigni.it/blog/?feed=rss2&amp;p=40</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

