<?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>duber's blog &#187; maxscript</title>
	<atom:link href="http://blog.duber.cz/category/3ds-max/maxscript/feed" rel="self" type="application/rss+xml" />
	<link>http://blog.duber.cz</link>
	<description>the official duber studio™ blog</description>
	<lastBuildDate>Thu, 22 Jul 2010 15:53:28 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>duberPython features demonstration!</title>
		<link>http://blog.duber.cz/3ds-max/duberpython-features-demonstration</link>
		<comments>http://blog.duber.cz/3ds-max/duberpython-features-demonstration#comments</comments>
		<pubDate>Thu, 04 Mar 2010 15:16:28 +0000</pubDate>
		<dc:creator>loocas</dc:creator>
				<category><![CDATA[3ds Max]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[maxscript]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[technical]]></category>

		<guid isPermaLink="false">http://blog.duber.cz/?p=457</guid>
		<description><![CDATA[
I&#8217;m trhilled to be able to finally showcase, at least, some of our very own Python implementation into 3ds Max!
First off, our primary reason for writing our own, proprietary, Python connection to 3ds Max is Tactic by Southpaw Technology. An awesome asset management system entirely written in Python that I decided to invest in and [...]]]></description>
			<content:encoded><![CDATA[<p><img src='http://blog.duber.cz/wp-content/uploads/duberpython_banner.png' alt='duberPython banner' /></p>
<p>I&#8217;m trhilled to be able to finally showcase, at least, some of our very own Python implementation into 3ds Max!</p>
<p>First off, our primary reason for writing our own, proprietary, Python connection to 3ds Max is <a href="http://southpawtech.com/tactic.html">Tactic by Southpaw Technology</a>. An awesome asset management system entirely written in Python that I decided to invest in and integrate our tools and software packages into. Another reason for this connection, later came up, was the need for writing much more complex scripts with complex GUIs, since, as you probably know, a few functional lines of code are hardly enough in a modern, efficient, VFX production of today. <img src='http://blog.duber.cz/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>The heart of our Python integration is <a href="http://www.microsoft.com/NET/">dotNET from Microsoft</a>. I can&#8217;t express myself enough how much I appretiate this framework! The brain of our Python integration is <a href="http://www.ironpython.net/">IronPython</a>. Also a product from Microsoft, completely open source and free, which are two very important aspects for any pipeline tool in any production facility of any size. Not the price as much as the availability of the software. And with IronPython and Microsoft, I am certain that this piece of software will be around for years!</p>
<p><span id="more-457"></span></p>
<p>So, what have we done?</p>
<ul>
<li>We&#8217;ve developed a bridge that connects MAXScript and Python via dotNET.</li>
<li>The bridge converts most of native Python and MAXScript data types to and from one another.</li>
<li>We&#8217;ve implemented several, custom, methods in Python that allow us to directly communicate with 3ds Max via MAXScript.</li>
<li>We&#8217;ve also implemented error reporting so that when an error is thrown in Python, it&#8217;ll return the exception in MAXScript for debuging.</li>
<li>Everything is based on dotNET and written in C#.</li>
<li>The best part? Our Python bridge is completely platform and 3ds Max version independent!</li>
</ul>
<p>Let me talk about the custom Python methods first. We&#8217;ve incorporated a class called <strong>mxsCon</strong>, that stores several methods for direct communication with 3ds Max as well as a variable<br />
that stores passed arguments from MAXScript to Python for greater flexibility, especially when executing short code snippets.</p>
<p>The initial design meant to provide a way of directly running Python code from within MAXScript. However, with more complex tools needed nowdays, this proved to be insufficient and thus we&#8217;ve developed a way of executing more complex Python scripts written externally using IronPython. This works perfectly well if you plan on using 3ds Max&#8217;s interpreter and just want to pass values around MAXScript and Python. This is perfectly efficitent and enough for writing really complex tools based on Python. In our case, it&#8217;s the connection to Tactic.</p>
<p>However, later, it occured to me that since we have most of the hard work done, why not bring everything over to the Python side. Since Python is such a great and powerful language, why bother with MAXScript! So we developed another method for executing MAXScript code directly within Python scripts and have the result, evaluated in MAXScript, be passed back to Python. IronPython that is. Since all the value conversions had already been done, this proved to be an extremely powerful and efficient way of writing very complex tools, now even, with very complex GUIs. Since everything is based on dotNET, we can utilise IronPython and some of the IDEs available for super quick GUI development. I used <a href="http://www.icsharpcode.net/OpenSource/SD/">SharpDevelop</a>, an open source IDE for writing dotNET applications, for all my GUI and code stuff. Then I just hook up MAXScript commands that I pass Python values to in order to perform some actions in 3ds Max, like opening a file from our server stored in Tactic. Or, create objects and list them in a ListView. Or even write a direct 3ds Max &#8211; Maya translator! Why not? <img src='http://blog.duber.cz/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Anyways, here are the methods and their purpose in 3ds Max:</p>
<ul>
<li>Python.run( &#60;string&#62; ) &#8212; will execute a Python script wrapped in double quotes (effectively a string).</li>
</ul>
<p>Example:</p>
<pre>
Python.run
(
	"import sys
	mxsCon.setResult( sys.version )"
)
</pre>
<p></br><br />
In this case, Python.run() will return whatever the mxsCon.setResult() will pass to it (more on that later).</p>
<ul>
<li>Python.runFromFile( &#60;string&#62; ) [ args:#() ] &#8212; will execute a Python script stored in an external file and alternatively pass it custom arguments.</li>
</ul>
<p>Example:</p>
<pre>
Python.runFromFile @"C:\myPythonScript.py" args:#( 10., true, #(1,2,3), "some string" )
</pre>
<p></br><br />
In Python, you&#8217;ll have to catch the passed arguments in order to use them, however the conversion of the data types will be done automatically for you.</p>
<ul>
<li>Python.inspect( &#60;data type&#62; ) &#8212; this method will inspect what data type you passed to it and how it will convert it to Python.</li>
<li>Python.getError() &#8212; this method returns the last unhandled exception in Python code.</li>
<li>Python.setVerbosity( &#60;int&#62; ) &#8212; allows you to set the level of verbosity for error reporting.</li>
<li>Python.getVerbosity() &#8212; retreives the level of verbosity you currently use.</li>
<li>Python.resetPy() &#8212; a very useful method for resetting our bridge residing in memory in case you&#8217;ve changed something radical in the source code etc&#8230;</li>
</ul>
<p>And here are the custom methods developed in C# for IronPython use in the scripts. These only exist when run via our Pythoner.dll module. If you run the Python scripts without Pythoner, you&#8217;ll have to handle their lack of presence. I&#8217;ve done this via a custom class that I import in the scripts I use. This is extremely flexible since when I run the code outside of 3ds Max, I can still use its functionality without having to deal with error handlers all over the place.</p>
<ul>
<li>mxsCon.setResult( &#60;data&#62; ) # this method will return whatever it encapsulates directly to 3ds Max as well as in Python should you need to work with it later in the script.</li>
</ul>
<p>Example:</p>
<pre>
import math

def myFunc( arg ):
	sum = arg + 100.
	return mxsCon.setResult( [arg, sum] )

if __name__ == '&#60;module&#62;':
	myFunc( math.pi )
</pre>
<p></br><br />
The myFunc function will not only return a List of whatever you pass to it as well as the result of addition, but it&#8217;ll also pass this List directly to MAXScript for later use in 3ds Max.</p>
<ul>
<li>mxsCon.getResult() # this method will only return the last value stored in memory using the .setResult() method. Useful for later usage in Python.</li>
<li>mxsCon.convert( &#60;data&#62; ) # this method will convert the input data types from Python to MAXScript compatible data types, but will return then wrapped as a string. This<br />
may be useful for other usage reasons. I used it for debugging or printing values in Python in MAXScript format.</li>
<li>mxsCon.execute( &#60;data&#62; ) # here&#8217;s where the magic happens. This method is quite complex. It not only evaluates whatever is passed to it in a String format, but it&#8217;ll also wait for the result from MAXScript and return it within Python. Another, very cool, feature of this method is similar to String formatting capabilities known from Python.</li>
</ul>
<p>Some examples of the mxsCon.execute() method:</p>
<pre>
# assume here's a ton of complex Python code that invokes this method
returnedVal = mxsCon.execute( r'Box()' )
# will create a box in 3ds Max and return OK (converted to True) back to Python.

returnedVal = mxsCon.execute( r'getDir {0}', r'#scripts' )</pre>
<p>The .execute method will first evaluate its input into a single string,<br />
in this case: r&#8217;getDir #scripts&#8217;, in a similar fashion the .format method works in Python.<br />
Then it&#8217;ll execute the command in MAXScript and retun its output back to Python.<br />
The output, in this case, will be a string: &#8216;C:\Program Files\Autodesk\3ds Max 2009\scripts&#8217;</p>
<p><a href="http://blog.duber.cz/wp-content/gallery/vids/pythoner_demo/pythoner_demo.html"><img src="http://blog.duber.cz/wp-content/uploads/pythoner_sharpdevelop_demo.png" alt="duberPython Features Demo" title="duberPython Features Demo" width="560" height="350" class="aligncenter size-full wp-image-468" /></a></p>
<p>But, enought with the talk, see it for yourself in action in this short Windows.Forms demo. (clicking the image will take you to the video)</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.duber.cz/3ds-max/duberpython-features-demonstration/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>duberPython is coming to life!</title>
		<link>http://blog.duber.cz/3ds-max/duberpython-is-coming-to-life</link>
		<comments>http://blog.duber.cz/3ds-max/duberpython-is-coming-to-life#comments</comments>
		<pubDate>Thu, 10 Dec 2009 23:59:03 +0000</pubDate>
		<dc:creator>loocas</dc:creator>
				<category><![CDATA[3ds Max]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[maxscript]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[technical]]></category>
		<category><![CDATA[alpha]]></category>
		<category><![CDATA[bridge]]></category>
		<category><![CDATA[communication]]></category>
		<category><![CDATA[conversion]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[duber]]></category>
		<category><![CDATA[duberpython]]></category>
		<category><![CDATA[independent]]></category>
		<category><![CDATA[IronPython]]></category>
		<category><![CDATA[pythonier]]></category>
		<category><![CDATA[tunnel]]></category>

		<guid isPermaLink="false">http://blog.duber.cz/3ds-max/duberpython-is-coming-to-life</guid>
		<description><![CDATA[
I am very excited to present a very early development results for our own Python implementation in 3ds Max.
First a bit of an intro. At duber, I&#8217;ve setup everything around Python, the most versatile and powerful language I&#8217;ve ever seen. I felt in love with Python so much that it even influenced my decision to [...]]]></description>
			<content:encoded><![CDATA[<p><img src='http://blog.duber.cz/wp-content/uploads/duberpython_banner.png' alt='duberPython banner' /></p>
<p>I am very excited to present a very early development results for our own Python implementation in 3ds Max.</p>
<p>First a bit of an intro. At duber, I&#8217;ve setup everything around <a href="http://www.python.org">Python</a>, the most versatile and powerful language I&#8217;ve ever seen. <a href="http://blog.duber.cz/3ds-max/im-loving-python">I felt in love with Python</a> so much that it even influenced my decision to leave <a href="http://eyeonline.com/Web/EyeonWeb/Products/fusion6/fusion6.aspx">Fusion</a> (my favourite compositing app) and dive into <a href="http://www.thefoundry.co.uk/pkg_overview.aspx?ui=CBC2593A-2C9F-4EF9-84BE-C198B0171453">Nuke</a> (my, now, most favourite compositing app). I even invested in a commercial data and asset management system, <a href="http://southpawtech.com/tactic.html">Tactic</a>, that is entirely written in Python. I run tons of custom Python scripts to tie together programs such as Tactic, Nuke, <a href="http://www.iridas.com/framecycler/">FrameCycler</a>, Photoshop etc&#8230; etc&#8230; But the last missing piece to the entire pipeline puzzle was 3ds Max.</p>
<p><span id="more-319"></span></p>
<p>There were initiatives to bring Python into Max, both from <a href="http://area.autodesk.com/blogs/chris/my_first_forays_into_net_and_ironpython_from_maxscript">Autodesk</a> and from <a href="http://forums.cgsociety.org/showthread.php?f=98&#038;t=816475">3rd party developers</a>. The problem is, none of those are final, open-source, nor fully functional.</p>
<p>What I need with Max, at least for now, is to be able to communicate with the Python tools running at my studio. I need Max to be able to communicate with Tactic. I need it to communicate with FrameCycler. And I need it to communicate with Nuke. Since I have most of the tiny scripts up and running that provide this communication layer, the last bit missing was Max being able to execute Python scripts and catch Python&#8217;s outputs.</p>
<p>We&#8217;ve achieved this with IronPython and a bit of C# magic.</p>
<p>Even though IronPython is different from CPython (the regular distro), it provides some additional functionality and mainly, it communicates flawlessly with dotNET. Another area that Max is well tied to. So this made for a perfect match! All we needed was a layer, a bridge of some sort, that&#8217;d make IronPython play nice with Max and vice versa. What we have right now is a very early Alpha build, very simple, elegant and light, that does just that! Maybe, if Autodesk doesn&#8217;t do it for us, we might extend this functionality beyond a simple communication layer and might actually make Python scripts command 3ds Max, so that we will be able to create objects, modify them, manipulate with the scene etc&#8230; etc&#8230; all directly via Python&#8217;s code. But for now, all I need is a two way communication tunnel that bridges the gap between MAXscript and Python. So far, we can run directly Python commands/scripts from within MAXScript code and we can run Python script files stored on the HDD and return results in MAXScript.</p>
<p>Here&#8217;s a sample of what we have right now:</p>
<p><img src='http://blog.duber.cz/wp-content/uploads/runpython.png' alt='Python scripts running directly from MXS' /></p>
<p><img src='http://blog.duber.cz/wp-content/uploads/runpython_str.png' alt='Python scripts running directly from MXS' /></p>
<p><img src='http://blog.duber.cz/wp-content/uploads/runpythonfile.png' alt='Python scripts running from a file inside of MXS' /></p>
<p>We&#8217;re working on proper data type wrapping right now. So far, we&#8217;ve got INTEGER, FLOAT and STRING types as well as DOUBLE type (naturally) being properly translated between MAXScript and Python. Hopefully I&#8217;ll have all the various data types being correctly translated to and from MAXScript and Python by the end of the week.</p>
<p>Also, the beauty of it is that it&#8217;s based on dotNET code and it was compiled independent on CPU architecture, which means it runs as fast and fine on both x86 machines and versions of Max as on x64 platforms. The other huge benefit is it is independent of 3ds Max entirely. It only requires dotNET Framework 3.5+ and IronPython libraries, but doesn&#8217;t require a recompile if I need it running under Max 9, 2008, 2009, 2010 or any other future versions of Max!</p>
<p>It is obviously not as robust or complex as <a href="http://forums.cgsociety.org/showthread.php?f=98&#038;t=816475">Blur&#8217;s latest Python plugin</a>, but thanks to that, it&#8217;s very versatile and flexible, which is great! <img src='http://blog.duber.cz/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://blog.duber.cz/3ds-max/duberpython-is-coming-to-life/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>An interesting concept behind Structs in MAXScript</title>
		<link>http://blog.duber.cz/3ds-max/an-interesting-concept-behind-structs-in-maxscript</link>
		<comments>http://blog.duber.cz/3ds-max/an-interesting-concept-behind-structs-in-maxscript#comments</comments>
		<pubDate>Tue, 08 Dec 2009 18:05:54 +0000</pubDate>
		<dc:creator>loocas</dc:creator>
				<category><![CDATA[3ds Max]]></category>
		<category><![CDATA[maxscript]]></category>
		<category><![CDATA[photos]]></category>
		<category><![CDATA[technical]]></category>
		<category><![CDATA[class]]></category>
		<category><![CDATA[classes]]></category>
		<category><![CDATA[custom]]></category>
		<category><![CDATA[inheritance]]></category>
		<category><![CDATA[instantiation]]></category>
		<category><![CDATA[method]]></category>
		<category><![CDATA[methods]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[referencing]]></category>
		<category><![CDATA[special]]></category>
		<category><![CDATA[struct]]></category>
		<category><![CDATA[structs]]></category>
		<category><![CDATA[variables]]></category>

		<guid isPermaLink="false">http://blog.duber.cz/3ds-max/an-interesting-concept-behind-structs-in-maxscript</guid>
		<description><![CDATA[I bumped into this issue of referencing values inside of Structs, which is a very elegant solution to using variables across your code, while avoiding global declarations. The issue was pretty much that I wasn&#8217;t aware of the implementation design of Structs in MAXscript.
Basically, Structs are these overly simplified custom classes know from such languages [...]]]></description>
			<content:encoded><![CDATA[<p>I bumped into this issue of referencing values inside of Structs, which is a very elegant solution to using variables across your code, while avoiding global declarations. The issue was pretty much that I wasn&#8217;t aware of the implementation design of Structs in MAXscript.</p>
<p>Basically, Structs are these overly simplified custom classes know from such languages as Python (to which I&#8217;ll try to compare these). However, Structs are really so simple that they don&#8217;t even implement such functionality as inheritance (a pitty by the way), or more advanced functionality known from Python. Structs, rather than classes, could be called <em>groups</em>. That&#8217;s what I&#8217;ve been using them for mainly. I grouped a bunch of functions and called them via a standard attribute reference paradigm.</p>
<p><span id="more-318"></span></p>
<p>Here&#8217;s a super simple Struct encapsulating a function that prints &#8220;HELLO WORLD&#8221;:</p>
<pre>
<code>struct tstStruct
(
	fn printHello =
	(
		print "HELLO WORLD"
	)
)</code>
</pre>
<p>You can then call the function via it&#8217;s <em>parent</em>, the struct, like this:<br />
<code>tstStruct.printHello()</code></p>
<p>A very convenient method for grouping tons of functions together and not messing around with namespaces or any other, possibly existing, names in your MAXScript session. However, after I read the article on avoiding using global variables at all times, over at <a href="http://tech-artists.org/wiki/Rollout_and_Struct_Pairs">tech-artists.org</a>, I discovered new possibilities and immediately started writing much cleaner and more elegant complex scripts! However, since I&#8217;m used to classes from Python and I&#8217;ve never used variables inside Structs, I bumped into a problem I didn&#8217;t know about. When you declare a struct with a variable in it, the variable isn&#8217;t immediately accessible from the outside of the Struct, you have to, sort of, initialize the variable at first. This is what I did wrong:</p>
<pre>
<code>struct tstStruct
(
	myVar = 0.,

	fn printHello =
	(
		print "HELLO WORLD"
	)
)</code>
</pre>
<p>I simply assumed that the variable is there and I can access and modify it at will. But I was wrong. You see, accessing the variable myVar right after the Struct&#8217;s declaration will throw this error:</p>
<pre>
<code>-- Unknown property: "myVar" in #Struct:tstStruct(
  myVar:&#60;data&#62;,
  printHello:&#60;fn&#62;)</code>
</pre>
<p>What I didn&#8217;t know was that I had to initialize the variables in the Struct in order to be able to access them. The problem was that Structs don&#8217;t provide special methods (functions) for such things as Python does, for example. So I couldn&#8217;t use something like the __init__ function. I fired up the MAXScript reference and read that in order to initialize the variables, I have to assign the Struct to a new object and explicitly assign to the variables, which is highly inconvenient, by the way. Anyways, here&#8217;s how to do it:</p>
<pre>
<code>struct tstStruct
(
	myVar = 0.,

	fn printHello =
	(
		print "HELLO WORLD"
	)
)

clsInst = tstStruct myVar:0.</code>
</pre>
<p>At that moment, you have to call the clsInst object in order to access all the functions and all the explicitly declared variables:</p>
<pre><code>clsInst.myVar; clsInst.printHello()</code>
</pre>
<p>Now it works as it should and I can use the variable inside the Struct to assign to and read from in my scripts, which is a very good practice as I&#8217;ve learned <img src='http://blog.duber.cz/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Let&#8217;s see how it&#8217;s done in Python. Python&#8217;s classes are the real deal, they support such advanced features as inheritance, multiple inheritance even, and also provide a much, much broader functionality, such as special methods. However, there is a bit of similarity between MAXScript&#8217;s Structs and Python&#8217;s Classes. Let&#8217;s see:</p>
<pre class="brush: py">
<code>class tstClass:
	myVar = 0.

	def __init__(self):
		self.testVal = 10.

	def printHello(self):
		print "HELLO WORLD"</code>
</pre>
<p>The simple code example above declared a new Class object named tstClass. The Class itself contains a variable object, myVar, a mandatory __init__ method and a custom function, printHello, similar in functionality to the MAXScript counterpart. However, the similar behavior of the Class and the Struct is in that when I call the Class directly and ask for its myVar variable, I get a value of 0.0, which is correct, since I haven&#8217;t initialized the Class object yet and thus the __init__ method wasn&#8217;t executed. The similarity is in that the Class wasn&#8217;t initialized, but I can still access the variable myVar without Python throwing an error. Which was what I assumed from MAXScript at first.</p>
<p>However, as soon as I initialize the Class by assigning the object to a new variable, I execute the __init__ method and thus overwrite the myVar variable with a value of 10.0. By calling this code snippet:</p>
<pre class="brush: py">
<code>instCls = testClass()

print testClass.testVal
print instCls.testVal</code>
</pre>
<p>I get this output:</p>
<pre class="brush: py">
<code>0.0
10.0</code>
</pre>
<p>Meaning that the myVar value called upon uninitialized Class is still the default 0.0, but as soon as the Class gets initialized, the variable gets assigned a value of 10.0 in the __init__ special method.</p>
<p>Unfortunately MAXScript doesn&#8217;t utilize special methods for its Structs, thus the initialization is a bit cumbersome and unintuitive, also quite inconvenient when having tons of variables in the Structs. Same goes for the <em>self</em> special object that references objects inside the Class, which is very handy.</p>
<p><strong>EDIT</strong>: As Mathieson pointed out in the comments below, you don&#8217;t need to explicitly call the variables when instantiating the Struct. All that really is needed is to instantiate the Struct properly for the inicialization process to take place and then you can access all the variables within the Struct. Thanks again to Mathieson for pointing that out!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.duber.cz/3ds-max/an-interesting-concept-behind-structs-in-maxscript/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Python in 3ds Max &#8211; FINALLY POSSIBLE!</title>
		<link>http://blog.duber.cz/3ds-max/python-in-3ds-max-finally-possible</link>
		<comments>http://blog.duber.cz/3ds-max/python-in-3ds-max-finally-possible#comments</comments>
		<pubDate>Sun, 25 Oct 2009 20:14:30 +0000</pubDate>
		<dc:creator>loocas</dc:creator>
				<category><![CDATA[3ds Max]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[maxscript]]></category>
		<category><![CDATA[opinions]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[technical]]></category>
		<category><![CDATA[access]]></category>
		<category><![CDATA[accessible]]></category>
		<category><![CDATA[blur]]></category>
		<category><![CDATA[blurpython]]></category>
		<category><![CDATA[embedded]]></category>
		<category><![CDATA[exec]]></category>
		<category><![CDATA[execute]]></category>
		<category><![CDATA[from]]></category>
		<category><![CDATA[in]]></category>
		<category><![CDATA[IronPython]]></category>
		<category><![CDATA[Max]]></category>
		<category><![CDATA[PyQt]]></category>
		<category><![CDATA[Qt]]></category>
		<category><![CDATA[run]]></category>
		<category><![CDATA[tactic]]></category>
		<category><![CDATA[trolltech]]></category>

		<guid isPermaLink="false">http://blog.duber.cz/3ds-max/python-in-3ds-max-finally-possible</guid>
		<description><![CDATA[
Yes! Once again, Blur studio showed how it&#8217;s supposed to be done.
They&#8217;ve released, or allowed their Eric Hulser to release, an updated version of their blurPython modules for 32bit and 64bit 3ds Max versions from Max 9 all the way up to 2009! And not only that. They&#8217;ve also provided libs and modules for tying [...]]]></description>
			<content:encoded><![CDATA[<p><img src='http://blog.duber.cz/wp-content/uploads/blurpython_banner.png' alt='blurPython Banner' /></p>
<p>Yes! Once again, <a href="http://www.blur.com">Blur studio</a> showed how it&#8217;s supposed to be done.</p>
<p>They&#8217;ve released, or allowed their Eric Hulser to release, an updated version of their <a href="http://forums.cgsociety.org/showthread.php?f=98&#038;t=816475">blurPython modules for 32bit and 64bit 3ds Max</a> versions from Max 9 all the way up to 2009! And not only that. They&#8217;ve also provided libs and modules for tying up Python, 3ds Max and Qt together! This is massive news as I&#8217;ve been trying to get Python (concretely IronPython) work in 3ds Max but I&#8217;ve been constantly hitting road blocks until I finally bumped into Blur&#8217;s updated blurPython.</p>
<p><span id="more-286"></span></p>
<p>The problem with IronPython would be the .NET classes that are required in order to embed IronPython inside 3ds Max. Since I don&#8217;t know C# at all, I&#8217;m not able to write custom wrappers to use in this combination, unfortunately. Another issue would be incompatibility with other programs that already run Python natively, such as Nuke or Maya, that I want to tie together under one managed pipeline environment in my studio. IronPython is a Microsoft opensource project that brings Python programming to .NET or vice-versa, which is great on many levels and I was really excited on bringing this to Max, since Max is already pretty tied in with .NET and I thought this might have been the best and easiest solution.</p>
<p>Well, nevermind, I&#8217;ll leave that part on Autodesk, if they ever decide to bring Python to Max. But for now, I&#8217;ll be happily enjoying Blur&#8217;s blurPython effort with Qt, which I was about to learn anyways (I bought a <a href="http://www.amazon.com/Programming-Python-Prentice-Software-Development/dp/0132354187/ref=sr_1_1?ie=UTF8&#038;s=books&#038;qid=1256498711&#038;sr=8-1">Rapid GUI Programming with Python and Qt</a> book a while back, but haven&#8217;t gotten to reading it yet).</p>
<p>After a few minutes fiddling with Python 2.6, Qt and a bunch of modules required in order to make blurPython run under Max, I&#8217;ve finally managed to get Python code executed and working correctly in Max!</p>
<p><a href='http://blog.duber.cz/wp-content/uploads/blurpython_max.png' title='blurPython running in Max internally' rel="lightbox[286]"><img src='http://blog.duber.cz/wp-content/uploads/blurpython_max.thumbnail.png' alt='blurPython running in Max internally' /></a></p>
<p>And with a bit of help from <a href="http://www.mackevision.de/index.html">Thorsten Kaufmann</a>, I also managed to get Python code up and running from an external editor, which is very useful! Although I use SciTe, which got implemented as a MAXScript Pro Editor in Max 2008, I believe, I can&#8217;t get lexer and other language syntax up and running in it since it&#8217;s heavily modified and fit for MAXScript only, which sucks. So I use SciTe externally for Python and simply run the code from there to show up in Max.</p>
<p><a href='http://blog.duber.cz/wp-content/uploads/blurpython_external.png' title='blurPython running in Max from external editor' rel="lightbox[286]"><img src='http://blog.duber.cz/wp-content/uploads/blurpython_external.thumbnail.png' alt='blurPython running in Max from external editor' /></a></p>
<p>The only drawback of this is the fact that we&#8217;ll be 100% dependant on Blur for maintainig these plugins and modules. Well, modules won&#8217;t be an issue, these are open-source, but the parts that are closed-source are inaccessible to other programmers. So, whatever Blur decides to do with their plugins, we&#8217;ll have to go their way. Which is a bit problematic for a studio to rely their entire 3ds Max pipline on this (like mine). But we&#8217;ll see, maybe Autodesk will acquire or at least somehow officially support Blur&#8217;s efforts. Maybe Blur will decide to release the package as an open-source project to the public, or perhaps as a commercial package? If not, we&#8217;ll still be dependant on on thing or another, but this might prove to be either a huge win or a huge loss situation. The pros are, thankfully, huge for me, at least. So I&#8217;ll take the risk and adopt blurPython in my pipeline, since I need it for accessing <a href="http://southpawtech.com/">Tactic</a> projects and SObjects from within Max.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.duber.cz/3ds-max/python-in-3ds-max-finally-possible/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>MAXScript Pro Editor&#8217;s automatic indentation drove me nuts!</title>
		<link>http://blog.duber.cz/3ds-max/maxscript-pro-editors-automatic-indentation-drove-me-nuts</link>
		<comments>http://blog.duber.cz/3ds-max/maxscript-pro-editors-automatic-indentation-drove-me-nuts#comments</comments>
		<pubDate>Sat, 16 Aug 2008 17:54:31 +0000</pubDate>
		<dc:creator>loocas</dc:creator>
				<category><![CDATA[3ds Max]]></category>
		<category><![CDATA[maxscript]]></category>
		<category><![CDATA[technical]]></category>
		<category><![CDATA[autoindent]]></category>
		<category><![CDATA[automatic]]></category>
		<category><![CDATA[back]]></category>
		<category><![CDATA[before]]></category>
		<category><![CDATA[default]]></category>
		<category><![CDATA[editor]]></category>
		<category><![CDATA[get]]></category>
		<category><![CDATA[indent]]></category>
		<category><![CDATA[indent.automatic]]></category>
		<category><![CDATA[indentation]]></category>
		<category><![CDATA[maintain]]></category>
		<category><![CDATA[Max]]></category>
		<category><![CDATA[MXS]]></category>
		<category><![CDATA[of]]></category>
		<category><![CDATA[override]]></category>
		<category><![CDATA[pro]]></category>
		<category><![CDATA[revert]]></category>
		<category><![CDATA[rid]]></category>
		<category><![CDATA[scintilla]]></category>
		<category><![CDATA[scite]]></category>
		<category><![CDATA[scripting]]></category>
		<category><![CDATA[to]]></category>

		<guid isPermaLink="false">http://blog.duber.cz/3ds-max/maxscript-pro-editor-automatic-indentation-drove-me-nuts</guid>
		<description><![CDATA[
I&#8217;ve gotten sick of the defaultly setup auto-indentation in MAXScript Pro Editor as I&#8217;m too used to the old-school MAXScript editor found in Max prior to 3ds Max 2008. Thankfully, since somebody at Autodesk had the brightest idea of implementing a very well-known and well-used Scintilla based text editor, we&#8217;re allowed to tweak and change [...]]]></description>
			<content:encoded><![CDATA[<p><img src='http://blog.duber.cz/wp-content/uploads/auto_indentation_banner.png' alt='Auto indentation banner' /></p>
<p>I&#8217;ve gotten sick of the defaultly setup auto-indentation in MAXScript Pro Editor as I&#8217;m too used to the old-school MAXScript editor found in Max prior to 3ds Max 2008. Thankfully, since somebody at Autodesk had the brightest idea of implementing a very well-known and well-used <a href="http://www.scintilla.org/">Scintilla</a> based text editor, we&#8217;re allowed to tweak and change any of the editor&#8217;s settings to our liking!</p>
<p><span id="more-88"></span></p>
<p>I simply love <strong>total control</strong> over <em>what I do</em> and <em>how I do it</em>. So, changing this behavior was a must for me. I opened up the <a href="http://scintilla.sourceforge.net/SciTEDoc.html">SciTE documentation</a> and looked up the auto indentation options. Thankfully, there was the one and only command that I needed in order to override the lexer pre-defined indentation for MAXScript code:</p>
<p><code>indent.maintain.<em>filepattern</em>=1</code></p>
<p>Easily enough, replace the <em>filepattern</em> property with <em>$(file.patterns.MAXScript)</em> and you&#8217;re done!</p>
<p>To include this tag in the actual MAXScript Pro Editor, open the MXS_Editor.properties file and paste this code below line 112 which should read: &#8220;#indent.auto=1&#8243; (if not, for the sake of tidyness, paste the line in the &#8220;#Indentation&#8221; area):</p>
<p><code>indent.maintain.$(file.patterns.MAXScript)=1</code></p>
<p>That&#8217;s it, now SciTE behaves exactly like the old-school MAXScript editor, indentation-wise, of course <img src='http://blog.duber.cz/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://blog.duber.cz/3ds-max/maxscript-pro-editors-automatic-indentation-drove-me-nuts/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Checksums in 3ds Max</title>
		<link>http://blog.duber.cz/3ds-max/checksums-in-3ds-max</link>
		<comments>http://blog.duber.cz/3ds-max/checksums-in-3ds-max#comments</comments>
		<pubDate>Sun, 10 Aug 2008 20:19:54 +0000</pubDate>
		<dc:creator>loocas</dc:creator>
				<category><![CDATA[3ds Max]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[maxscript]]></category>
		<category><![CDATA[technical]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[3d]]></category>
		<category><![CDATA[3ds]]></category>
		<category><![CDATA[checksum]]></category>
		<category><![CDATA[checksums]]></category>
		<category><![CDATA[class]]></category>
		<category><![CDATA[classes]]></category>
		<category><![CDATA[dotNET]]></category>
		<category><![CDATA[integration]]></category>
		<category><![CDATA[Max]]></category>
		<category><![CDATA[MD5]]></category>

		<guid isPermaLink="false">http://blog.duber.cz/3ds-max/checksums-in-3ds-max</guid>
		<description><![CDATA[After reading a very interesting and helpful article about checksums and how practical they are for comparing large datasets over at Adam Pletcher&#8217;s Tech Art Tiki blog, I was immediately interested in such methods as I&#8217;m doing some R&#38;D on data management in a larger creative environment and need such a feature. Unfortunately, MAXScript natively [...]]]></description>
			<content:encoded><![CDATA[<p>After reading a very interesting and helpful article about checksums and how practical they are for comparing large datasets over at <a href="http://techarttiki.blogspot.com/2008/03/checksums.html">Adam Pletcher&#8217;s Tech Art Tiki blog</a>, I was immediately interested in such methods as I&#8217;m doing some R&amp;D on data management in a larger creative environment and need such a feature. Unfortunately, MAXScript natively doesn&#8217;t support MD5 hashes (or any other kinds of hashes), so you&#8217;re pretty much stuck with just a few options.</p>
<p><span id="more-86"></span></p>
<p>One of them is, <a href="http://techarttiki.blogspot.com/2008/03/calling-python-from-maxscript.html">as Adam describes</a>, utilizing Python from within Max and call its native MD5 functions. There are two ways, but both are very limiting. One of them is registering a COM server from within Python and calling the functions through OLE objects from Max. The other possibility is using blur&#8217;s implementation of Python&#8217;s interpreter, blurPython, and calling the module, somehow, natively. Both of these methods work and are quite easy to setup, however, both of them are very hard to be deployed in a more complex environment.</p>
<p>What I need is an integrated MAXScript solution that yields the same result as the MD5 implementation in Python, so that I&#8217;ll be able to directly compare results from within Maya and Max for example. After searching the web and looking into the MD5 algorithm I quickly realized that re-writing the algorithm myself in MAXScript isn&#8217;t the way. But thankfully, Microsoft implemented a vast number of hash algorithms into its .NET framework as I learned on the web, so this looked like the obvious choice.</p>
<p>After a few minutes at the <a href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.aspx">MSDN central</a> I found what I&#8217;d been looking for. An actual MD5 implementation. However, as .NET is quite a comprehensive and large framework, the implementation isn&#8217;t as straight forward as the one found in Python. Nevertheless, all you need are two classes:</p>
<p><code>"System.Security.Cryptography.MD5"<br />
"System.Text.Encoding"</code></p>
<p>These are the .NET strings you&#8217;ll need for instancing the classes in MAXScript. So, let&#8217;s take a look at the code block:</p>
<p><code><br />
md5Class = dotNetClass "System.Security.Cryptography.MD5"<br />
encoding = dotNetClass "System.Text.Encoding"<br />
MD5 = md5Class.Create()<br />
</code></p>
<p>In this block, I&#8217;ve declared three variables, the first two were instances of the .NET classes and the last one, <em>MD5</em>, is a newly created object from the Cryptograpy.MD5 class called by the .NET .Create() method. You have a few options for the method to specify how the MD5 algorithm should treat your input, but I left it at default as I don&#8217;t need anything specific.</p>
<p>Now we are set to go through the last step, which is providing the MD5 object with arguments for computing the hash. This is done through another .NET method called .ComputeHash(). Unfortunately for us, the ComputeHash method only accepts either a Byte[] array or a Stream object (not sure whether it&#8217;d take a Max&#8217;s fileStream object directly, but mu guess is it wouldn&#8217;t) to generate the hash based on the input data. This is where the System.Text.Encoding class comes in handy, because it has a method for converting a string through a concrete character table (ASCII, UTF-8, etc&#8230;) to bytes. I&#8217;ve chosen the UTF-8 even though I&#8217;m certain I&#8217;m not likely to use anything beyond the ASCII table definition. The procedure to get the byte code of your string is as follows:</p>
<p><code><br />
encoding = dotNetClass "System.Text.Encoding"<br />
encoding.UTF8.GetBytes(myString)</code></p>
<p>Bear in mind that you can use different character tables to facilitate your concrete needs, but basically this is all you need to pass the MD5 function to calculate your checksum. With this knowledge, the following code is all there is to calculating correct MD5 checksums inside 3ds Max:</p>
<p><code>md5Class = dotNetClass "System.Security.Cryptography.MD5"<br />
encoding = dotNetClass "System.Text.Encoding"<br />
MD5 = md5Class.Create()<br />
hashArr = MD5.ComputeHash(encoding.UTF8.GetBytes(myString)) -- it's smarter to store the resulting array of byte values for later manipulation<br />
</code></p>
<p>The interesting part is that by default, this method returns an array of decimal numbers:</p>
<p><code>#(13, 87, 80, 212, 152, 226, 236, 248, 58, 163, 91, 29, 33, 199, 60, 102)</code></p>
<p>I don&#8217;t know of any .NET method or a property that&#8217;d return a standard hexadecimal value as we&#8217;re used to from, for example, Python. However, it is easy to overcome with a formatting function (since Max 2008 or with an AVG extension in previous versions) called <em>formattedPrint</em>. I wrote a custom function that solves this whole issue and does exactly what you&#8217;d expect from a natively implemented function, it simply expects a value and returns a hexadecimal (correctly formatted) string. Make sure you check the documentation for the correct <em>formattedString</em> arguments as they are quite important in this case for correct formatting of the hexadecimal values! Here&#8217;s the code:</p>
<p><code>fn MD5Checksum input =<br />
(<br />
&nbsp;&nbsp;&nbsp;&nbsp;md5Class = dotNetClass "System.Security.Cryptography.MD5"<br />
&nbsp;&nbsp;&nbsp;&nbsp;encoding = dotNetClass "System.Text.Encoding"<br />
&nbsp;&nbsp;&nbsp;&nbsp;myHash = "" as string<br />
&nbsp;&nbsp;&nbsp;&nbsp;myString = "" as string<br />
&nbsp;&nbsp;&nbsp;&nbsp;try (myString = input as string) catch (return false)<br />
&nbsp;&nbsp;&nbsp;&nbsp;MD5 = md5Class.Create()<br />
&nbsp;&nbsp;&nbsp;&nbsp;hashArr = MD5.ComputeHash(encoding.UTF8.GetBytes(myString))<br />
&nbsp;&nbsp;&nbsp;&nbsp;for o in hashArr do<br />
&nbsp;&nbsp;&nbsp;&nbsp;(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myHash += formattedPrint o format:"02x"<br />
&nbsp;&nbsp;&nbsp;&nbsp;)<br />
&nbsp;&nbsp;&nbsp;&nbsp;return myHash<br />
)</code></p>
<p>To sum this up, let&#8217;s compare this custom MD5 function based on .NET classes with Python&#8217;s native implementation. For the sake of completeness, here&#8217;s the code you&#8217;ll need in order to generate an MD5 hash in Python (I&#8217;ll use the same name &#8220;myString&#8221; for the string variable as in the MXS example above for clarity):</p>
<p><code>import hashlib<br />
hashlib.md5(myString).hexdigest()</code></p>
<p>Yeah, I know, very simple, isn&#8217;t it <img src='http://blog.duber.cz/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> Yet again, <a href="http://blog.duber.cz/3ds-max/im-loving-python">Python kicks some serious ass</a> here! Anyways, let&#8217;s test it on a long string (just to make sure both of the methods yield the same result) like:</p>
<p><code>"ThisIsAVeryLongStringThatIsHardToReadButShouldStressTestBothMethodsEnough"</code></p>
<p>Both MAXScript and Python return (strings):</p>
<p><code>"0d5750d498e2ecf83aa35b1d21c73c66"</code></p>
<p>So, this is it, now you should be more familiar with .NET classes, how they work from within MAXScript and that the whole .NET framework is one hell of a good job by Microsoft for developers of any kind, such as TDs working in DCC applications, which is sweet! <img src='http://blog.duber.cz/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://blog.duber.cz/3ds-max/checksums-in-3ds-max/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Connecting to a MySQL database from CG applications.</title>
		<link>http://blog.duber.cz/3ds-max/connecting-to-a-mysql-database-from-cg-applications</link>
		<comments>http://blog.duber.cz/3ds-max/connecting-to-a-mysql-database-from-cg-applications#comments</comments>
		<pubDate>Sat, 09 Aug 2008 22:19:19 +0000</pubDate>
		<dc:creator>loocas</dc:creator>
				<category><![CDATA[3ds Max]]></category>
		<category><![CDATA[Maya]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[maxscript]]></category>
		<category><![CDATA[technical]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[3d]]></category>
		<category><![CDATA[3ds]]></category>
		<category><![CDATA[accessing]]></category>
		<category><![CDATA[assembly]]></category>
		<category><![CDATA[connecting]]></category>
		<category><![CDATA[connection]]></category>
		<category><![CDATA[connector]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[dotNET]]></category>
		<category><![CDATA[Max]]></category>
		<category><![CDATA[ODBC]]></category>
		<category><![CDATA[string]]></category>
		<category><![CDATA[using]]></category>

		<guid isPermaLink="false">http://blog.duber.cz/3ds-max/connecting-to-a-mysql-database-from-cg-applications</guid>
		<description><![CDATA[I&#8217;ve been recently doing some R&#38;D on MySQL databases and connection through Python in Maya as well as Python in Max (through blurPython library), but I couldn&#8217;t seem to have found a way to connect to a MySQL database via ODBC. The problem lied in OLE methods as they&#8217;re not both much documented in MAXScript [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been recently doing some R&amp;D on MySQL databases and connection through Python in Maya as well as Python in Max (through blurPython library), but I couldn&#8217;t seem to have found a way to connect to a MySQL database via ODBC. The problem lied in OLE methods as they&#8217;re not both much documented in MAXScript reference and they&#8217;re tied to the operating system, not Max directly. But thankfully, I bumped into a solution today, out of a blue <img src='http://blog.duber.cz/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><span id="more-54"></span></p>
<p>To save you some time, don&#8217;t bother trying to connect to the database (db for short) via the standard example:<br />
<code>DogConn=createOLEObject "ADODB.Connection"<br />
DogConn.Open "driver={SQL Server}; server=localhost; database=test"</code></p>
<p>output:<br />
<code><OLEObject:ADODB.connection><br />
-- Runtime error: OLEObject method call failed:<br />
Error Message 1: [Microsoft][ODBC SQL Server Driver][DBNETLIB]SQL Server does not exist or access denied.<br />
method: open()</code></p>
<p>This concrete driver is a Microsoft SQL Server driver, so obviously, this doesn&#8217;t make much senese to use this method for connecting to a MySQL database. Since there are numerous ways of setting up the connection via different providers or drivers I was lost. But thankfully , Sun provides its own <a href="http://dev.mysql.com/downloads/connector/odbc/5.1.html">ODBC connectors</a> for various operating systems, including 64bit versions for Windows. So download the one that fits your OS and after installing it, just check what name the driver has assigned in the Data Sources(ODBC) under Administrative Tools. It should read &#8220;MySQL ODBC 5.1 Driver&#8221;, which is exactly what you need for successful connecting to a MySQL database. Easily enough, from the comprehensive list of example connection strings found at <a href="http://www.connectionstrings.com/?carrier=mysql">ConnectionStrings.com</a> I was finally able to write this code:</p>
<p><code>DogConn=createOLEObject "ADODB.Connection"<br />
DogConn.Open "Driver={MySQL ODBC 5.1 Driver};Server=serverName;Database=dbName;User=userName; Password=password"</code></p>
<p>Even though it returns &#8220;undefined&#8221;, don&#8217;t be alarmed, this is a good thing. So, now you&#8217;re good to go and start fully appretiating the whole database purpose and design!</p>
<p>As for dotNET. It&#8217;s much easier (as it&#8217;s Microsoft&#8217;s next &#8220;big thing&#8221;) to code for and also you&#8217;re less likely to bump into similar problems. Again, download <a href="http://dev.mysql.com/downloads/connector/net/5.2.html">the latest .NET connector from Sun</a> and try executing this snippet in Max 9+:</p>
<p><code>dotNet.loadAssembly "C:\\Program Files (x86)\\MySQL\\MySQL Connector Net 5.2.2\\Binaries\\.NET 2.0\\MySql.Data.dll"<br />
DBConnection = dotNetObject "MySql.Data.MySqlClient.MySqlConnection"<br />
DBConnection.ConnectionString = "Server=192.168.1.14;Database=test;Uid=root;Pwd=root"<br />
DBConnection.open()</code></p>
<p>dotNET works in a slightly different way. Instead of loading up a provider or service, it loads up an &#8220;assembly&#8221;, which is a dll, in this case Sun&#8217;s .NET connector, and then allows you to work with its methods. So I first loaded the dll up, then fired the dotNetObject function, then I specified the connection string and finally opened up the connection. Then you&#8217;re good to go!</p>
<p>Even simplier is the Python way of things, as usual <img src='http://blog.duber.cz/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> All you need is a <a href="http://sourceforge.net/projects/mysql-python">MySQLdb module available at SourceForge.net</a>, install it for your version of Python and then try running this code:</p>
<p><code>import MySQLdb as db<br />
conn = db.connect("serverName","userName","password","databaseName")</code></p>
<p>Now you&#8217;re ready for some serious querying! <img src='http://blog.duber.cz/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> It really is this simple and that&#8217;s why <a href="http://blog.duber.cz/3ds-max/im-loving-python">I&#8217;m really loving Python</a>. Anyways, these were just a few examples of how to connect to a MySQL database via ODBC, .NET and Python, which is really all you&#8217;ll ever need for connecting to MySQL from 3ds Max, Maya or XSI.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.duber.cz/3ds-max/connecting-to-a-mysql-database-from-cg-applications/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Dividing matrices is possible and quite useful.</title>
		<link>http://blog.duber.cz/3ds-max/dividing-matrices-is-possible-and-quite-useful</link>
		<comments>http://blog.duber.cz/3ds-max/dividing-matrices-is-possible-and-quite-useful#comments</comments>
		<pubDate>Sat, 12 Jul 2008 14:44:41 +0000</pubDate>
		<dc:creator>loocas</dc:creator>
				<category><![CDATA[3ds Max]]></category>
		<category><![CDATA[maxscript]]></category>
		<category><![CDATA[technical]]></category>
		<category><![CDATA[3ds]]></category>
		<category><![CDATA[divide]]></category>
		<category><![CDATA[dividing]]></category>
		<category><![CDATA[division]]></category>
		<category><![CDATA[link]]></category>
		<category><![CDATA[matrices]]></category>
		<category><![CDATA[matrix]]></category>
		<category><![CDATA[Max]]></category>
		<category><![CDATA[parent]]></category>
		<category><![CDATA[space]]></category>
		<category><![CDATA[transformation]]></category>

		<guid isPermaLink="false">http://blog.duber.cz/3ds-max/dividing-matrices-is-possible-and-quite-useful</guid>
		<description><![CDATA[I was trying to solve a problem when I had an object (a point helper) in a scene that was part of a hierarchy (in a rig) but I wanted the object to transform in a different object&#8217;s space than was its parent! Essentially, this means transforming objects in &#8220;AUX&#8221; pivots&#8217; space (if you know [...]]]></description>
			<content:encoded><![CDATA[<p>I was trying to solve a problem when I had an object (a point helper) in a scene that was part of a hierarchy (in a rig) but I wanted the object to transform in a different object&#8217;s space than was its parent! Essentially, this means transforming objects in &#8220;AUX&#8221; pivots&#8217; space (if you know MotionBuilder, you know where I&#8217;m going with this).</p>
<p><span id="more-79"></span></p>
<p>There is a simple way to get object&#8217;s transformation value in their parent space, the equation is as follows:</p>
<p><code>objectsOffsetTM = $myObject.transform * inverse $myObject.parent.transform</code></p>
<p>The resulting matrix3 value yields the exact transform of the object &#8220;MyObject&#8221; extracted in its parent space, which is extremely useful if you&#8217;ve done some, slightly advanced, rigging. Now, from this equation and with very basic math knowledge, one&#8217;d assume that when the only unknow in this formula would be the $MyObject.transform value, you&#8217;d divide the entire equation by the &#8220;inverse $MyObject.parent.transform&#8221; value and so you&#8217;d get something like this:</p>
<p><code>$myObject.transform = objectsOffsetTM / inverse $myObject.parent.transform</code></p>
<p>In fact, this is not possible as there&#8217;s no formal mathematical way defined for matrix divisions. Trying to do this will produce an error. However, with a little knowledge of math, you&#8217;ll be able to quickly rewrite the equation so that it uses defined math methods for matrices and get the transform for your object. In my case, however, I didn&#8217;t want to calculate the object&#8217;s parent space transformation from its own parent, but instead, I wanted to calculate the object&#8217;s parent space transformation from a completely separate object, which, in fact, lied on a totally different level of the hierarchy (in my rig). So, instead of using the formula above, you&#8217;d only swap the &#8220;parent&#8221; transformation value for a completely different transformation value, like so:</p>
<p><code>$myObject.transform = objectsOffsetTM / inverse $differentObject.transform</code></p>
<p>This formula is to give you an idea (off of the names of the variables used) what I needed. Now, this still throws an error, since, as stated above, you can&#8217;t divide matrices. How did I go about this issue then? Let&#8217;s use a simplified example to show the math principle behind this. The equation I&#8217;m using here is of this kind:</p>
<p><code>x = A * B</code></p>
<p>But, what if you don&#8217;t know &#8220;A&#8221;? How do you get the unknown &#8220;A&#8221; then?</p>
<p><code>A = x/B</code></p>
<p>Great, we finally arrived at the very destination which isn&#8217;t possible, as we can&#8217;t use divisions. Think for a second <img src='http://blog.duber.cz/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> a division is inverse multiplication, right? So, a variable &#8220;B&#8221; has to be inversed in order to use multiplication in the equation above. How to do that? Simple, a &#8220;B&#8221; on the power of 1 yields exactly the same value &#8220;B&#8221;, right? Inversion is defined as a power of &#8220;negative&#8221; exponent, which in this case is -1, so, the modified equation with this knowledge applied looks like this:</p>
<p><code>A = x * B^(-1)</code></p>
<p>That&#8217;s it! That&#8217;s all I needed for calculating the object&#8217;s transform from a known offset and a known different object transform. There&#8217;s only one little problem left to solve. How do you square a matrix? It&#8217;s easy when the exponent is positive, however, what if, like in this case, the exponent is actually negative? The math definition for non-positive exponent square in relation to the matrices is their &#8220;inverse&#8221; value. Thankfully, there&#8217;s a function in Max that does exactly that, it&#8217;s logically called &#8220;inverse&#8221; <img src='http://blog.duber.cz/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> Now, there&#8217;s nothing standing in our way to solve the problem! The resulting equation with all the math involved looks like this:</p>
<p><code>$myObject.transform = objectsOffsetTM * inverse(inverse $differentObject.transform)</code></p>
<p>You can simplify this as inverting an already inverse matrix is the matrix itself:</p>
<p><code>$myObject.transform = objectsOffsetTM * $differentObject.transform</code></p>
<p>See how simple that is <img src='http://blog.duber.cz/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> This equation in practice applied to an object in a scene looks as if the object was linked (parented) to the master object, while in fact, it&#8217;s not, which was the whole point of this example:</p>
<p><img src="http://blog.duber.cz/wp-content/plugins/flash-video-player/default_video_player.gif" /></p>
<p>One last note about matrices, don&#8217;t forget that matrices are not commutative, which means that A * B != B * A, so in this case the differentObject&#8217;s transform has to be pre-multiplied by the objectsOffsetTM matrix and not the other way around.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.duber.cz/3ds-max/dividing-matrices-is-possible-and-quite-useful/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Intermediate wheel rig.</title>
		<link>http://blog.duber.cz/3ds-max/intermediate-wheel-rig</link>
		<comments>http://blog.duber.cz/3ds-max/intermediate-wheel-rig#comments</comments>
		<pubDate>Wed, 25 Jun 2008 23:34:17 +0000</pubDate>
		<dc:creator>loocas</dc:creator>
				<category><![CDATA[3ds Max]]></category>
		<category><![CDATA[maxscript]]></category>
		<category><![CDATA[technical]]></category>
		<category><![CDATA[3ds]]></category>
		<category><![CDATA[direction]]></category>
		<category><![CDATA[intersection]]></category>
		<category><![CDATA[local]]></category>
		<category><![CDATA[matrix]]></category>
		<category><![CDATA[Max]]></category>
		<category><![CDATA[ray]]></category>
		<category><![CDATA[rough]]></category>
		<category><![CDATA[script]]></category>
		<category><![CDATA[speed]]></category>
		<category><![CDATA[spin]]></category>
		<category><![CDATA[spinning]]></category>
		<category><![CDATA[surface]]></category>
		<category><![CDATA[tracing]]></category>
		<category><![CDATA[transform]]></category>
		<category><![CDATA[vector]]></category>
		<category><![CDATA[wheel]]></category>

		<guid isPermaLink="false">http://blog.duber.cz/3ds-max/intermediate-wheel-rig</guid>
		<description><![CDATA[A friend of mine asked me how I&#8217;d go about rigging a wheel so that it spins no matter which direction it travels and stick to a ground as well. At first I thought this&#8217;d be a piece of cake as all I really needed was a direction vector and its magnitude to add to [...]]]></description>
			<content:encoded><![CDATA[<p>A friend of mine asked me how I&#8217;d go about rigging a wheel so that it spins no matter which direction it travels and stick to a ground as well. At first I thought this&#8217;d be a piece of cake as all I really needed was a direction vector and its magnitude to add to the rotation of the wheel. Well, the solution turned out NOT to be that simple in the end.</p>
<p>(the video lags a bit, but the entire rig is actually faster than real-time)<br />
<img src="http://blog.duber.cz/wp-content/plugins/flash-video-player/default_video_player.gif" /></p>
<p><span id="more-74"></span></p>
<p>Aside from bumping and dealing with a few 3ds Max &#8220;quirks&#8221;, I actually had to solve quite an interesting problem. When I start setting up a system/rig or working out a tricky problem I begin with the simplest possible scenario, so in this case I started with a simple one dimensional solution to the rotational problem. I simply sent the wheel master (that dragged all the helpers along) in one direction I wanted the wheel to spin. Obviously, this was the &#8220;forward&#8221; direction so that the wheel could actually turn. You can read about this simple solution at <a href="http://paulneale.com/tutorials/custAttributes/customAttributes.htm">Paul Neale&#8217;s web</a>, I simply based my solution on his procedure. However, as I said, this is only a one dimensional approach, which means, the system spins the wheel no matter which direction it travels. Besides, Paul&#8217;s example doesn&#8217;t take local rotation of the wheel into account. I needed a more robust solution: first of all, I needed a system that&#8217;d spin the wheel only when travelling forward or backward relatively to its orientation, so that it wouldn&#8217;t spin if, for example, the wheel was oriented perpendicular to the direction of travel. Secondly, I needed the wheel to &#8220;stick&#8221; to any given surface as it&#8217;d be used in an animation where the animator would, preferrably, only setup a direction of travel and the rig would take care of the rest of the secondary animation for them. This brought a new problem up as I&#8217;ll describe later.</p>
<p>So, back to the one dimensional solution. Essentially, all you need is a value about which the wheel center will spin. You can calculate that quite easily by multiplying the travelled distance by the circumference of the wheel. The circumference is 2*Pi*r, where r is the radius of the wheel. However, you subdivide the circumference by 6.28319 in Paul&#8217;s example, so, you can simply skip the 2*Pi calculation as that&#8217;s essentially the same value. In the end, all you need is the total distance travelled &#8216;v&#8217; (which is NOT a vector!) and the radius of the wheel. The formula is super simple: rotation = v/r. That&#8217;s it! <img src='http://blog.duber.cz/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> Really, there&#8217;s no catch to that, it simply works. Another note to take into account is that the whole system is history dependant, which means it has to start at a specific time and it has to be provided (updated) with a constant Dt (delta t = time step). So, go ahead and prepare your scene like in Paul&#8217;s tutorial.</p>
<p>Done? Good. You should now end up with a wheel that spins when moved in its &#8220;forward&#8221; or &#8220;backward&#8221; direction. The problems start when you move the wheel sideways, it still spins! Why is that? Well, the whole system is based on a position of the wheel in space, which, in other words, means a vector pointing from the origin to the wheel&#8217;s pivot. The other problem, directly associated with this approach, is that it doesn&#8217;t respect the local orientation of the wheel. I wanted to find a solution to this problem as well.</p>
<p>A local vector pointing in the direction where the wheel will be travelling was the obvious choice. But how do you get such a vector? You can&#8217;t derive the local direction of travel from the object itself as is. A vector is a direction with a magnitude, which is very important to realize, especially if your system is heavily dependant on both. So, to get the correct vector pointing in the direction where the wheel will be travelling AND having the correct magnitude of the actual speed of the wheel, you need to compare two points in time-space (master being a point helper controlling the position of the wheel):</p>
<p><code><br />
local posIncrement = 0.0 as float<br />
posIncrement = master.pos.y - (at time (currentTime-1) master.pos.y)<br />
rotation = (posIncrement+storedDistance)/(wheelRadius)<br />
</code></p>
<p>I just used the <em>at time</em> context to get the object&#8217;s previous x position and subtracted it from the current object&#8217;s x position. However, this method yields only the magnitude I was after, not the direction I also needed. So how do you go about this? First the theory: if you need to get a direction vector between two points, you need to subtract the two points in space, then, you can ask for the vector&#8217;s length to obtain its magnitude. So, basically, I subtract from a position at time t position at time t-1 and get the difference vector, which yields the direction the wheel will be travelling. The problem is, this doesn&#8217;t solve the problem with the wheel&#8217;s local orientation <img src='http://blog.duber.cz/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> To cover that, you need to multiply this resulting vector by the direction vector, which in my case was the Y axis as the wheel was originally aligned to the identity matrix when I was rigging it. The final snipped for this step looks like this:</p>
<p><code><br />
local posIncrement = 0.0 as float<br />
posIncrement = length((master.pos - (at time (currentTime-1) master.pos)) * master.transform.row2)<br />
rotation = (posIncrement+storedDistance)/(wheelRadius)<br />
</code></p>
<p>This gets me the positional incremet in the wheel&#8217;s local Y axis (row2 of the transform matrix is the projection vector of the object&#8217;s Y axis), if the Y axis is fully aligned to the direction it travels, the multiplication ratio will be 1:1 (if normalized! you should never scale control objects, due to this behavior!). So, this was it, I solved the problem in 1 dimension in respect to the local orientation of the wheel!</p>
<p>However, there is another problem when you extend the system to the point that the wheel actually sticks to a surface. The problem lies in the wheel&#8217;s Z direction it can travel as it adds to the final rotation. Why should I be concerned about the Z axis? Well, imagine a very rough terrain the wheel would be travelling on. If you move forward, it spins correctly without any &#8220;sliding&#8221;, however, if there&#8217;s a big bump in the way, the wheel actually spins slower than it should, because it only counts on the translation along the Y axis (in my case), not in the Z axis! A wheel is actually a two-dimensional object, like a circle, which can spin when touching any of the two world planes in the 2D space. Sphere, for example, is a fully three-dimensional object that can spin in any direction when touching any of the three world planes. You can see the result of the 2D solution on the video above where the wheel nicely sticks to the rough terrain no matter which direction it travels (as long as it&#8217;s aligned to the direction). So, how do you go about that? Well, you need to extend the whole formula into another dimension. In this case you need a two dimensional solution that&#8217;d take care of the translation in Y and Z axis. The script snippet would then look like this:</p>
<p><code><br />
local posIncrement = [0.0,0.0] as point2<br />
posIncrement.x = length((master.pos - (at time (currentTime-1) master.pos)) * master.transform.row2)<br />
posIncrement.y = length((master.pos - (at time (currentTime-1) master.pos)) * master.transform.row3)<br />
rotation = (length (posIncrement+storedDistance))/(wheelRadius)<br />
</code></p>
<p>Notice the use of a <em>point2</em> data type in this case. You need to store the positional increment for the Y axis as well as for the Z axis. You then sum it up with the stored distance value (also of a point2 data type) and ask for the length of the resulting vector, which gives you the magnitude, which is the distance the wheel travelled in the last time step.</p>
<p>That&#8217;s pretty much it, well, at least the most difficult part, there are other problems I had to face, which I don&#8217;t consider that difficult to solve, like the actuall snapping on the surface or dealing with negative time increments (i.e.: scrubbing through the time slider backwards) or dealing with Max&#8217;s script controllers not updating custom attribute variables correctly, which is an annoying bug. Well, I hope you&#8217;ve enjoyed this article at least as much as I enjoyed solving this little puzzle <img src='http://blog.duber.cz/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://blog.duber.cz/3ds-max/intermediate-wheel-rig/feed</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>3D procedural textures are actually 3D!</title>
		<link>http://blog.duber.cz/3ds-max/3d-procedural-textures-are-actually-3d</link>
		<comments>http://blog.duber.cz/3ds-max/3d-procedural-textures-are-actually-3d#comments</comments>
		<pubDate>Sat, 07 Jun 2008 17:30:09 +0000</pubDate>
		<dc:creator>loocas</dc:creator>
				<category><![CDATA[3ds Max]]></category>
		<category><![CDATA[maxscript]]></category>
		<category><![CDATA[technical]]></category>
		<category><![CDATA[3d]]></category>
		<category><![CDATA[display]]></category>
		<category><![CDATA[generate]]></category>
		<category><![CDATA[modeling]]></category>
		<category><![CDATA[noise]]></category>
		<category><![CDATA[procedural]]></category>
		<category><![CDATA[representation]]></category>
		<category><![CDATA[texture]]></category>
		<category><![CDATA[view]]></category>
		<category><![CDATA[viewport]]></category>
		<category><![CDATA[volume]]></category>

		<guid isPermaLink="false">http://blog.duber.cz/3ds-max/3d-procedural-textures-are-actually-3d</guid>
		<description><![CDATA[Have you ever thought that you actually can display a 3D procedural (such as Noise, Cellular etc&#8230;) in the 3D space? No? Well, then know that it is possible and it&#8217;s nothing difficult. Well, the most difficult part will be what should actually represent the color values. The representation is up to you, but for [...]]]></description>
			<content:encoded><![CDATA[<p>Have you ever thought that you actually can display a 3D procedural (such as Noise, Cellular etc&#8230;) in the 3D space? No? Well, then know that it is possible and it&#8217;s nothing difficult. Well, the most difficult part will be <em>what</em> should actually represent the <em>color</em> values. The representation is up to you, but for my experiment, I chose simple point helpers (nulls) of a very small size so that they looked almost like points (vertices would have done as well).</p>
<p>Take a look at this short video capturing the result of <em>modeling</em> a noise procedural:</p>
<p><img src="http://blog.duber.cz/wp-content/plugins/flash-video-player/default_video_player.gif" /></p>
<p><span id="more-64"></span></p>
<p>My approach used a very simple way of &#8220;sampling&#8221; points in space and testing, whether the noise texture in that particular point has a value higher or equal to 0.5 (again, you can choose whatever number you like, the range is from -1 to 1 for noise textures, I only scaled the resulting value to a 0 &#8211; 1 range, so 0.5 represents a value of 0.0). I chose a cubic volume (a box) in which I sampled 125 000 points and tested every one of them whether they lie in a color value higher than 0.5. The result yielded 67 632 actual TRUE values, which means that the algorythm created 67 632 point helpers in the exact spot where the color value of the noise function was higher than 0.0 (remember, I scaled the noise, so the test value was 0.5!). The final result can be seen in the short video above.</p>
<p>Now, how did I go about it. Firstly note that I wrote this algo. in about 1 minute <img src='http://blog.duber.cz/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> so it&#8217;s nowhere near being optimized or &#8220;clean&#8221;, but it was so simple to write I sticked with it, besides it worked, so, for the sake of the experiment, I didn&#8217;t bother investing more time into optimizing it etc&#8230; The basic idea is to sample a point in three axis in a given volume. The volume was specified by the box I created at the begining. I simply used it&#8217;s .min and .max properties to get the exact bounding box of the object (at first I wanted to try to sample points in a sphere, but then I ditched the idea as writing the actual sphere volume in a script would delay me too much from the experiment I wanted to perform) and then three loops to go through all the values in each of the axis in the volume by a certain increment (remember, you cannot calculate infinite formulas <img src='http://blog.duber.cz/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> ). Here&#8217;s the script that did all the work for me:</p>
<p><code><br />
step = 2<br />
volume = $Box01<br />
for i = volume.min.x to volume.max.x by step do<br />
(<br />
&nbsp;&nbsp;&nbsp;&nbsp;for j = volume.min.y to volume.max.y by step do<br />
&nbsp;&nbsp;&nbsp;&nbsp;(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for k = volume.min.z to volume.max.z by step do<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if noiseVal = 0.5*(1.0+(fractalNoise [i/20., j/20., k/20.] 0.5 2.0 5.0)) >= 0.5 do<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pt = point size:1.0 centerMarker:false axisTripod:false cross:false box:true constantScreenSize:true drawOnTop:false wireColor:white<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pt.pos = [i, j, k]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)<br />
&nbsp;&nbsp;&nbsp;&nbsp;)<br />
)<br />
</code></p>
<p>I told you it was simple! <img src='http://blog.duber.cz/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> The for loops go through the individual directions in the tripod-axis and stop each 2 units in that direction (in this case, the variable <em>step</em> controls this sampling) and tests whether the noise color value is greater than 0.5 then it continues on with the next point and so on and so forth. Each time it hits a value greater or equal to 0.5 it creates a point helper. That&#8217;s it, that&#8217;s all it does. <img src='http://blog.duber.cz/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> Obviously, this could be pushed much much farther, for example, you could actually model a geometrical object based on these values, but, quite frankly, I don&#8217;t think I&#8217;d be able to code that as that&#8217;d require some really complex algorythms to just generate the mesh from vertices it creates. But it&#8217;d be interesting to see what the actual mesh would look like as the points look a bit chaotic and blend together, visually.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.duber.cz/3ds-max/3d-procedural-textures-are-actually-3d/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
