3ds Max Mayhemhttp://area.autodesk.com/Topics of interest to people using and extending 3ds Max by Christopher Diggins. Sun, 24 May 2015 07:07:04 UTCCurvature to Vertex Color Modifier using Max Creation GraphChristopher Diggins<p>One popular request on the <strong><a href="/3dsMaxFeedback.autodesk.com">Autodesk 3ds Max Feedback site</a></strong>&nbsp;is the <strong><a href="http://3dsmaxfeedback.autodesk.com/forums/80695-general-feature-requests/suggestions/1495159-curvature-map#comments">curvature map</a></strong>.&nbsp;<span style="line-height: 1.5em;">While you can't create procedural texture maps with Max Creation Graphs (at least not now) you can create modifiers that set the vertex color map and then use the vertex color map to drive materials.</span></p> <div><span style="line-height: 1.5em;">https://www.youtube.com/watch?v=dEzwgBn7aqo.</span></div> <div><span style="line-height: 1.5em;"><br /></span></div> <p><span style="line-height: 1.5em;">In the zip file&nbsp;<strong><a href="/userdata/blogs/chris/CurvatureMCG.zip">CurvatureMCG.zip</a></strong>&nbsp;there are three tools and a few supporting compounds. To use the simply unzip the file into your MCG user folder&nbsp;(</span><span style="line-height: 1.5em;">%userprofile%/Autodesk/3ds Max 2016/Max Creation Graph) and restart 3ds Max. Alternatively you can go into the MCG editor and select "Operators &gt; Reload Operators" and then "Build &gt; Evaluate all Tools".</span></p> <p>In the package are three MCG modifiers:</p> <p><span style="line-height: 1.5em;">1.</span><span class="Apple-tab-span" style="white-space: pre;"> </span><strong>Curvature</strong> -&nbsp;<span style="line-height: 1.5em;">Computes curvature at each face-vertex based on the angle between the vertex normal and the face normal. The value is clamped at 90 degrees +/- a delta (default 10), converted to a gray scale value, and stored in the vertex color channel.</span></p> <p><span style="line-height: 1.5em;">2.</span><span class="Apple-tab-span" style="white-space: pre;"> </span><strong>SmoothVertexColors</strong> -&nbsp;<span style="line-height: 1.5em;">A modifier that smooths the vertex colors in two steps: </span><span style="line-height: 1.5em;">a.</span><span class="Apple-tab-span" style="white-space: pre;"> </span><span style="line-height: 1.5em;">Gives each face the same vertex color across the face.&nbsp;</span><span style="line-height: 1.5em;">b.</span><span class="Apple-tab-span" style="white-space: pre;"> </span><span style="line-height: 1.5em;">At each vertex averages the vertex color based on the vertex color of each contributing corner.&nbsp;</span></p> <p><span style="line-height: 1.5em;">3.</span><span class="Apple-tab-span" style="white-space: pre;"> </span><strong>VertexColorGrayScaleToColor</strong> -&nbsp;<span style="line-height: 1.5em;">A modifier for visualizing gray scale vertex colors. It converts gray-scale values in the vertex color channel to RGB where 0,0,0 is red, 0.5,0.5,0.5 is green, and 1.0,1.0,1.0 is blue.&nbsp;</span></p> <p><span style="line-height: 1.5em;">I'm also sharing with you a scene (<strong><a href="/userdata/blogs/chris/DragonWithCurvature.zip">DragonWithCurvature.zip</a></strong>) with the modifiers and a simple material applied to the Stanford dragon.</span></p> <h2>Under the hood</h2> <p><span style="line-height: 1.5em;">In order to understand what is going on in the MCG graphs, the key is to first understand how the TriMesh structure is organized as a set of immutable (unchanging) data-channels.&nbsp;</span><span style="line-height: 1.5em;">&nbsp;</span></p> <p><span style="line-height: 1.5em;"><img src="/userdata/blogs/chris/2015-04-19_2349.png" /></span></p> <p><span style="line-height: 1.5em;"><br /></span></p> <p>Data channels are arrays of data associated with different mesh elements: faces, vertices, face-vertices (i.e. the corners of each face), and edges. Data channels can have different types (Int32, Boolean, Single, Vector3, etc.) and can be either direct or indirect. A direct data channel mean the data buffer has the same length as the associated number of elements, and can be indexed in the same manner. An example of this are the material IDs data channel.&nbsp;<span style="line-height: 1.5em;">&nbsp;</span></p> <p>An indirect data channel has two arrays: the data buffer and an index buffer. The index buffer is the same length as the number of elements, and is used to lookup data elements. The most common example of this is the topology data channel. The topology data channel has a vertex buffer and an index buffer. The index buffer is the same length as the number of face-vertices (i.e. corners of faces). This is how most 3D APIs represent triangular meshes. &nbsp;We say that the topology channel is an indirect data channel of type "Vector3" that is associated with face-vertices.&nbsp;</p> <p>In 3ds Max a common category of data channel is called a MapChannel. In MCG the map channel is an indirect data channel of type Vector3 that is associated with face-vertices. Map channels are exposed to 3ds Max users via the <strong><a href="http://knowledge.autodesk.com/support/3ds-max/learn-explore/caas/CloudHelp/cloudhelp/2015/ENU/3DSMax/files/GUID-5945F5FC-0D14-48BF-B2C5-31CE6C4DCB05-htm.html">Channel Info Utility</a>&nbsp;</strong>which&nbsp;is one way to understand them better. &nbsp;</p> <h2><span style="line-height: 1.5em;">About Vertex Colors&nbsp;</span></h2> <p>Despite the somewhat misleading name v<span style="line-height: 1.5em;">ertex colors are a general purpose mechanism to store Vector3 data (triples of floating point values) with particular face-vertices. A face-vertex is a corner of a triangle. There are exactly N*3 face-vertices in a TrIMesh, where N is the number of face. This is usually different than the number of vertices, because multiple faces can share a vertex.</span></p> <p><span style="line-height: 1.5em;"><strong>BUG ALERT</strong>: due to a bug in the current version of MCG, the vertex data channel data buffer must have exactly N*3 data elements.&nbsp;</span></p> <p>For more information on Vertex Colors, and an arguably better explanation of mapping channels in general, I suggest reading the topic <strong><a href="http://help.autodesk.com/view/3DSMAX/2015/ENU/?guid=__files_GUID_CBBA20AD_F7D5_46BC_9F5E_5EDA109F9CF4_htm">Understanding Texture Coordinates and Vertex Colors</a></strong>&nbsp;in the MAXScript help.</p> <p>I hope you find the samples useful, and I'd love to hear what type of MCG tools you come up with that do magic with vertex colors!&nbsp;</p>Mon, 20 Apr 2015 03:29:39 UTChttp://area.autodesk.com/blogs/chris/curvature-to-vertex-color-modifier-using-max-creation-graphMax Creation Graph (MCG) Sample Pack for 3ds Max 2016Christopher Diggins<p>Now that 3ds Max 2016 is <strong><a href="http://www.autodesk.com/products/3ds-max/overview">available for download</a></strong>&nbsp;I'm pleased to announce a set of 30 sample MCG tools and 80 new compounds that you can download, use, and learn from!&nbsp;</p> <p><span style="line-height: 1.5em;">https://www.youtube.com/watch?v=ckfdHlzisTY</span></p> <div><span style="line-height: 1.5em;">In order to install the tools unzip the contents of </span><strong style="line-height: 1.5em;"><a href="/userdata/blogs/chris/MaxCreationGraph.zip" style="line-height: 1.5em;">MaxCreationGraph.zip</a></strong><span style="line-height: 1.5em;">&nbsp;</span><span style="line-height: 1.5em;"><span style="line-height: 1.5em;">and it into your Max Creation Group user folder. You can navigate directly to that folder by pasting</span></span> <pre>%userprofile%/Autodesk/3ds Max 2016/Max Creation Graph</pre> <span style="line-height: 1.5em;">into your Windows explorer.&nbsp;</span></div> <p>If you have any other compounds and tools installed, be sure to back them up first, in case some files in the zip package have the same name as existing files. When you restart 3ds Max you should see a number of new modifiers in the modifier pull-down. Each name of the new modifier starts with "A" (e.g. "APush"). There will also be a new category in the object creation panel called "Max Creation Graph" with several new tools.&nbsp;</p> <p>I have also created a sample test file that you can load once you unzip the tools and restart 3ds Max here:&nbsp;<strong><a href="/userdata/blogs/chris/MCGSampleTestScene.zip" style="line-height: 1.5em;">MCGSampleTestScene.zip</a></strong>.&nbsp;</p> <p><img src="/userdata/blogs/chris/MCGSampleScene.png" width="958" height="789" /></p> <p><span style="line-height: 1.5em;">Your comments and questions are certainly appreciated, enjoy!</span></p>Fri, 17 Apr 2015 03:59:49 UTChttp://area.autodesk.com/blogs/chris/max-creation-graph-mcg-sample-pack-for-3ds-max-2016Introducing Max Creation GraphsChristopher Diggins<h1>Introducing Max Creation Graphs (MCG)</h1> <p><img style="float: right;" src="/userdata/blogs/chris/basement.jpg" width="138" height="192" /><span style="line-height: 1.5em;">Now that <a href="/blogs/max/introducing-3ds-max-2016">3ds Max 2016 has been officially announced</a> I can finally come out of stealth mode and tell you why you haven't heard from me for over a year!</span></p> <p><a href="/blogs/max">Eddie Perlberg</a>&nbsp;had me locked me up in a basement along with Martin Coven and a team of talented developers and QA until we completed the&nbsp;<a href="http://3dsmaxfeedback.autodesk.com/forums/80695-general-feature-requests/suggestions/1467083-ice-for-3ds-max-modifiers">#1 most request feature for 3ds Max</a>.</p> <p><span style="line-height: 1.5em;">The result of our effort is a new feature in 3ds Max 2016 called the </span><strong style="line-height: 1.5em;">Max Creation Graph</strong><span style="line-height: 1.5em;"> editor (or MCG for short). This tool enables user to create modifiers, geometry, and utility plug-ins using a visual node-based workflow.</span></p> <p>With MCG you can create a new plug-in for 3ds Max in <b>minutes</b> by simply wiring together parameter nodes, computation nodes, and output nodes. The resulting graph can then be saved in an XML file (.maxtool) or be packaged with any compounds (.maxcompound) it depends in a ZIP file (.mcg) which you can share easily with 3ds Max users.</p> <p>https://www.youtube.com/watch?v=E2Pv2-zjHD4</p> <p>Once an MCG tool is evaluated you will have one of the following:</p> <ul> <li>New objects primitive in a the "Max Creation Graph" category in the creation panel</li> <li>A new modifier in the modifier pull-down</li> <li>A new MAXScript utility</li> <li>A new MAXScript function</li> </ul> <p><span style="line-height: 1.5em;">After evaluation two files are generated next to your .maxtool file</span></p> <ul> <li>A MAXScript plugin wrapper (.ms)</li> <li>A representation of the .NET function compiled from the graph (.txt)</li> </ul> <h2>MCG is not Softimage ICE</h2> <p>Despite the title of the original request on user feedback (which you might notice was first suggested by Martin Coven before we hired him, I'm sure he is glad to finally get his votes back) and the obvious similarities this is not an integration of Softimage ICE in 3ds Max. At the heart of MCG is a brand new visual programming language we developed on top of the .NET framework.</p> <p><img src="/userdata/blogs/chris/RingCloneGraph.png" width="1145" height="891" /></p> <p>Some of you may also be familiar with another open-source visual language from Autodesk called <a href="http://dynamobim.com/">Dynamo</a> and see some similarities. Dynamo is very similar to MCG (it is easy to extend using .NET and supports some functional programming concepts) but at the <a href="http://steellworks.blogspot.ca/2013/01/dynamo-fscheme-refactor-progress.html">core is an interpreter</a> whereas MCG is compiled directly to .NET byte-code. This design choice made sense for Dynamo, because it was designed for parametric geometry construction, however the performance was not sufficient to enable us to create tools for 3ds Max users.</p> <p>3ds Max users expect all parameters of geometry and modifiers to be able to be animated and to have the results updated in near real-time in the viewport (usually buildings don't dance, but they can in 3ds Max). Because of this requirement we had to develop a full compiler. I'll bore you with more details if you buy me a beer (or I accidentally start to blog while drinking).</p> <h2>A functional dataflow visual programming language</h2> <p>For the most part MCG is a traditional visual programming language. Nodes perform a transformation on data that flows through input connections and output the result to the output "value" connection.</p> <p>One characteristic of MCG that is immediately apparent is the fact that there are "function" connection outputs. This enables computations to flow through a graph as data. In computer science we call these <a href="http://en.wikipedia.org/wiki/First-class_function">first-class functions</a>.</p> <p style="padding-left: 30px;">When a node is connected from the "function" output, the entire left sub-graph is treated as a function, with unconnected inputs in the graph treated as function arguments. This is equivalent to the <a href="http://en.wikipedia.org/wiki/Lambda_calculus">lambda abstraction operation</a>. More on this in later tutorials.</p> <p>In MCG we can not only pass functions as arguments to higher-order functions like "Map" or "Combine" we can also return functions from operators such as "Bind" which performs a partial application or "Compose" which performs function composition. We can also store functions in arrays. I'll go into more details on this in a future blog post.&nbsp;</p> <p><img src="/userdata/blogs/chris/RingOfTeapots.png" style="line-height: 1.5em;" /></p> <p>A few things to note about MCG: most data that flows through the graph (with a few exceptions such as "INode", "Cache<t>", and "Random" objects) are immutable data structures. In other words MCG is nearly a pure functional programming language (like <a href="http://en.wikipedia.org/wiki/Haskell_(programming_language)">Haskell</a>). An example of this is that when you send data into a "SetValue" node the array you get on the other side is a new array, and the original one remains unchanged. This was done so that multi-threaded evaluation (e.g. via "ParallelMap") could be done quickly and easily. I promise more information on multithreading in a later post. </t></p> <h2>The Future</h2> <p>We are a publicly traded company which implies certain legal obligations, so unfortunately I can never talk about the future as much as I would like. It always makes me a bit sad, because I spend a lot of time thinking about the future &hellip; more time than my boss would like. :-)</p> <p>https://www.youtube.com/watch?v=tmudH_C97O4</p> <p>At the very least I hope that I have proven to you that by going on to <a href="/3dsMaxFeedback.autodesk.com">3dsMaxFeedback.autodesk.com</a> YOU are directly influencing the future. Yes, big requests might take four years to deliver on, and sometimes we can't tell you we are working on them (it is a very competitive business after all) but we are paying very close attention.</p> <p>I never forget that without the support of our users there would be no 3ds Max, and I wouldn't have my dream job.</p> <p><span style="color: #5d9013; font-family: ff-meta-web-pro, Arial, sans-serif; font-size: 24px; line-height: 1.2em;">Sample MCG Tools</span></p> <p>For some <a href="/blogs/chris/max-creation-graph-mcg-sample-pack-for-3ds-max-2016"><strong>sample MCG tools made by our team see this blog post</strong></a>.&nbsp;<span style="line-height: 1.5em;">There are also a number of 3rd party sample tools and videos posted on the </span><a href="https://www.facebook.com/groups/1611269852441897" style="line-height: 1.5em;"><strong>MCG Facebook page</strong></a><span style="line-height: 1.5em;">.</span></p> <p>On the Autodesk 3ds Max Learning Channel on YouTube you can find a tutorial series on Max Creation Graphs:&nbsp;</p> <p>https://www.youtube.com/watch?v=YBPVUvvMdD0&amp;list=PLnKw1txyYzRl1IVsbSFwd-c9i9cz-rRJ1</p> <p><span style="line-height: 1.5em;">For inspirstaion, here was the demo video made by Martin Coven:&nbsp;</span></p> <p><span style="line-height: 1.5em;">https://www.youtube.com/watch?v=3nsAlw_j4lQ</span></p> <div></div> <p><span style="color: #5d9013; font-family: ff-meta-web-pro, Arial, sans-serif; font-size: 24px; line-height: 1.2em;">Acknowledgements</span></p> <p>MCG would not have been possible without the hard work of a talented and passionate development team. The core team included Martin Coven as designer and instigator, myself as architect, along with Abdelhak Ouhlal, Attila Szabo, Clint Lewis, Rick Delesdernier, and Roman Woelker. Larry Minton and Tom Hudson also contributed at crucial points to help develop key functionality. Martin Ashton played an important role developing the initial prototype of MCG and I look forward to the tutorials he creates on his <a href="http://www.youtube.com/user/ScriptingSDKHowTos">YouTube SDK and scripting learning channel</a>.</p> <p>Of course this is an effort that spanned the entire 3ds Max team. No feature is developed in isolation, it takes an entire team of people working together to deliver 3ds Max. The whole team has worked hard to create a release that I am truly proud of.</p> <p>I personally want to thank Eddie Perlberg, Michael Russo, Kelcey Simpson, and Chris Young for believing that our team could deliver on such a bold and daring vision, and supporting us through the process.</p> <p>I also want to thank all of the Beta members and 3dsMaxFeedback contributors for their invaluable feedback, support, and encouragement.</p> <h2>Final Words</h2> <p><span style="line-height: 1.5em;">For now I want to leave you with the same words that Eddie shared with me recently "This is just the beginning."</span></p>Mon, 13 Apr 2015 01:07:37 UTChttp://area.autodesk.com/blogs/chris/introducing-max-creation-graphsPyQt UI in 3ds Max 2014 ExtensionChristopher Diggins<p>Chances are you are reading this because you want to write some UI for 3ds Max using Python. Because 3ds Max is fundamentally a Win32 application there are some challenges to overcome:</p> <ol> <li>Make your PyQt window is a proper child windows of 3ds Max</li> <li>Make sure that Python doesn't collect your objects</li> <li>Making sure that accelerators are disabled when your Widget has the focus</li> </ol> <h2>Making PyQt Windows a Child of 3ds Max</h2> <p>Digia provides a Qt module for C++ called <a href="http://doc.qt.digia.com/solutions/4/qtwinmigrate/winmigrate-walkthrough.html">QtWinMigrate</a> that was designed specifically to support mixing Qt with native Win32 UI. This <a href="/blogs/chris/embedding-qt-content-in-a-3ds-max-dockable-frame">works very well in C++</a> but unfortunately is not available by default in the PyQt or PySide packages. Luckily Blur studios wrapped make this package available in their <a href="https://code.google.com/p/blur-dev/downloads/list">binary PyQt distribution</a>. If you need to build it from sources yourself the <a href="https://github.com/glennra/PyQtWinMigrate">SIP sources can also be found online</a>.</p> <p>Once installed (note: I didn't install the Blur plug-ins. I have no idea how that could affect Python in the 3ds Max 2014 extension) you have to tell the 3ds Max Python engine where the PyQt module is. This can be done by updating the PYTHONPATH folder to point to the folder containing your Blur PyQt installation. For example I installed the Blur Qt into my regular Python installation folder, I set the PYTHONPATH user environment variable to "C:\Python27\Lib\site-packages".&nbsp; If you already have the PYTHONPATH variable you can append it to the list of paths, separating it from the others using a semicolon. If 3ds Max is running you will have to restart it before this change can take effect.</p> <p>A simple test to see if 3ds Max Python can find the PyQt is to write:<br />python.executeFile "demoPyVersionTool.py"</p> <p>On my system the result is:</p> <p>&nbsp;&nbsp;&nbsp; 3ds Max 2014 path environment variable c:\\program files\\autodesk\\3ds max 2014\\<br />&nbsp;&nbsp;&nbsp; MaxPlus module False<br />&nbsp;&nbsp;&nbsp; PyQt QT version 4.8.3<br />&nbsp;&nbsp;&nbsp; PyQt module True<br />&nbsp;&nbsp;&nbsp; PyQt version snapshot-4.9.5-9eb6aac99275<br />&nbsp;&nbsp;&nbsp; PySide module False<br />&nbsp;&nbsp;&nbsp; Python prefix C:\Program Files\Autodesk\3ds Max 2014\python<br />&nbsp;&nbsp;&nbsp; Python version 2.7.3 (default, Apr 10 2012, 23:24:47) [MSC v.1500 64 bit (AMD64)]<br />&nbsp;&nbsp;&nbsp; os module True<br />&nbsp;&nbsp;&nbsp; sys module True<br />&nbsp;&nbsp;&nbsp; #success<br />&nbsp;&nbsp;&nbsp;</p> <p>Once all of this is done you have to do a bit of extra work to get the 3ds Max HWND from the MaxPlus API because it is exposed as a SWIG object, and not a plain int. Here is a snippet of code that illustrates how to do this.</p> <pre class="prettyprint">import MaxPlus, ctypes from PyQt4 import QtGui, QtCore, QtWinMigrate def getMaxHwnd(): mem = long(MaxPlus.Win32.GetMAXHWnd()) return ctypes.c_longlong.from_address(mem).value class MaxWidget(QtGui.QMainWindow): def __init__(self): self.parent = QtWinMigrate.QWinWidget(getMaxHwnd()) QtGui.QMainWindow.__init__(self, self.parent)<br />&nbsp;</pre> <h2>Make sure that Python doesn't collect your objects</h2> <p>There is not much documentation on how to assure that Python doesn't collect your PyQt objects, and to be honest I don't know exactly what the best practice should be. The general principle is that Python needs to see at least one active reference to an object so that it doesn't collect it. For this purpose I use a class member variable to track custom high-level PyQt widgets that I create which I remove when the widget is closed. </p> <pre class="prettyprint">class _Widgets(object): _instances = [] class MaxWidget(QtGui.QMainWindow): def __init__(self): self.parent = QtWinMigrate.QWinWidget(getMaxHwnd()) QtGui.QMainWindow.__init__(self, self.parent) _Widgets._instances.append(self) def closeEvent(self, event): if self in _Widgets._instances: _Widgets._instances.remove(self)<br />&nbsp;</pre> <h2>Making sure that accelerators are disabled when your Widget has the focus</h2> <p>Another challenge with UI code in 3ds Max is that the main window of 3ds Max will interpret most key-presses as shortcut keys. When you have an edit field in a Python UI this can pose some obvious problems. Normally in regular 3ds Max UI programming we can use the DisableAccelerators API call to temporarily disable shortcut keys. The problem with PyQt is knowing exactly when to make this call.</p> <p>Intuitively we may think that overriding the Qwidget.focusInEvent() would work, but when using PyQt with Win32, the event is not triggered automatically when switching from a non-PyQt managed window to a PyQt window. The best approach that I have been able to come up with is to install an event filter of the QApplication instance that previews all mouse clicks. If the QApplication exposed to Python sees a mouse click, then we assume that a PyQt window has gained focus and we can disable accelerators. It&rsquo;s a bit hacky, and I'm sure the more experienced Python programmers out there can suggest an alternative, but this is the best I could find for now, at least until we can make improvements to the core.</p> <p>Putting this together with the other techniques here is a complete code example</p> <pre class="prettyprint"># To execute from MAXScript (if in your &lt;maxroot&gt;/scripts/python folder. # python.executeFile "auDemoPyQt.py" import MaxPlus import ctypes from PyQt4 import QtGui, QtCore # Requires PyQt4 binaries from Blur studios https://code.google.com/p/blur-dev/downloads/list from PyQt4 import QtWinMigrate # Get or create the application instance as needed # This has to happen before any UI code is triggered app = QtGui.QApplication.instance() if not app: app = QtGui.QApplication([]) def getMaxHwnd(): ''' Get the HWND of 3ds Max as an int32 ''' mem = long(MaxPlus.Win32.GetMAXHWnd()) return ctypes.c_longlong.from_address(mem).value class _Widgets(object): ''' Used to store all widget instances and protect them from the garbage collector ''' _instances = [] class _FocusFilter(QtCore.QObject): ''' Used to filter events to properly manage focus in 3ds Max. This is a hack to deal with the fact that mixing Qt and Win32 causes focus events to not get triggered as expected. ''' def eventFilter(self, obj, event): # We track any mouse clicks in any Qt tracked area. if event.type() == QtCore.QEvent.MouseButtonPress: print "Mouse down", obj elif event.type() == 174: # QtCore.QEvent.NonClientAreaMouseButtonPress: print "Non-client button press", obj else: return False MaxPlus.CUI.DisableAccelerators() return False class MaxWidget(QtGui.QMainWindow): # Note: this does not work automatically when switching focus from the rest of 3ds Max # to the PyQt UI. This is why we have to install an event filter. def focusInEvent(self, event): print "Focus gained on MaxWidget" MaxPlus.CUI.DisableAccelerators() def __init__(self): print "Creating MaxWidget" self.parent = QtWinMigrate.QWinWidget(getMaxHwnd()) QtGui.QMainWindow.__init__(self, self.parent) _Widgets._instances.append(self) # Install an event filter. Keep the pointer in this object so it isn't collected, and can be removed. self.filter = _FocusFilter(self) app.installEventFilter(self.filter) def closeEvent(self, event): print "Closing MaxWidget" if self in _Widgets._instances: _Widgets._instances.remove(self) # Very important, otherwise the application event filter will stick around for app.removeEventFilter(self.filter) class MyWidget(QtGui.QWidget): def btnPressed(self): print "Button pressed" if self.parent(): self.parent().setFocus() def __init__(self): QtGui.QWidget.__init__(self) self.topLayout = QtGui.QGridLayout() self.nextLayout = QtGui.QGridLayout() self.textEdit = QtGui.QTextEdit() self.textEdit.setText("Hello world") self.btn = QtGui.QPushButton("Apply") self.btn.pressed.connect(self.btnPressed) self.nextLayout.addWidget(self.textEdit) self.nextLayout.addWidget(self.btn) self.topLayout.addLayout(self.nextLayout, 0, 0) self.setLayout(self.topLayout) def main(): main = MaxWidget() w = MyWidget() main.setCentralWidget(w) main.show() if __name__ == '__main__': main()</pre>Wed, 11 Dec 2013 19:47:02 UTChttp://area.autodesk.com/blogs/chris/pyqt-ui-in-3ds-max-2014-extensionThe 3ds Max Gunslinger and yes I read your Crash Error Reports (CER&#039;s)Christopher Diggins<p>This year we had our first ever "gunslinger" event for 3ds Max. This was an opportunity for members of the development team (developers, QA, design, and product manager) to meet a cross-section of 3ds Max users and discuss their ideas, questions, and concerns. We invited several prominent members of the 3ds Max community to meet with the 3ds Max team in the Montreal office for two and a half days. For some it was also an opportunity to meet with the new 3ds Max product manager <a href="/blogs/eddie">Eddie Perlberg</a>, though many customers already know him through his work as an application engineer, his blog, or via his classes at Autodesk University.<br /><br />During the event we discussed the 3ds Max product development process (e.g. how we use the Scrum development methodology and the legal repercussions that prevent us from talking publicly about current or future feature development). Hopefully they better understood why we are sometimes vague about what we are doing, and why it seems to take long (from a&nbsp; cutsomer perspective) to start on new features. We also spent a lot of time learning how they use the product, what their pain points are, and what they want to do more easily in the future.</p> <p>One question a lot of them had was how we choose what we work on. What surprised me to learn was that many customers didn't realize how influential CER data is for us when fixing bugs and improving stability. A CER (Crash Error Report) is the data sent to 3ds Max when a crash occurs and a dialog pops-up asking if you want to send the data to 3ds Max. We have an official description of the <a href="http://usa.autodesk.com/adsk/servlet/index?siteID=123112&amp;id=7047344&amp;linkID=9241177">CER workflow on Autodesk.com</a>.<br /><br />Autodesk receives hundreds of thousands of CER reports annually. This means that we can't follow-up on inidividual CER reports, and instead rely heavily on data-mining techniques. The data goes to a database and is auto-triaged based on the module and auto-linked to related crashes. When patterns emerge, CERs are grouped into defects which are tehen submitted by the QA team to the development team. So as a developer I often see CERs once there are a group in a certain module (e.g. function or DLL) and assigned to a defect, which is usually a long time after it is submitted. At that point I can end up reading hundreds of CER reports one by one trying to find patterns.<br /><br />Many people realize that 3ds Max 2014 is a very stable release which is due in large part to us working from data provided to us from CER reports. This has helped us identify, prioritize, and fix problems. The most useful thing you can do is provide us with steps that can consistently reproduce the crash. A description of the problem and the worfklow can also help (one of our users keeps us entertained by describing his problems in Haiku). Yes, we do get some data on what you were doing, but the technology is far from perfect. However, even without anything else just clicking "send" with no data still helps us to identify the modules that need to be reviewed more carefully. <br /><br /></p>Sun, 27 Oct 2013 16:41:28 UTChttp://area.autodesk.com/blogs/chris/the-3ds-max-gunslinger-and-yes-i-read-yourcrash-error-reports-cer039sADN DevDays Conference in Las Vegas at AU and a New 3ds Max SDK BlogChristopher Diggins<p>The Autodesk Developer Network (ADN) is going to be hosting another DevDays co-located at Autodesk University in Las Vegas on Monday December 2nd this year. I'll be there to talk about the new Python API in 3ds Max. For more information on attending you can see <a href="http://around-the-corner.typepad.com/adn/2013/10/adn-devdays-au-las-vegas-2013.html">Cyrille Fauvel's blog</a> or <a href="http://au.autodesk.com/las-vegas/pre-conference/adn-conference-devlab">register directly here</a>. In addition I will be available (along with ADN and other members of the engineering team) to answer your SDK questions and help you resolved technical problems during the <span class="s4-b-lh19 mdGrey">ADN DevLab programming workshop on the second day. <br /></span></p> <p><span class="s4-b-lh19 mdGrey">The other piece of good news (which I apologize for being late to announce) is that Kevin Vandecar, 3ds Max developer consultant at ADN, has launched a new <a href="http://getcoreinterface.typepad.com/blog/2013/09/welcome-to-the-new-3ds-max-customization-and-programming-blog.html">blog for 3ds Max SDK users</a> called amusingly enough "GetCoreInterface". Hopefully this will make up for the lack of activity on my own blog.&nbsp; </span></p> <p><span class="s4-b-lh19 mdGrey"><br /></span></p>Thu, 17 Oct 2013 18:40:18 UTChttp://area.autodesk.com/blogs/chris/adn-devdays-conference-in-las-vegas-at-au-and-a-new-3ds-max-sdk-blogM&amp;E Scripting and SDK Channel on YouTubeChristopher Diggins<p>Recently the video learning team launched a new learning channel (<a href="http://www.youtube.com/user/ScriptingSDKHowTos/videos">http://www.youtube.com/user/ScriptingSDKHowTos/videos</a>) dedicated to SDK and scripting users. Right now we have videos on FBX, Maya, MotionBuilder and ICE. I hear that they are working on some 3ds Max videos, so if you do any SDK/scripting development I suggest subscribing!</p> <p>Here are a few samplers:</p> <p>http://www.youtube.com/watch?v=CvRgN6m5XuU</p> <p>http://www.youtube.com/watch?v=eXFGeZZbMzQ</p> <p>http://www.youtube.com/watch?v=OgT1B69BqWg</p> <p>http://www.youtube.com/watch?v=1PF-dBjsqOM</p> <p>One of the great things about the video channels is that they are a great way to enter into a dialogue with our subject matter experts and make suggestions for future learning materials.</p> <p></p>Sat, 12 Oct 2013 12:16:27 UTChttp://area.autodesk.com/blogs/chris/mampe-scripting-and-sdk-channel-on-youtubeAutodesk Exchange Apps Portathon is happening on September 13th.Christopher Diggins<p>The <a href="http://apps.exchange.autodesk.com/en">Autodesk Exchange store</a> provides a broad range of Autodesk&reg; approved extensions for users of several Autodesk products such as 3ds Max and Maya. If you are a developer of extensions for Autodesk products it is a great way to reach more potential users. For more information on publishing content to app-exchange see <a href="http://apps.exchange.autodesk.com/en/Publisher/Description">http://apps.exchange.autodesk.com/en/Publisher/Description</a>.</p> <p>To support and encourage developers to port existing scripts and plug-ins to the app-exchange, Autodesk is hosting a portathon, a 48 hour virtual web based coding event runs through September 13 and 14, 2013.This is a community event where you&rsquo;ll have the opportunity to work closely with Autodesk engineers in real time and meet hundreds of other Autodesk software partners from around the world.&nbsp; It is all designed to help you get your apps ready and published on Autodesk Exchange Apps.</p> <p>There&rsquo;s no cost to join the Portathon, but there is a reward.&nbsp; For all new apps submitted to the Autodesk Exchange Apps store by midnight on September 14, 2013 and accepted for publication in the store by October 31, 2013, you will receive US$ 100 per app (for up to 5 apps &ndash; US$ 500 total).</p> <p>Don't delay - join well over 100 developers in getting the help you may need to get your apps published. For details visit: <a href="http://autode.sk/15DjZpq">http://autode.sk/15DjZpq</a></p>Tue, 10 Sep 2013 17:29:06 UTChttp://area.autodesk.com/blogs/chris/autodesk-exchange-apps-portathon-is-happening-on-september-13th3ds Max and Stage AutomationChristopher Diggins<p>Stage automation is a growing industry that plays an important role in live entertainment events from music shows to Cirque du Soleil. What may come as a surprise is that thanks to a plug-in from Stage Technologies 3ds Max is playing an increasingly important role in designing, simulating, and visualizing automation for live events.</p> <p><a href="http://www.stagetech.com/press/sculptor-animation-toolkit">Stage Technologies</a> is an Australian company specializing in live event automation, they sell a number products for managing and controlling numerous types of live event automations. Among their products is a 3ds Max plug-in called <a href="http://www.stagetech.com/sculptor-toolkit">Sculptor Animation Toolkit</a>. Sculptor toolkit turns 3ds Max into a tool for designing and preview automation and to receive feedback on what movements are impossible or dangerous. Once ready Sculptor Toolkit data can be sent directly from 3ds Max to the <a href="http://www.stagetech.com/echameleon">eChameleon automation software</a>.</p> <p>As an example Sculptor Toolkit can be used to define a trolley that travels along a track, add a revolving ring hanging from it, then add some winches below the revolving ring as linear axes; these winches might then act as pickups in a larger bridled system. Flight paths, either drawn or sourced from recorded joystick data can be imported and supplementary feedback is provided to the operator when refining these paths, ensuring the flown move will run safely.</p> <p>The following video shows Sculptor Toolkit in action.</p> <p>http://www.youtube.com/watch?v=t3XW2Pq8LxQ</p> <p>3ds Max and the Sculptor Toolkit have been used together to design and visualize live event productions from <a href="http://www.stagetech.com/Radiohead-control">RadioHead</a> to the <a href="http://www.stagetech.com/Pan_American_Games">Pan-American games opening ceremony</a> to animating a giant robotic Gorilla for an upcoming musical about King Kong.</p> <p>http://vimeo.com/57498670</p> <p>For more information on Sculptor Animation Toolkit see <a href="http://www.stagetech.com/press/sculptor-animation-toolkit">http://www.stagetech.com/press/sculptor-animation-toolkit</a>. <br /><br /></p>Mon, 06 May 2013 14:47:58 UTChttp://area.autodesk.com/blogs/chris/3ds-max-and-stage-automation3ds Max and Flash Working TogetherChristopher Diggins<p>You may be familiar with <a href-:http:="" zynga="" com="" game="" farmville-two="">FarmVille 2</a>: it is currently the second most popular app on FaceBook with over <a href="http://www.appdata.com/leaderboard/apps?metric_select=mau_estimate&amp;style=classic">40,000,000 estimated monthly users</a> (as of the date of this posting). What you may not know is that FarmVille is built using the Flare3D engine and 3ds Max.</p> <p>The following video talks about the role of 3ds Max in FarmVille 2:</p> <p>http://www.youtube.com/watch?v=8iBjwLHyag4</p> <p>This next video talks about the role of Flare3D in FarmVille 2:</p> <p>http://www.youtube.com/watch?v=nnNKko2ELKQ</p> <p><a href="http://www.flare3d.com/">Flare3D</a> is a 3D engine that leverages a relatively new Flash technology called Stage3D (previously known as Molehill) to deliver GPU accelerated 3D graphics called Stage 3D. You can try Flare3D and the <a href="http://www.flare3d.com/downloads/">3ds Max exporter for free here</a>. The following video demonstrates the Flare3D exporter for lightmaps:</p> <p>http://www.youtube.com/watch?v=IG5acCdnz00</p> <p>A popular open-source 3D engine for Flash is <a href="http://away3d.com/">Away3D</a>. The following video is the Away3D Demo reel presented at GDC:</p> <p>http://vimeo.com/62962084</p> <p>Zynga, the makers of FarmVille 2, use Away3D in another popular Facebook game called <a href="http://away3d.com/showcase/detail/cafe_world">Caf&eacute; World</a>. Away3D was also used to build interactive 3D web applications to promote the <a href="http://megane.renault.co.uk/uk/#/3d.html">Renault Megane</a> and the <a href="http://www.nissan-stagejuk3d.com/">Nissan Juke</a>.</p> <p>[EDIT: Rob Bateman from Away3D suggest that people also check out the <a href="http://www.nissan.co.uk/GB/en/vehicles/crossovers/juke/personalisation.html">Nissan Juke 3D configurator</a> as it better showcases Away3D functionality, but unfortunately for me it only works on Google Chrome.].</p> <p>One use case of 3ds Max and Away3D that I found particularly interesting was <a href="https://itunes.apple.com/au/app/the-clarence/id576987034?mt=8">this iPad app</a> (built with Adobe AIR) for a <a href="http://away3d.com/showcase/detail/the_clarence">condo project called the Clarence</a>.</p> <p>There is a <a href="http://www.adobe.com/devnet/flashplayer/articles/away3d-autodesk3dsmax.html">tutorial on the Adobe website</a> for step by step instruction on how to create an interactive 3D application for 3ds Max using Away3D. If you want you can also download an Away3D exporter project&nbsp; <a href="http://code.google.com/p/awd/">Away3D file format (AWD) project on Google code</a>.</p>Tue, 23 Apr 2013 01:04:08 UTChttp://area.autodesk.com/blogs/chris/3ds-max-and-flash-working-together3ds Max SDK and MAXScript CHMs now availableChristopher Diggins<p>We discontinued CHM support for SDK documentation two releases ago in order to focus on HTML-based help.&nbsp;<span style="line-height: 1.5em;">However since many users asked us for CHMs on the 3ds Max feedback forums:&nbsp;</span><a href="http://3dsmaxfeedback.autodesk.com/forums/80701-sdk-and-scripting-enhancements/suggestions/2099795-compiled-maxscript-reference-chm-" style="line-height: 1.5em;">http://3dsmaxfeedback.autodesk.com/forums/80701-sdk-and-scripting-enhancements/suggestions/2099795-compiled-maxscript-reference-chm-</a>&nbsp;we have decided to bring back CHM for the 3ds Max SDK and MAXScript.</p> <p>Check out the new help on our updated SDK help page at: <a href="http://www.autodesk.com/me-sdk-docs">http://www.autodesk.com/me-sdk-docs</a>.&nbsp;</p>Sat, 20 Apr 2013 13:47:26 UTChttp://area.autodesk.com/blogs/chris/3ds-max-sdk-and-maxscript-chms-now-availableSell or Share your Plug-ins, Tutorials, or other Content for 3ds Max and Maya via the Autodesk ExchangeChristopher Diggins<p>With the release of Maya 2014 and 3ds Max 2014 the Autodesk Exchange site makes it easier for plug-in, content, and tutorial developers to distribute and sell their content more easily to Autodesk customers.</p> <ul> <li>The Autodesk Exchange for 3ds Max can be found at: <a href="http://apps.exchange.autodesk.com/3DSMAX/Home/Index">http://apps.exchange.autodesk.com/3DSMAX/Home/Index</a></li> <li>The Autodesk Exchange for Maya can be found at: <a href="http://apps.exchange.autodesk.com/MAYA/Home/Index">http://apps.exchange.autodesk.com/MAYA/Home/Index</a></li> </ul> <p>Both Maya 2014 and 3ds Max 2013 have direct links to the exchange app store from within the product under the help menu. In Maya go to "Help &gt; Exchange Apps" in the main menu. In 3ds Max go to "Help &gt; Autodesk Product Information &gt; Exchange Apps".</p> <p>According to the <a href="http://usa.autodesk.com/adsk/servlet/index?id=17183245&amp;siteID=123112">Autodesk Exchange developer center</a> "apps" aren't restricted to plug-ins, and can be anything a customer will find useful. For example:</p> <ul> <li>&nbsp;&nbsp;&nbsp; Plug-ins</li> <li>&nbsp;&nbsp;&nbsp; Standalone applications</li> <li>&nbsp;&nbsp;&nbsp; Training tutorials</li> <li>&nbsp;&nbsp;&nbsp; E-books</li> <li>&nbsp;&nbsp;&nbsp; Content</li> </ul> <p>Note that at the current time there is no cost to sign-up and Autodesk is currently taking no commission, but may do so in the future. For more information on that <a href="http://usa.autodesk.com/adsk/servlet/item?siteID=123112&amp;id=20149725">see the Publisher FAQ</a>.</p> <p>If you have enough information and want to get started publishing your content for 3ds Max or Maya, you can go directly the following links:</p> <ul> <li>3ds Max -<a href="http://apps.exchange.autodesk.com/3DSMAX/Home/Index"> </a><a href="http://apps.exchange.autodesk.com/Publisher/Description?productline=3DSMAX">http://apps.exchange.autodesk.com/Publisher/Description?productline=3DSMAX</a><a href="http://apps.exchange.autodesk.com/3DSMAX/Home/Index"></a></li> <li>Maya - <a href="http://apps.exchange.autodesk.com/Publisher/Description?productline=MAYA">http://apps.exchange.autodesk.com/Publisher/Description?productline=MAYA</a></li> </ul> <p>Happy content publishing!</p>Fri, 19 Apr 2013 14:04:13 UTChttp://area.autodesk.com/blogs/chris/sell-or-share-your-plug-ins-tutorials-or-content-for-3ds-max-and-maya-via-the-autodesk-exchangeEmbedding Qt Content in a 3ds Max Dockable FrameChristopher Diggins<p>The 3ds Max API provides a custom Windows control called a CUIFrame that allows a plug-in developer to create dockable content. As part of a recent investigation I decided to figure out how to embed a Qt C++ dialog CUIFrame in CUIcontent. I created a helper class called "DockableWindow" that can be used as follows:</p> <pre class="code">DockableWindow* DoStuff() { DockableWindow* dock = DockableWindow::Create(_T("My QT Demo")); HWND h = dock-&gt;GetHWND(); dlg = new QWinWidget(h); Ui::Dialog().setupUi(dlg); dock-&gt;SetWidget(dlg); return dock; } </pre> <p>Here is the implementation of the DockableWindow class.</p> <pre class="code">class DockableWindow : public CUIPosData, public CUIFrameMsgHandler { HWND h; ICUIFrame* frame; QWidget* w; CUIPosData posData; DockableWindow(HWND hwndCuiFrame) : h(hwndCuiFrame), w(NULL), frame(NULL) { frame = ::GetICUIFrame(h); frame-&gt;InstallMsgHandler(this); } void ResizeFrameToContent() { RECT r = {0}; if (w == NULL) return; GetWindowRect(h, &amp;r); MoveWindow( h, r.left, r.top, w-&gt;width(), w-&gt;height(), TRUE ); } void ResizeContentToFrame() { if (w == NULL) return; RECT r = {0}; GetWindowRect(h, &amp;r); int width = r.right - r.left; int height = r.bottom - r.top; w-&gt;resize(width, height); } virtual int GetWidth(int sizeType, int orient) { switch (sizeType) { case CUI_MIN_SIZE: return 50; case CUI_MAX_SIZE: return 10000; } return w-&gt;width(); } virtual int GetHeight(int sizeType, int orient) { switch (sizeType) { case CUI_MIN_SIZE: return 50; case CUI_MAX_SIZE: return 10000; } return w-&gt;height(); } public: enum DockFlags { Top = 1 &lt;&lt; 0, Bottom = 1 &lt;&lt; 1, Left = 1 &lt;&lt; 2, Right = 1 &lt;&lt; 3, Horizontal = Left | Right, Vertical = Top | Bottom, All = Horizontal | Vertical, }; virtual ~DockableWindow() { ::ReleaseICUIFrame(frame); delete w; } static DockableWindow* Create(MCHAR* name, DockFlags pos = All, DWORD initialPos = 0, bool isDockedInitially = false, bool resizable = true, bool visible = true) { HWND h = ::CreateCUIFrameWindow( ::GetCOREInterface()-&gt;GetMAXHWnd(), name, 0, 0, 0, 0); if (!h) return NULL; DockableWindow* r = new DockableWindow(h); ICUIFrame* f = r-&gt;GetICUIFrame(); DWORD flags = pos | CUI_FLOATABLE; if (resizable) flags |= CUI_SM_HANDLES; f-&gt;SetPosType(flags); if (isDockedInitially) r-&gt;Dock(initialPos); f-&gt;Hide(visible ? FALSE : TRUE); return r; } virtual int ProcessMessage (UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case CUI_POSDATA_MSG: { CUIPosData **cpd = (CUIPosData **)lParam; cpd[0] = this; return TRUE; } case WM_SIZING: ResizeContentToFrame(); return FALSE; } return FALSE; } bool HasWidget() { return GetWidget() != NULL; } QWidget* GetWidget() { return w; } void SetWidget(QWidget* w) { delete(this-&gt;w); this-&gt;w = w; if (w == NULL) return; w-&gt;move(0, 0); ResizeFrameToContent(); w-&gt;show(); } void Dock(DWORD location) { if (location &amp; Top) GetCUIFrameMgr()-&gt;DockCUIWindow(h, Top); else if (location &amp; Bottom) GetCUIFrameMgr()-&gt;DockCUIWindow(h, Bottom); else if (location &amp; Left) GetCUIFrameMgr()-&gt;DockCUIWindow(h, Left); else if (location &amp; Right) GetCUIFrameMgr()-&gt;DockCUIWindow(h, Right); } void Float() { GetCUIFrameMgr()-&gt;FloatCUIWindow(h); } HWND GetHWND() { return h; } ICUIFrame* GetICUIFrame() { return frame; } }; </pre> <p>For more information see the <a href="http://doc.qt.digia.com/solutions/qtwinmigrate/qwinwidget.html">QWinWidget</a> Qt class and the following 3ds Max SDK classes:</p> <ul> <li><a href="http://docs.autodesk.com/3DSMAX/16/ENU/3ds-Max-SDK-Programmer-Guide/cpp_ref/class_c_u_i_pos_data.html">CUIPosData</a></li> <li><a href="http://docs.autodesk.com/3DSMAX/16/ENU/3ds-Max-SDK-Programmer-Guide/cpp_ref/class_c_u_i_frame_mgr.html">CUIFramMgr</a></li> <li><a href="http://docs.autodesk.com/3DSMAX/16/ENU/3ds-Max-SDK-Programmer-Guide/cpp_ref/class_c_u_i_frame_msg_handler.html">CUIFrameMsgHandler</a></li> <li><a href="http://docs.autodesk.com/3DSMAX/16/ENU/3ds-Max-SDK-Programmer-Guide/cpp_ref/class_i_c_u_i_frame.html">ICUIFrame</a></li> </ul>Thu, 04 Apr 2013 16:22:18 UTChttp://area.autodesk.com/blogs/chris/embedding-qt-content-in-a-3ds-max-dockable-frameChristopher&#039;s Thoughts on Technical DebtChristopher Diggins<h2>Manny Lehman&rsquo;s Law</h2> <p>A well-known occurrence in software development is that as software evolves it structure deteriorates. This is called Manny Lehman&rsquo;s law:</p> <p style="padding-left: 30px;">"As an evolving program is continually changed, its complexity, reflecting deteriorating structure, increases unless work is done to maintain or reduce it." &mdash; <a href="http://en.wikipedia.org/wiki/Meir_Manny_Lehman">Meir Manny Lehman</a>, 1980</p> <h2>The Technical Debt Metaphor</h2> <p>Ward Cunningham first used a metaphor of debt to describe how certain software development practices can accelerate the deterioration of software in an experience paper for OOPSLA 92:</p> <p style="padding-left: 30px;">"Although immature code may work fine and be completely acceptable to the customer, excess quantities will make a program unmasterable, leading to extreme specialization of programmers and finally an inflexible product. Shipping first time code is like going into debt. A little debt speeds development so long as it is paid back promptly with a rewrite. Objects make the cost of this transaction tolerable. The danger occurs when the debt is not repaid. Every minute spent on not-quite-right code counts as interest on that debt. Entire engineering organizations can be brought to a stand-still under the debt load of an unconsolidated implementation, object- oriented or otherwise." - <a href="http://c2.com/doc/oopsla92.html">Ward Cunningham</a>, 1992</p> <h2>The Impact of Technical Debt</h2> <p>Since technical debt means an increase in overall system complexity this results in an increase in:</p> <ul> <li>number of defects</li> <li>defect complexity</li> <li>defect fix time</li> <li>cost to implement new feature</li> <li>cost to address technical debt</li> </ul> <p>The last point should drive home just how appropriate the debt analogy is, since like financial debt, technical debt will compound over time until it cripples development!</p> <h2>Kinds of Technical Debt</h2> <p>Generally speaking technical debt can be anything during the software development process that slows down a developer&rsquo;s productivity. For example a bug fix in one module may have unintended consequences in other modules because previous work caused a tight coupling between the two modules; or perhaps removing a feature takes far longer than expected because the code is scattered among multiple modules due to poor code cohesion.</p> <p>Technical debt can be categorized in the following types:</p> <ul> <li><b>Process Debt</b> &ndash; Processes become more complex and inefficient over time. Examples include builds, automated tests, check-ins, reviews, bug logging, bug tracking, etc.</li> <li><b>Code Hygiene Debt</b> &ndash; Examples included duplicated code, dead code, inadequate documentation, monolithic classes, inconsistent style, and cryptic symbol names.</li> <li><b>Architectural Debt</b> &ndash; Examples include high coupling of components, poor cohesion, poorly understood modules and systems, redundant systems, and unused systems.</li> <li><b>Knowledge Debt</b> &ndash; As products grow in complexity and team members come and go knowledge that is not written down gets lost. It takes longer for developers to become familiar with the inner workings of different systems. This can lead to cases where existing features are re-implemented.</li> </ul> <h2>When Technical Debt approaches Bankruptcy</h2> <p>Some signs that your project is nearly bankrupt with technical debt:</p> <ul> <li>Fixing bugs regularly causes regressions</li> <li>It is hard for developers predict what the effect of making a change to code will have</li> <li>There are many duplicated systems</li> <li>Developers are demoralized and disengaged</li> <li>Simple changes to the software take a long time to make</li> <li>It takes a long time before new team member can contribute to the project in a meaningful way</li> <li>Losing a single developer devastates the team and product development plans; this is a sign of extreme specialization mentioned by Ward Cunningham</li> </ul> <h2>Software Development Misconceptions</h2> <p>Many programmers have some misconceptions that poor sofrware development practices are necessary for rapid software development. It is common to hear among developers statements like:</p> <ul> <li>I don&rsquo;t have time to document or test my code</li> <li>I didn&rsquo;t write that module</li> <li>It is easier for me to write a brand new module than upgrading the existing one</li> <li>I don&rsquo;t understand that code so I&rsquo;m not going to touch it</li> <li>Cutting and pasting code is quicker</li> <li>Shorter variable or function names saves me time typing</li> <li>I don&rsquo;t have time to break up the long function into several smaller ones.</li> <li>I&rsquo;ll go back and improve/fix/document/test it later</li> <li>It is the QA responsibility to find bugs in my code</li> <li>Anyone can tell what I&rsquo;m doing from reading the code</li> <li>I don&rsquo;t care if someone understands it, it works.</li> </ul> <p>These reasons and more are often used to justify a <em>quick and dirty</em> coding approach; however often what is quick in the short term only means quick to write and check-in. The total time it costs an organization to deal with the dirty code is often much longer than if the developer just followed good code.</p> <p>Good software development practices can become nearly effortless with a bit of retraining. An intentional and good-faith effort has to be made to learn and to follow good coding guidelines for a period of time.</p> <h2>Mitigating Technical Debt</h2> <p>Technical debt is virtually impossible to avoid altogether, but there are several steps that a development team can take to minimize its introduction:</p> <ol> <li>Agree and adhere to coding guidelines</li> <li>Document the code and architecture</li> <li>Always provide tests and samples for new features</li> <li>Try to update and reuse existing systems, rather than introducing new similar system</li> <li>If a new system has to be introduced that replicates functionality of an existing system, then the old system should be updated to use the new one</li> <li>Conduct architecture reviews of proposed modules, features</li> <li>Refuse to admit code into the code-base that violates the guidelines.</li> <li>Use tools to detect violation of coding guidelines</li> <li>NEVER cut and paste code: introduce a new function or class. &nbsp;</li> </ol> <h2>Reducing Technical Debt</h2> <p>The following are some ideas for how reducing technical debt</p> <ul> <li><b>Delete code</b> &ndash; The easiest way to refactor code is to remove it; find features that can be removed.</li> <li><b>Address the biggest debt first</b> &ndash; Areas of the software that impede developers the most should be addressed first.</li> <li><b>Merge systems</b> &ndash; If there are multiples systems doing similar things they should be merged into one.</li> <li><b>Don&rsquo;t be afraid to break things</b> - As <a href="http://www.codinghorror.com/blog/2009/02/paying-down-your-technical-debt.html">Jeff Atwood says</a> &ldquo;don&rsquo;t be afraid to break things: paying off technical debt means refactoring code and taking risks. If refactoring is done properly it should be easier to identify and fix bugs, afterwards."</li> </ul> <h2>Last Words</h2> <p>Technical debt if left unaddressed will crush a project and the morale of the people working on it. Don't put your head in the sand regarding technical debt, confront it head on!</p> <p>I'd love to hear your thoughts about this article and technical debt in general.</p>Wed, 13 Mar 2013 13:59:43 UTChttp://area.autodesk.com/blogs/chris/christophertechnical-debtJSON Scene Description LanguageChristopher Diggins<p>Today I'm presenting the first public draft an informal specification for a 3D scene description language designed specifically for web-services called the JSON Scene Description Language. I've tried to come up with a specification that is similar in spirit to JSON: as simple as possible, extremely generic, and very useful.</p> <p>I'd appreciate any feedback you can provide, thanks!</p> <h2>JSON Scene Description Language</h2> <p>Draft Version, February 14th, 2013<br />by Christopher Diggins, Autodesk</p> <h2>Summary</h2> <p>JSON Scene Description Language (JSDL) is a specification for transmitting descriptions of 3D scenes via web services.</p> <h2>Introduction</h2> <p>Traditional representations of 3D scenes are monolithic static file formats (for example FBX and COLLADA) which do not lend themselves well to transmission over a network or for consumption by light-weight clients such as web-browsers.</p> <p>JSDL is a specification for describing a scene hierarchy and the various scene elements (assets) contained within it. JSDL is open-ended in that it does not specify how to represent scene elements themselves. JSDL is compatible with any format for representing geometry, texture maps, materials, animation, particle effects, etc.</p> <p>An important advantage of JSDL is that it supports multiple representations of the same scene element. An example of how this can be useful would be if a web-service wanted to present a custom binary mesh formats to certain clients that can support it, but to present more generic represesentations to other clients.</p> <h2>Overview</h2> <p>JSDL consists of the following parts:</p> <ul> <li><strong>Scene record</strong> - A JSON record describing a scene. It contains a scene graph and an array of asset descriptors.</li> <li><strong>Scene graph</strong> - A JSON representation of a tree of scene nodes. Each node has a transform, and may refer to one or more child objects.</li> <li><strong>Asset descriptors</strong> - An asset descriptor is a JSON record that contains meta-information about an asset and an array of the representations available.</li> <li><strong>Assets</strong> - An asset is a constituent part of a scene. An asset can be any kind of data. Typical examples of assets in 3D scenes include geometry, texture maps, materials, cameras, particle effects, animation tracks, and more.</li> <li><strong>Asset representations</strong> - An asset can have one or more representations. Each asset representation type has an identifier similar to a MIME type.</li> </ul> <h2>Asset URL</h2> <p>An asset is identified using a URL of the form:</p> <pre>[&lt;<em>scene_url</em>&gt;/]&lt;<em>asset_id</em>&gt;[/&lt;<em>asset_representation_id</em>&gt;]<br /> </pre> <p>The scene URL component is optional, if it is omitted then the asset ID is assumed to belong to the current scene. The asset ID component identifies the scene element (the "resource"). The asset representation ID component is also optional; if it is omitted then the JSON asset descriptor record is returned.</p> <h2>Scene Object</h2> <p>The scene object is a JSON object that describes a scene hierarchy and contains a list of all assets descriptors.</p> <pre class="code">scene : { id : string, roots : [node], camera : string, assets : object, }<br /> </pre> <p>The identifier is a string that can only contain letters, digits, and the underscore character, and cannot start with a digit. The roots field contains the top level scene nodes (i.e. those with no parents). The camera field is an optional asset URL or identifier that indicates the default camera. The assets field is an a dictionary of asset descriptors. Each asset key is an asset identifier that consists of letters, numbers, the "_" character, or the "-" character.</p> <h2>Scene Graph Node</h2> <p>A scene graph node:</p> <pre class="code">node : { transform : [float], assets : [string], children : [node], }<br /> </pre> <p>The transform is an optional four by four matrix indicating the nodes offset from the parent. The assets field is an array of asset URLs or asset identifiers. The children field contains an array of child nodes.</p> <h2>Asset Descriptor</h2> <p>The asset descriptor is a JSON record that identifies an asset and lists the avaialable representations.</p> <pre class="code">asset : {<br /> representations : [string], default : { type : string, value : object, } } </pre> <p>The representations field is an array of asset representation type identifiers. A default representation may be embedded in the asset descriptor record if it is a JSON object. The "default.type" field is the type identifier, and the "default.value" is the JSON object.</p> <h2>Asset Representation Type Identifier</h2> <p>The asset representation type identifier is similar in concept to a &ldquo;mime-type&rdquo;. It is a string that represents a particular type of data. The asset representation identifier should start with a letter, and can consist of letters, numbers, and the '.' character.</p> <h2>Appendix: Predefined Asset Representation Type Identifiers</h2> <p>JSDL does not require specific asset representations, or representation identifiers. The following are some recommended identifiers for common asset representation types:</p> <ul> <li>3ds &ndash; .3ds file, a legacy 3D Studio DOS file format (<a href="http://en.wikipedia.org/wiki/.3ds">http://en.wikipedia.org/wiki/.3ds</a> )</li> <li>alembic &ndash; Alembic 3D data interchange format (<a href="http://code.google.com/p/alembic/">http://code.google.com/p/alembic/</a>)</li> <li>autodesk.dwf &ndash; Autodesk design web format (<a href="http://en.wikipedia.org/wiki/Design_Web_Format">http://en.wikipedia.org/wiki/Design_Web_Format</a>)</li> <li>autodesk.dwg &ndash; CAD file format compatible with AutoCAD (<a href="http://en.wikipedia.org/wiki/.dwg">http://en.wikipedia.org/wiki/.dwg</a>)</li> <li>autodesk.dxf &ndash; Autodesk design exchange format (<a href="http://en.wikipedia.org/wiki/AutoCAD_DXF">http://en.wikipedia.org/wiki/AutoCAD_DXF</a>)</li> <li>autodesk.fbx.binary &ndash; FBX binary format</li> <li>autodesk.fbx.text &ndash; FBX ASCII format</li> <li>autodesk.max &ndash; Autodesk 3ds Max file</li> <li>autodesk.maya.text &ndash; Autodesk Maya ASCII file</li> <li>autodesk.maya.binary &ndash; Autodesk Maya Binary file</li> <li>autodesk.softimage &ndash; Autodesk Softimage file</li> <li>awd &ndash; Away3D binary format (<a href="http://code.google.com/p/awd/">http://code.google.com/p/awd/</a>)</li> <li>collada &ndash; COLLADA file format ( <a href="http://www.khronos.org/collada/">http://www.khronos.org/collada/</a> )</li> <li>image.bitmap &ndash; Bitmap file (<a href="http://en.wikipedia.org/wiki/Bitmap">http://en.wikipedia.org/wiki/Bitmap</a>)</li> <li>image.jpg &ndash; JPEG file format (<a href="http://en.wikipedia.org/wiki/Jpeg">http://en.wikipedia.org/wiki/Jpeg</a>)</li> <li>image.gif &ndash; Graphics Interchange file format (GIF) (<a href="http://en.wikipedia.org/wiki/Gif">http://en.wikipedia.org/wiki/Gif</a>)</li> <li>image.tif &ndash; Tagged Image File Format (TIFF) (<a href="http://en.wikipedia.org/wiki/Tagged_Image_File_Format">http://en.wikipedia.org/wiki/Tagged_Image_File_Format</a>)</li> <li>image.png &ndash; Portable Network Graphics format (<a href="http://en.wikipedia.org/wiki/Portable_Network_Graphics">http://en.wikipedia.org/wiki/Portable_Network_Graphics</a>)</li> <li>ply &ndash; Stanford triangle format ( <a href="http://en.wikipedia.org/wiki/PLY_(file_format)">http://en.wikipedia.org/wiki/PLY_(file_format)</a> )</li> <li>stl.binary &ndash; STL binary file ( <a href="http://en.wikipedia.org/wiki/STL_(file_format)">http://en.wikipedia.org/wiki/STL_(file_format)</a>)</li> <li>stl.text &ndash; STL ASCII file ( <a href="http://en.wikipedia.org/wiki/STL_(file_format)">http://en.wikipedia.org/wiki/STL_(file_format)</a> )</li> <li>threejs.camera.json &ndash; Three.JS camera object</li> <li>threejs.geometry.json &ndash; Three.JS geometry object</li> <li>threejs.light.json &ndash; Three.JS light object</li> <li>threejs.material.json &ndash; Three.JS material object</li> <li>wavefront.mtl - Wavefront .MTL file ( <a href="http://en.wikipedia.org/wiki/Wavefront_.obj_file">http://en.wikipedia.org/wiki/Wavefront_.obj_file</a> )</li> <li>wavefront.obj &ndash; Wavefront .OBJ file ( <a href="http://en.wikipedia.org/wiki/Wavefront_.obj_file">http://en.wikipedia.org/wiki/Wavefront_.obj_file</a> )</li> </ul> <p>The various threejs.X.json representations are defined as those formats that can be loaded by the <a href="https://github.com/mrdoob/three.js/blob/master/src/loaders/JSONLoader.js">Three.JS JSON loader</a>.</p> <h2>Appendix: Example JSDL</h2> <p>The following is a JSDL file describing a scene with two instances of a square with a side of length 2.0. The second square is offset from the first square by [3, 4, 5].</p> <p>The default representation of the square is a Three.JS compatible JSON format, the alternative formats are a Wavefront OBJ ASCII file format, and the Alembic binary format.</p> <pre class="code">{ "id" : "my_scene" "roots" : [ { "assets" : ["Square"], "children" : [ "transform" : [ 1, 0, 0, 3, 0, 1, 0, 4, 0, 0, 1, 5, 0, 0, 0, 1 ] "assets" : ["Square"], ], } ], "assets" : [ "Square" : { "representations" : [ "threejs.geometry.json", "wavefront.obj", "alembic"], "default" : { "type" : "threejs.geometry.json", "value" : { "vertexes" : [ [-1, 1, 0], [1, 1, 0], [1, -1, 0], [-1, -1, 0], ], "faces": [ [3, 2, 1], [3, 1, 0], ] } } } } </pre> <p>If this JSDL scene is hosted on a URL such as http://test.autodesk.com we would then be able expect the following URLs to exhibit specific behavior:</p> <ul> <li>http://test.autodesk.com/my_scene - This would return the above JSON object.</li> <li>http://test.autodesk.com/my_scene/Square &ndash; This would return the &ldquo;assets.Square&rdquo; JSON object.</li> <li>http://test.autodesk.com/my_scene/Square/threejs.geometry.json &ndash; This would return the &ldquo;assets.Square.default.value&rdquo; JSON object.</li> <li>http://test.autodesk.com/my_scene/Square/wavefront.obj - This would return an .obj text representation of the square object.</li> <li>http://test.autodesk.com/my_scene/Square/alembic - This would return an alembic binary representation of the square object</li> </ul> <h2>Acknowledgements</h2> <p>A special thank you to Aaron Tarnow at Autodesk for reviewing this specification and his enthusiastic support. Thanks to Stephen Taylor, Robert Goulet, Andre Gauthier, Mark Davies, and Mathieu Mazerolle at Autodesk, Grayson Lang at Adobe, Paul Brunt of GLGE, and Rob Bateman of Away 3D. This specification would not be possible if they didn't generously share their knowledge and experience.</p>Thu, 14 Feb 2013 15:11:29 UTChttp://area.autodesk.com/blogs/chris/json-scene-description-languageCreating a Procedural Tree in MAXScriptChristopher Diggins<p>The following is a two-part MAXScript video tutorial produced by the <a href="http://www.youtube.com/user/3dsMaxHowTos?feature=watch">Autodesk 3ds Max YouTube learning channel</a>. This is a beginner level introduction to MAXScript that will show you how to create, move, scale, and rotate objects. You'll learn how to create animations, use the for loop, and create random variations.</p> <p>http://www.youtube.com/watch?v=ZoIY5lT6IV4</p> <p>http://www.youtube.com/watch?v=NxI-ru5yAa0</p>Thu, 31 Jan 2013 18:59:31 UTChttp://area.autodesk.com/blogs/chris/creating-a-procedural-tree-in-maxscriptMaya 2013 Extension 2: .NET and moreChristopher Diggins<h2>A .NET API for Maya</h2> <p>Cyrille Fauvel from the Autodesk Developer Network gave the first public sneak peek of a .NET API for Maya back in <a href="http://around-the-corner.typepad.com/adn/2012/12/maya-going-on-net.html">December on his blog</a>. I'm pleased to announce that it is now a reality for our subscription customers with the release of the Extension 2 Maya 2013 on <a href="http://usa.autodesk.com/adsk/servlet/pc/index?id=17662508&amp;siteID=123112">the subscription site</a>.</p> <p>For fun here is a sample Hello World plug-in for Maya written in C#:</p> <pre class="code">using System; using Autodesk.Maya.Runtime; using Autodesk.Maya.OpenMaya; [assembly: MPxCommandClass(typeof(MayaNetPlugin.helloWorldCmd), "helloWorldCmd")] [assembly: ExtensionPlugin(typeof(MayaNetPlugin.helloWorldPlugin), "Autodesk", "1.0", "Any")] namespace MayaNetPlugin { &nbsp; &nbsp; public class helloWorldPlugin : IExtensionPlugin &nbsp; &nbsp; { &nbsp; &nbsp; &nbsp; &nbsp; bool IExtensionPlugin.InitializePlugin() { return true; } &nbsp; &nbsp; &nbsp; &nbsp; bool IExtensionPlugin.UninitializePlugin() { return true; } &nbsp; &nbsp; &nbsp; &nbsp; String IExtensionPlugin.GetMayaDotNetSdkBuildVersion() { return ""; } &nbsp; &nbsp; } &nbsp; &nbsp; public class helloWorldCmd : MPxCommand,IMPxCommand &nbsp; &nbsp; { &nbsp; &nbsp; &nbsp; &nbsp; public override void doIt(MArgList argl) &nbsp; &nbsp; &nbsp; &nbsp; { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MGlobal.displayInfo("Hello World\n"); &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; } } </pre> <p>Of course it gets much more interesting than that since there is support for docking WPF windows in Maya, and for using LINQ. Here is an example of how LINQ can be used to query the dependency graph for all selected objects with a mesh:</p> <pre class="code">var meshes = from p in new MSelectionList() where p.hasFn(MFn.Type.kMesh) select new MFnMesh(p);<br /> </pre> <p>In the Maya devkit/dotnet folder though you can find over 60 sample .NET plug-ins ported from the C++ API. For more information on the Maya .NET API you should <a href="http://docs.autodesk.com/MAYAUL/2013/ENU/Maya-API-Documentation/files/GUID-F5CEF518-A721-4FB8-8BBA-BECB1B39FAEF.html">check out the documentation</a>.</p> <p>Also note that the Autodesk Developer Network has made a C# plug-in wizard available on the <a href="http://www.autodesk.com/developmaya">Maya developer center page</a>.</p> <h3>SDK Documentation Improvements</h3> <p>There has also been a number of improvements to the SDK documentation:</p> <ul> <li>The <a href="http://docs.autodesk.com/MAYAUL/2013/ENU/Maya-API-Documentation/files/Writing_a_Deformer_Node.htm">Writing a Deformer Node chapter</a> has been updated.</li> <li>The <a href="http://docs.autodesk.com/MAYAUL/2013/ENU/Maya-API-Documentation/files/Manipulators.htm">Manipulators chapter</a> has been updated.</li> </ul> <p>For detailed information on the changes in the SDK and SDK documentation see the <a href="http://docs.autodesk.com/MAYAUL/2013/ENU/Maya-API-Documentation/files/GUID-F5CEF518-A721-4FB8-8BBA-BECB1B39FAEF.htm">What's New in Extension 2 for Maya 2013 topic</a>. There is also some information about other improvements to the Maya 2013 Extension 2 in the <a href="http://download.autodesk.com/global/docs/maya2013/en_us/files/wn_2013_ex2.htm">Maya user documentation</a>.</p> <h3>SDK Documentation Translator Widget</h3> <p>Finally is a special treat for Maya users who don't speak English as a first language: the addition of a <a href="http://docs.autodesk.com/MAYAUL/2013/ENU/Maya-API-Documentation/files/GUID-272D2A65-821F-46C0-8B88-6258487A3E93.htm">Microsoft Translation widget to the SDK documentation</a>. This is a pilot project, that we first tried on Gameware customers and that we are now rolling to the larger audience of Maya SDK users.</p> <p>I'd appreciate hearing your feedback regarding any or all of these improvements.</p>Wed, 23 Jan 2013 18:24:37 UTChttp://area.autodesk.com/blogs/chris/maya-2013-extension-2-a-net-api-and-moreA very gentle introduction to MAXScript for ArtistsChristopher Diggins<p>Embedded in one of the over <a href="http://www.youtube.com/user/3dsMaxHowTos?feature=watch">200 videos on the Autodesk 3ds Max learning channel</a> on YouTube is a very practical introduction to MAXScript for people with no programming experience. At <a href="http://youtu.be/nmdEMpblRqg?t=2m55s">about 4 minutes into a video on using MassFX</a> Amer shows how to use MAXScript to automate changing a property on over 300 objects. What is great about this is that Amer takes the time to explain everything that he is doing without assuming the audience is familiar with MAXScript.</p> <p>What he shows introduces several basic concepts:</p> <ul> <li>Using the MAXScript recorder to discover the necessary code how to change a desired property</li> <li>What the "$" symbol means (currently selected object)</li> <li>How to change a property of all objects in the currently selected set</li> </ul> <p>Its a great example of how one line of MAXScript code can save an artist a lot of wear and tear on their wrist!</p> <p>For convenience here is the video in its entirety.</p> <p>http://www.youtube.com/watch?v=nmdEMpblRqg</p>Thu, 17 Jan 2013 18:45:04 UTChttp://area.autodesk.com/blogs/chris/a-very-gentle-introduction-to-maxscript-for-artistsCreating an Undoable Python Command for MayaChristopher Diggins<p class="MsoNormal">Autodesk's <a href="http://www.youtube.com/user/MayaHowTos?feature=watch">Maya learning channel on YouTube</a> has released a new tutorial on how to make an undoable command plug-in for Maya using Python. The command creates a swarm of particles in a turbulence field.</p> <p class="MsoNormal">Some of the commands demonstrated:</p> <ul> <li><a href="http://download.autodesk.com/global/docs/maya2013/en_us/CommandsPython/turbulence.html">turbulence</a></li> <li><a href="http://download.autodesk.com/global/docs/maya2013/en_us/Commands/particle.html">particle</a></li> <li><a href="http://download.autodesk.com/global/docs/maya2013/en_us/CommandsPython/connectDynamic.html">connectDynamic</a></li> </ul> <p class="MsoNormal">Some of the classes used:</p> <ul> <li><a href="http://docs.autodesk.com/MAYAUL/2013/ENU/Maya-API-Documentation/cpp_ref/class_m_dag_path.html">MDagPath</a></li> <li><a href="http://docs.autodesk.com/MAYAUL/2013/ENU/Maya-API-Documentation/cpp_ref/class_m_dag_modifier.html">MDagModifier</a></li> <li><a href="http://docs.autodesk.com/MAYAUL/2013/ENU/Maya-API-Documentation/cpp_ref/class_m_fn_particle_system.html">MFnParticleSystem</a></li> </ul> <p class="MsoNormal">You can <a href="http://areadownloads.autodesk.com/wdm/maya/HTM_PYT_Command_Plug-ins_Part1.zip">download the code from the tutorial here</a>.</p> <p class="MsoNormal">http://www.youtube.com/watch?v=BZyXe3MhEyI</p>Tue, 15 Jan 2013 21:22:29 UTChttp://area.autodesk.com/blogs/chris/creating-an-undoable-python-command-for-mayaCross Platform C# Game Development with MonoGameChristopher Diggins<p>I am (or rather was) a big fan of XNA, Microsoft's C# game development framework, and I had high hopes for it. I was particularly enthusiastic when Silverlight started supporting a subset of it. Unfortunately Microsoft has given no indication (as far as I am aware of) that they will be supporting XNA for Winows 8 Metro and <a href="http://visualstudiomagazine.com/articles/2012/07/13/silverlight-transitions-continue-for-developers-and-microsoft.aspx">Silverlight is apparently not being supported on Windows 8 metro</a>. There have been a lot of speculation around the future of C#-based game development for Windows on various threads. For an interesting and informed discussion on the topic see <a href="http://gamedev.stackexchange.com/questions/22292/what-is-the-future-of-xna-in-windows-8-or-how-will-manged-games-be-developed-in">this topic on gamedev.stackexchange.com</a>.</p> <p>When I first read the thread on GameDev several months ago I had skimmed past a post talking about an open-source project called <a href="http://monogame.codeplex.com/">MonoGame</a>. Today I revisited the MonoGame web-site and I was impressed with the number of downloads, positive reviews, and the general momentum of the project.</p> <p>Here is the MonoGame mission statement:</p> <p style="padding-left: 30px;">MonoGame is an Open Source implementation of the Microsoft XNA 4 Framework. Our goal is to allow XNA developers on Xbox 360, Windows &amp; Windows Phone to port their games to the iOS, Android, Mac OS X, Linux and Windows 8 Metro. &nbsp;PlayStation Mobile development is currently in progress.</p> <p>Imagine writing applications and games for all of those platforms at once in C#? Wouldn't that be amazing! To be honest I'm generally very skeptical when it comes to the success of open-source projects, but this group seems to be doing everything right. I also like their approach of building upon mature open-source projects like <a href="http://www.opentk.com/">OpenTK</a> and <a href="http://www.slimdx.org">SlimDX</a>.</p> <p>However, what reaslly sold me were the trailers for <a href="http://www.armedgame.com/get-armed">ARMED!</a> from SickHead games. This awesome looking game has been ported to Windows 8 Metro and Windows 7 Phone using MonoGame. I'm curious about the success they will have porting to other platforms!</p> <p>At least for now I've become optimistic and enthusiastic about the prospect of serious game development in C# once again.</p> <p>http://www.youtube.com/watch?v=T4bEWO4-I2A</p>Wed, 09 Jan 2013 17:13:41 UTChttp://area.autodesk.com/blogs/chris/cross-platform-c-game-development-with-monogame