3D SDK and Scripting Mayhemhttp://area.autodesk.com/Topics of interest to people customizing Autodesk M&E products using SDKs and scripting APIs by SDK Subject Matter Expert <a href="https://plus.google.com/100642342363670335651?rel=author">Christopher Diggins</a>.Sat, 18 May 2013 12:20:28 UTC3ds 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>[video]http://www.youtube.com/watch?v=t3XW2Pq8LxQ[/video]</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>[video]http://vimeo.com/57498670[/video]</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>[video]http://www.youtube.com/watch?v=8iBjwLHyag4[/video]</p> <p>This next video talks about the role of Flare3D in FarmVille 2:</p> <p>[video]http://www.youtube.com/watch?v=nnNKko2ELKQ[/video]</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>[video]http://www.youtube.com/watch?v=IG5acCdnz00[/video]</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>[video]http://vimeo.com/62962084[/video]</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>[video]http://www.youtube.com/watch?v=ZoIY5lT6IV4[/video]</p> <p>[video]http://www.youtube.com/watch?v=NxI-ru5yAa0[/video]</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>[video]http://www.youtube.com/watch?v=nmdEMpblRqg[/video]</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">[video]http://www.youtube.com/watch?v=BZyXe3MhEyI[/video]</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>[video]http://www.youtube.com/watch?v=T4bEWO4-I2A[/video]</p>Wed, 09 Jan 2013 17:13:41 UTChttp://area.autodesk.com/blogs/chris/cross-platform-c-game-development-with-monogameAn Introduction to MAXScriptChristopher Diggins<p>This is a MAXScript tutorial in the form of a <a mce_href="/userdata/blogs/chris/stickman.zip" href="/userdata/blogs/chris/stickman.zip">MAXScript program that you can download</a> and run. The program demonstrates a simple procedural animation of a walking stick-figure and an animated camera associated with the viewport. For more information on some of the concepts used in this script the following links will bring you to the relevant online MAXScript documentation:</p> <ul> <li><a href="http://docs.autodesk.com/3DSMAX/15/ENU/MAXScript-Help/files/GUID-19A946F5-3072-425F-8452-7CE16895D7DB.htm">sine function</a> (sin)</li> <li><a href="http://docs.autodesk.com/3DSMAX/15/ENU/MAXScript-Help/files/GUID-CC2D2450-AECD-4732-BF93-4AA91ED0BC56.htm">"animate" context expression</a></li> <li><a href="http://docs.autodesk.com/3DSMAX/15/ENU/MAXScript-Help/files/GUID-4E9CCD61-F575-42E1-8654-315DDF6C6A26.htm">"at time" context expression</a></li> <li><a href="http://docs.autodesk.com/3DSMAX/15/ENU/MAXScript-Help/files/GUID-E4732A5D-91C4-4EDD-8944-F00E7DC57D10.htm">"about" context expression</a></li> </ul> <p>Here is the source code of the program.</p> <pre class="code">/* MAXScript Tutorial This script demonstrates creating a procedural animation using MaxScript. It generates a simple stick man from cylinders and a sphere, and animates him in a simple walk cycle. Other concepts demonstrated include: * Create simple primitives * Link objects * Create animation frames * Set node transform properties in local coordinate space. * Use the sine function to achieve smooth back and forth motion * Creating a camera with a target and rotating it * Setting the active viewport, and associating it with a camera */ /* Clear the scene */ delete objects /* Initialize variables to help define the objects */ armlength = 15 leglength = 15 armradius = 2 legradius = 2 /* Create Body Parts */ body = cylinder radius:5 height:20 leftarm = cylinder radius:armradius height:armlength rightarm = cylinder radius:armradius height:armlength leftleg = cylinder radius:legradius height:leglength rightleg = cylinder radius:legradius height:leglength head = sphere radius:5 /* Set the arm positions */ leftarm.pos.x = -body.radius - armradius rightarm.pos.x = body.radius + armradius leftarm.pos.z = body.pos.z + body.height rightarm.pos.z = body.pos.z + body.height /* Set the leg positions */ leftleg.pos.x = leftarm.pos.x leftleg.pos.y = leftarm.pos.y rightleg.pos.x = rightarm.pos.x rightleg.pos.y = rightarm.pos.y /* Rotate the arms and legs by 180 degrees so that they point downwards */ leftarm.rotation.x_rotation = 180 rightarm.rotation.x_rotation = 180 leftleg.rotation.x_rotation = 180 rightleg.rotation.x_rotation = 180 /* Set the head location */ head.pos.z = body.pos.z + body.height + head.radius /* Link the body parts to the body */ leftarm.parent = body rightarm.parent = body leftleg.parent = body rightleg.parent = body head.parent = body /* Move the body up so the legs are aligned to the x/y plane. */ body.pos.z = leglength /* Animate the body to move along the local Y axis a small amount per frame The "animate on" context expression automatically creates key frames when animatable properties are modified */ animate on ( for t = 0 to 100 by 5 do ( /* The "at time" context expression gets/sets animatable properties at a specific time frame. */ at time t ( /* Assure that transforms occur in the node's local coordinate system */ in coordsys local ( move body [0, -2.5, 0] ) ) ) ) /* Rotate arms and legs In order to get the movement to change direction smoothly I use a sine function: */ animate on ( swingArc = 45 /* The number of degress each arm and leg swings */ spd = 10 /* Controls the speed at which the swing occurs */ for t = 0 to 100 by 5 do ( at time t ( leftarm.rotation.x_rotation = sin (t * spd) * swingArc + 180 rightarm.rotation.x_rotation = sin (t * spd + 180) * swingArc + 180 leftleg.rotation.x_rotation = sin (t * spd + 180) * swingArc + 180 rightleg.rotation.x_rotation = sin (t * spd) * swingArc + 180 ) ) ) /* Create a free camera targeted to the body */ cam = freeCamera pos:[100, -100, 50] cam.target = body /* Set the lower-right viewport as the active viewport */ viewport.activeViewport = 4 /* Associated the active viewport with the camera */ viewport.setCamera cam /* Animate the camera around the origin while moving up. */ animate on ( for t = 0 to 100 do ( at time t ( /* Rotate about the z_axis at the origin Uses the "about" context expression to set the pivot to perform rotations. */ about [0, 0, 0] ( rotate cam 1 z_axis ) /* Move the camera upwards */ move cam [0, 0, 1] /* Update the roll_angle controller of the camera so that we stay level with the x/y plane */ cam.transform.controller.Roll_Angle.controller.value = 0 ) ) ) </pre>Fri, 04 Jan 2013 20:57:03 UTChttp://area.autodesk.com/blogs/chris/an-introduction-to-maxscriptProject Sci-Viz: Molecular Graphics in 3ds MaxChristopher Diggins<h2>Project Sci-Viz</h2> <p><a href="http://labs.autodesk.com/utilities/sciviz">Project Sci-Viz</a> is a preview on Autodesk Labs of experimental technology we developed to enable popular molecular graphics toolkits written in Python, namely <a href="http://www.autopack.org">ePMV and autoPack</a>, in Autodesk 3ds Max 2013. Previously ePMV and autoPack technology were only available to users of Autodesk Maya or certain other software packages that shall remain nameless on my blog. </p> <p>The ePMV tool allows a user to download molecular recipes from various online databases such as the <a href="http://www.rcsb.org/pdb/home/home.do">Protein Data Bank (PDB)</a> and display various representations of them within the host 3D modeling tool.</p> <p>The autoPack and cellPack tool is based on volume filling algorithms, that are useful for packing molecules into cells with biologically relevant interactions to populate massive cell models with atomic or near-atomic details</p> <p>The following is a short video (2:30) that shows how to use ePMV to download and display a Polio virus.</p> <p>[video]http://www.youtube.com/watch?v=tcEHDUn_cC8[/video]</p> <p>The next video (3:30) shows autoFill being used to create a representation of an HIV virus:</p> <p>[video]http://www.youtube.com/watch?v=WpWSUphRzCI[/video]</p> <p>If you are interested in a more in-depth tutorial on using ePMV the following video (8:00) is aimed at newcomers to molecular graphics.</p> <p>[video]http://www.youtube.com/watch?v=qd3N3jTOwXc[/video]</p> <p>For more videos and tutorials of using ePMV and autoFill see: <a href="http://www.autopack.org/documentation/tutorials">http://www.autopack.org/documentation/tutorials</a>.</p> <p>Even if you aren't a scientist you may still find this to be interesting technology to use and experiment with. Please let us know in the comments if you are able to make any interesting renders or animation using the tools! The thumbnail for this blog for example is a render of an HIV virus made by our very own Kelly Michels, who has been a huge help in field testing the tools.</p> <p>A big thank you to Ludovic Autin and Graham Johnson for their huge efforts in writing and porting ePMV and autoPack to 3ds Max, and making the extremely useful video tutorials. </p>Fri, 23 Nov 2012 19:27:56 UTChttp://area.autodesk.com/blogs/chris/project-sci-viz-molecular-graphics-in-3ds-maxMAXScript - Mouse Tools for Vertex Weighting during SkinningChristopher Diggins<p>My colleague Amer Yassine recently finished posted his amazing <a href="http://www.youtube.com/playlist?list=PLnKw1txyYzRlxh1-BT4CifPXC5TBg2vUd">40 video tutorial on skinning and rigging for games</a> on the 3ds Max learning channel on YouTube. The process of adjusting vertex weights during skinning is very repetitive so he asked me to help him come up with a MAXScript tool to help ease the process. MAXScript mouse tools are explained <a href="http://docs.autodesk.com/3DSMAX/15/ENU/MAXScript-Help/files/GUID-80E8ADDC-F8A0-46F4-B909-4F39D5F37A29.htm">here in the MAXScript documentation</a>.</p> <pre>macroScript QuickSkinVertexWeight category:"Custom Skin Tools" tooltip:"Quick Vertex Weight Tool" ( tool AssignSkinVertexWeightTool ( local original fn setweight wt = ( if (wt &lt; 0) then wt = 0 if (wt &gt; 1.0) then wt = 1.0 skinOps.setWeight $.modifiers[#Skin] wt $.modifiers[#Skin].effect = wt ) on mousePoint clickno do ( if clickno &gt; 1 then return #stop original = $.modifiers[#Skin].effect ) on mouseAbort clickno do ( setweight original ) on mouseMove clickno do ( newval = (original + (gridDist.x * 0.01)) setweight newval ) ) startTool AssignSkinVertexWeightTool prompt:"Set Vertex Weight" )<br />&nbsp;</pre> <p>Here is the video where Amer first introduces the tool and explains how it works, enjoy!</p> <p>[video]http://www.youtube.com/watch?v=Ya02rmjNsUM[/video]</p>Fri, 02 Nov 2012 19:01:16 UTChttp://area.autodesk.com/blogs/chris/maxscript---mouse-tools-for-vertex-weight-during-skinningDynamically Compiling and Running C# Scripts for 3ds MaxChristopher Diggins<p>[<strong>EDIT</strong>: Nov. 12, 2012 I've updated the editor to fix a bug in the editor and include the source code]</p> <p>For impatient 3ds Max developers the ability to compile and run C# programs from within 3ds Max without having to restart it can be very useful. Since I am about as impatient as they come I developed a simple plug-in for 3ds Max that allows me to edit and run C# programs as if they were scripts.</p> <p>You can <a mce_href="/userdata/blogs/chris/CSharpScriptEditor3dsMax2013.zip" href="/userdata/blogs/chris/ScriptEditor.zip">download the C# script editor plug-in and source code here</a>. To install it copy the plug-in DLL file (and optionaly the PDB debug database) into the "\bin\assemblies" sub-folder of your 3ds Max 2013 installation.&nbsp; This should work on both 32-bit and 64-bit flavors of 3ds Max.</p> <p>Next you will have to "unblock" the DLL (at least for Windows 7, I'm not sure if it is required for Vista). Right click on the file in Windows Explorer after copying it to the "bin\assemblies" folder and press the unblock window.</p> <p>When you restart 3ds Max, you will have a new user action in the category ".NET Plug-ins" that you will need to associate with a shortcut key or menu item. The plug-in should work for both 32-bits and 64-bit flavors of 3ds Max, but won't work on 3ds Max 2012 or earlier.</p> <p>I've also included a sample program called "DemoScript_BentCylinder.cs" that you should be able to run from the editor.</p> <p><img src="/userdata/blogs/chris/script_editor.png" alt="script editor screenshot" height="492" width="699" /></p> <p></p> <h2>Implementation Details</h2> <p>The following code compiles the source code of one or more files each passed as a string.</p> <pre><span class="code">/// Looks for and executes a public static function named Main by searching all types in the assembly.</span><br /><span class="code">/// If more than one Main function is found or no Main function is found an exception is thrown. </span><br /><span class="code">public static void RunMain(Assembly asm, params string[] args)</span><br /><span class="code">{</span><br /><span class="code">&nbsp;&nbsp;&nbsp; MethodInfo main = null;</span><br /><span class="code">&nbsp;&nbsp;&nbsp; foreach (var t in asm.GetTypes())</span><br /><span class="code">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; foreach (var mi in t.GetMethods(BindingFlags.Public | BindingFlags.Static))</span><br /><span class="code">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (mi.Name == "Main")</span><br /><span class="code">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (main != null)</span><br /><span class="code">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; throw new Exception("Multiple Main methods found");</span><br /><span class="code">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; else </span><br /><span class="code">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; main = mi;</span><br /><span class="code">&nbsp;&nbsp;&nbsp; if (main == null)</span><br /><span class="code">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; throw new Exception("No static public Main method found in assembly");</span><br /><span class="code">&nbsp;&nbsp;&nbsp; main.Invoke(null, new object[] { args });</span><br /><span class="code">}</span><br /><br /><span class="code">/// Compiles source code given the language provider (e.g. CSharpCodeProvider or VBCodeProvider). </span><br /><span class="code">/// The named assemblies are referenced. The contents of each source code file is passed as a </span><br /><span class="code">/// separate "input" string.&nbsp; Returns the generated assembly if successful or a list of errors. </span><br /><span class="code">public static CompilerResults Compile(CodeDomProvider provider, IEnumerable&lt;string&gt; assemblies, params string[] input) </span><br /><span class="code">{ </span><br /><span class="code">&nbsp;&nbsp;&nbsp; var param = new System.CodeDom.Compiler.CompilerParameters(); </span><br /><span class="code">&nbsp;&nbsp;&nbsp; param.GenerateInMemory = true; </span><br /><span class="code">&nbsp;&nbsp;&nbsp; foreach (var asm in assemblies) </span><br /><span class="code">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; param.ReferencedAssemblies.Add(asm); </span><br /><span class="code">&nbsp;&nbsp;&nbsp; return provider.CompileAssemblyFromSource(param, input); </span><br /><span class="code">}</span> </pre> <p>If compilation is successful the generated assembly is returned as part of the CompilerResults. Once you have the assembly you can invoke the Main entry point as long as it is a public static method of any public type using the following bit of reflection magic:</p> <pre> public static void RunMain(Assembly asm, params string[] args) { MethodInfo main = null; foreach (var t in asm.GetTypes()) foreach (var mi in t.GetMethods(BindingFlags.Public | BindingFlags.Static)) if (mi.Name == "Main") main = mi; if (main == null) throw new Exception("No static public Main method found in assembly"); main.Invoke(null, new object[] { args }); } </pre> <p>The rest of the code in the plug-in is pretty unremarkable but. I'd love to hear if this tool (or some derivation) finds its way into your toolbox.</p>Fri, 26 Oct 2012 15:55:08 UTChttp://area.autodesk.com/blogs/chris/dynamically-compiling-and-running-c-scripts-for-3ds-maxSDK and Scripting Classes at Autodesk UniversityChristopher Diggins<p>Autodesk University is being held November 26th to November 29th at the Mandalay Bay Resort in Las Vegas. While Autodesk University starts officially on November 28th, the Autodesk Developer Network is holding a specialized conference for <a href="http://au.autodesk.com/?nd=m_e_adn_conference_devlab&amp;und=1785">M&amp;E users</a>. If you are interested in the roadmap for our SDKs and meeting with some of the ADN API gurus then I encourage you to attend!&nbsp;</p> <p>The following is a select list of classes at the main AU conference which should also be of interest to people who use the scripting API or SDKs of 3ds Max, Maya, and Softimage. For a more complete list of classes regarding M&amp;E products <a href="/au2012">go here</a>.</p> <p>The first two classes listed are being offered by Cyrille Fauvel and Kevin Vandecar from the Autodesk Developer Network.&nbsp;</p> <p><a href="https://www.autodeskuniversity2012.com/connect/sessionDetail.ww?SESSION_ID=2520&amp;tclass=popup">CP2520 - Using .NET Programming in Autodesk&reg; Maya&reg;</a><br />Cyrille Fauvel , Autodesk (Autodesk Developer Network)<br /><br />In this class, we will introduce you to .NET programming in Autodesk Maya software. We will present using the C# language, but the techniques can apply to any .NET programming language including Microsoft&reg; Visual Basic&reg;. We will cover how to create an assembly that will load into the Maya environment. We will show how to interface with other .NET Framework features that will include the Windows Presentation Foundation (WPF) and other features such as LINQ functionality. This class will be organized for those who want an introduction to these new APIs, including practical techniques. You do not need to know Maya programming, but some general programming experience will be helpful.</p> <p><a href="https://www.autodeskuniversity2012.com/connect/sessionDetail.ww?SESSION_ID=2177">CP2177 - Autodesk&reg; 3ds Max&reg; .NET API Introduction and Techniques</a><br />Kevin Vandecar , Autodesk (Autodesk Developer Network)<br /><br />Last year, with the release of the Autodesk&reg; Subscription Advantage Pack for Autodesk 3ds Max 2012, .NET users gained access to significant enhancements in the Autodesk 3ds Max C++ SDK, enabling them to do more with Autodesk 3ds Max 2012 software. Now, these .NET APIs are available in the main product. In this class, we will introduce you to .NET API programming in 3ds Max. We will present using the C# language, but the techniques can apply to any .NET programming language, including Microsoft&reg; Visual Basic&reg;. We will cover how to create an assembly that will load into the 3ds Max environment. We will show how to interface with other .NET Framework features that will include the Windows Presentation Foundation (WPF) and other features such as LINQ functionality. This class will be organized for those who want an introduction to these new APIs, including practical techniques. You do not need to know 3ds Max programming, but some general programming experience will be helpful.</p> <p><a href="https://www.autodeskuniversity2012.com/connect/sessionDetail.ww?SESSION_ID=2443&amp;tclass=popup">DG2443-P - Autodesk&reg; 3ds Max&reg; MAXScript + Microsoft&reg; .NET: Discover a Bigger World</a><br />Paul Neale , PEN Productions<br /><br />In 2009, Autodesk 3ds Max software opened up MAXScript to .NET to enhance user interface design and extend the capability of MAXScript beyond the confines of 3ds Max. With .NET, tool developers can create dynamic and comprehensive production tools to help manage scenes, characters, and data sets, as well as an infinite host of other possibilities. In this class, you will learn to inspect .NET classes and objects and use them to build comprehensive .NET tools in MAXScript. This is an intermediate MAXScript class&mdash;participants should have a good working knowledge of MAXScript and the fundamentals of coding, including a good understanding of function, for loops and data types.</p> <p><a href="https://www.autodeskuniversity2012.com/connect/sessionDetail.ww?SESSION_ID=2619">DG2619-L - Autodesk&reg; Softimage&reg; Interactive Creative Environment: Making Math Accessible</a><br />Todd Akita , Psyop<br /><br />An all-too-common complaint from most visual artists is that in school, mathematics wasn't taught with a specific application or goal in mind and was too abstract or difficult to visualize. The Interactive Creative Environment (ICE) in Autodesk Softimage software combines high performance with a user-friendly interface. This combination of fast visual feedback and ease of use makes it a great environment to apply mathematics towards problem-solving in a hands-on way. In this hands-on lab, we will first examine what ICE is and what it can do. Then, we will introduce and review essential math concepts (trigonometry, vectors, and matrices) and explore the application of those concepts in a production context. Attendees should be familiar with the Softimage interface, but non-users are welcome because the graphics-related material is general enough to be applicable to almost any software package.</p> <p><a href="https://www.autodeskuniversity2012.com/connect/sessionDetail.ww?SESSION_ID=2567&amp;tclass=popup">DG2567-P - Autodesk&reg; Maya&reg; Scripting: MEL&trade; and Python</a><br />Roland Reyer , Autodesk<br /><br />The script language MEL (Maya Embedded Language) is not only a feature of Autodesk Maya software, it is the foundation. Every function in Maya is a MEL command that can be accessed using menus, icons, buttons, marking menus, and other controls. In this class, we will cover MEL concepts, the possibilities and limitations of this scripting language, and the differences in the Maya API. We will work through some examples, and discuss the differences between MEL and Python and explain the advantages of using Python for Maya.</p> <p><a href="https://www.autodeskuniversity2012.com/connect/sessionDetail.ww?SESSION_ID=2176">DG2176-P - Think Outside the Box: Custom Development with Autodesk&reg; Entertainment Creation Suites</a><br />Laurent Abecassis , Di-O-Matic<br /><br />During this class, you will learn the best practices and typical approaches involved when developing custom tools for Autodesk&reg; 3ds Max&reg;, Autodesk&reg; Maya&reg;, Autodesk&reg; Softimage&reg;, and Autodesk&reg; MotionBuilder&reg; software. We will cover scripting and programming languages and discuss the numerous APIs and SDKs available from Autodesk. This class will help you grasp what you can do beyond what is available out of the box in Autodesk entertainment creation suites.</p> <p><a href="https://www.autodeskuniversity2012.com/connect/sessionDetail.ww?SESSION_ID=3567">AV3567 - Parametric Design Modeling with Autodesk&reg; 3ds Max&reg;</a><br />David Fano , CASE<br /><br />This class will describe how to use Autodesk 3ds Max software modeling tools to build iterative parametric design systems. In this class, we will cover Autodesk 3ds Max geometry types such as Editable Mesh, Poly, Patch, and NURBS; combine modifiers to build complex systems; use wire parameters to quickly make geometric patterns; and provide an introduction to MAXScript. In this class, you will learn to reduce the amount of explicit modeling you do and instead build flexible design systems so you can focus more effort on design.<br /><br /></p> <p>Please let me know if I am missing any SDK or scripting classes that you think would be of interest to Area members.</p>Mon, 15 Oct 2012 18:53:11 UTChttp://area.autodesk.com/blogs/chris/sdk-and-scripting-classes-at-autodesk-universityEmbedding a Web Server in 3ds Max using .NETChristopher Diggins<h2>Controlling a .NET Application Remotely using a Web Server</h2> <p>The problem of controlling a .NET application such as 3ds Max from another process, or over a network, is similar to the challenge of <a href="/blogs/chris/calling-python-from-c-using-xml-rpc">controlling Python from C#</a> just in the other direction. In this blog post I describe how to embed a simple web-server implemented in C# in 3ds Max that executes MAXScript code.&nbsp;&nbsp;</p> <p>I have attached both the source code, and the .NET plug-in as a DLL. <a href="/userdata/blogs/chris/WebServer.zip"><br />Download WebServer.zip</a></p> <p>To load the web-server plug-in you have to copy the assembly (MAXScriptWebServer.DLL) in the bin/assemblies sub-folder of 3ds Max 2013. Next you need start up 3ds Max in <strong>Administrator Mode</strong>. Now when you go to the "Customize menu" you should see the user action in the &ldquo;.NET samples&rdquo; category. You can then associate it with a short-cut key or menu option. For more information on registering custom actions see the <a href="http://docs.autodesk.com/3DSMAX/15/ENU/3ds-Max-Help/files/GUID-71DEAF46-80B6-47D8-8F58-F103CECEE1F5.htm%20">3ds Max documentation</a>.</p> <h2>Why use a Web Server and not Sockets?</h2> <p>At first it might seem like overkill to embed a web-server in your application when you just want to send messages to it. As one of my colleagues asked, why not just use sockets?</p> <p>When you get rigtht down to it, a web-server is effectively a wrapper around one end of a TCP/IP socket that uses HTTP as the application level communication protocol. Using HTTP provides you with a well-defined and widely available standard for sending data to and from a server, with protocols for both error handling and content encoding. For me the biggest win is the fact that I can use any web-browser as a client!</p> <h2>Fundamental Classes</h2> <p>Okay, now that we have gotten past your irrational fear of embedding a web-server in your .NET application let&rsquo;s look at the building blocks:</p> <ul> <li>System.Net.HttpListener &ndash; receiving and responding to HTTP requests</li> <li>System.Web.HttpUtility &ndash; parsing query string data</li> <li>System.Windows.Threading.Dispatcher &ndash; executing code on the main thread</li> <li>System.Thread.Thread &ndash; executing http listening on a separate thread</li> <li>Autodesk.Max.IGlobal &ndash; accessing the core interfaces of the 3ds Max .NET API, for example to execute MAXScript code.</li> </ul> <h2>Basics of Creating a CUI Action</h2> <p>I opted to create the server a custom .NET user action for 3ds Max 2013. To create a custom .NET action you have to create a class derived from UiViewModels.Actions.CUICommandAdapter. This is an abstract class that requires you to implement five methods:</p> <ul> <li>string ActionText &ndash; A string property that represents the name of the action as shown on menus and buttons.</li> <li>string InternalActionText &ndash; A non-localized version of ActionText</li> <li>void Execute(object parameter) &ndash; The function called when the action is triggered by 3ds Max. For example if a menu item selected or&nbsp; short-cut key us pressed.</li> <li>string Category &ndash; The name of the category the action can be found in the customize dialog.</li> <li>string InternalCategory &ndash; A non-localized version of Category.</li> </ul> <p>In your project you will have to first reference the following assemblies which can be found in the 3ds Max application folder:</p> <ul> <li>Autodesk.Max.dll</li> <li>UiViewModels.dll</li> </ul> <p>It is very important that when you create the reference in your proejct that you set the &ldquo;copy local&rdquo; property to false. Be sure you also don&rsquo;t make the same mistake I did and I link to the wrong version of 3ds Max.</p> <p>Now you will need to add references to the following Microsoft assemblies:</p> <ul> <li>PresentationCore</li> <li>System.Web</li> <li>System.Windows.Forms</li> <li>WindowsBase</li> </ul> <p>Finally you should set the output folder of the project to the &ldquo;bin/assemblies&rdquo; sub-folder of 3ds Max.</p> <p>For more information on writing .NET plug-ins <a href="http://docs.autodesk.com/3DSMAX/15/ENU/3ds-Max-SDK-Programmer-Guide/files/GUID-ED89ECC5-5E40-43AD-932A-CC377C5BFF55.htm">see the 3ds Max SDK documentation</a>.</p> <p></p> <h2>Starting the Web Server</h2> <p>When you start the web-server from the menu (or shortcut key depending on how you registered it) you will see the followigntext in the MAXScript listener:</p> <p style="padding-left: 30px;">&nbsp; Starting HTTP listener<br />&nbsp; HTTP listener started<br />&nbsp; Thread started</p> <p>You can now point your browser to: <a href="http://localhost:8080/test">http://localhost:8080/test</a> and you will see something similar to the following screen shot:</p> <p><img src="/userdata/blogs/chris/web-server.png" height="487" width="762" /></p> <h2><br />Using the web Server from MAXScript</h2> <p>The user action class library can also be loaded from MAXScript. This can be useful if you want the server to start up with 3ds Max. The following code shows how to launch the web-server from a MAXScript script:</p> <pre>fn startWebServer = ( Assembly = dotNetClass "System.Reflection.Assembly" maxroot = pathConfig.GetDir #maxroot Assembly.LoadFile (maxroot + "\\bin\\assemblies\\MaxScriptWebServer.dll") cls = dotNetClass "MaxScriptWebServer.MaxScriptWebServer" server = dotNetObject cls print "Created: " + server.actionText server.execute undefined ) startWebServer () </pre> <h2>Highlights of the Web Server Code</h2> <p>The web-server is implemented primarily by the System.Net.HttpListener class. The implementation is <a href="http://msdn.microsoft.com/en-us/library/3x8d2eck(v=vs.100).aspx">based on the example shown on MSDN</a>. The three most important things to note about the code are:</p> <ol> <li>We want the web-server to run on its own thread so that 3ds Max remains responsive.</li> <li>The MAXScript code comes from an HTML form URL encoded and has to be decoded.&nbsp;</li> <li>We want the MAXScript code to be executed on the main thread.</li> </ol> <p>First, to get the web-server to run on its own thread we use the System.Thread.Thread class.</p> <pre> var t = new Thread(() =&gt; ListenLoop()); t.Start(); </pre> <p>Next to decode the MAXScript code sent from the web-page we need to use System.Web.HttpUtility to retrieve and decode the form text.</p> <pre> public static string GetFormData(HttpListenerRequest request, string formName) { if (request == null || !request.HasEntityBody) return ""; var body = request.InputStream; var encoding = request.ContentEncoding; var reader = new System.IO.StreamReader(body, encoding); var text = reader.ReadToEnd(); body.Close(); reader.Close(); var queryVars = HttpUtility.ParseQueryString(text, encoding); return queryVars[formName]; } </pre> <p>Finally to execute the MAXScript code on the main thread we use a System.Windows.Threading.Dispatcher</p> <pre> // Execute the evaluation of the code as MAXScript on the main thread. Action a = () =&gt; global.ExecuteMAXScriptScript(code, false, null); dispatcher.Invoke(a); </pre> <h2>Next Steps</h2> <p>If you are interested in a more sophisticated mechanism for controlling 3ds Max you might want to look into using XML RPC to control 3ds Max using the <a href="http://xml-rpc.net/">XML-RPC.NET library</a>.</p> <p>If you need full bi-directional communication between a server application and multiple clients and for some reason polling is not acceptable then I would recommend investigating using <a href="http://stackoverflow.com/questions/4985629/html5-websockets-client-for-net">HTML5 Web sockets</a>.</p>Tue, 09 Oct 2012 15:24:12 UTChttp://area.autodesk.com/blogs/chris/embedding-a-web-server-in-3ds-max-using-netMAXScript - Baking Animation TransformsChristopher Diggins<p>A colleague of mine, Amer Yassine, who manages the awesome <a href="http://www.youtube.com/user/3dsmaxhowtos?feature=results_main">3ds Max YouTube learning channel</a> recently asked me how to bake world space transforms to helper objects.</p> <p>Amer provided me the example of an arm with three bones and three helper objects. Each helper object was parented to the bone and the bones were animated using an IK solution. When he collapsed the transform controllers on the point helpers it would create keyframes for the helpers but with 0 values. So when he unlinked the helper objects they were no longer animated. This makes sense because the position of helpers was in local space relative to the parent object, but what Amer wanted were position/rotation keys for the helpers based on the world-space data.</p> <p>My first thought was to try and find some scripts on <a href="http://www.scriptspot.com">ScriptSpot.com</a> to do what he wanted. However none seemed to work and at first I wasn't quite clear on what the precise problem we needed to solve was. Eventually I found a thread on <a href="http://www.cgsociety.com">CGSociety.com</a> where a similar question was framed in a way that explained what Amer and I were looking for except it applied to a camera:</p> <p style="padding-left: 30px;"><em>I have been fumbling around trying to find a way to bake out some animation I have on a camera. The camera is animated via three dummies in a hierarchy and I need to 'bake' in the animation at every keyframe in worldspace. Currently every method/script I have found bakes the animation in local space so when the dummies/point helpers have been deleted the camera does not retain any of the animation, yet I have a keyframes at every frame. Is there a way to create keyframes that would take the position/rotation of the camera in worldspace at everyframe and allow me to delete everything but the camera and retain all animation?</em></p> <p style="padding-left: 30px;"><a href="http://forums.cgsociety.org/archive/index.php/t-740206.html">http://forums.cgsociety.org/archive/index.php/t-740206.html</a></p> <p>Now I was getting somewhere, because I finally understood the problem! The ensuing thread didn't make much sense to either of us, but going back to first principles, I created a basic script that:</p> <ol> <li>Un-parented the helper from the bone.</li> <li>Created a key-frame for the helper object at each frame based on the bones position/rotation/scale.</li> </ol> <p>The resulting solution is quite elegant using MAXScript:</p> <pre>-- Create keys for the selected objects from the world space transforms taken from the parents (bones). -- Also unlink each object from the parent. startTime = 0 endTime = 100 nthFrame = 5 -- For all selected objects for obj in $ do ( -- Get the current parent (a bone) and unlink the object. bone = obj.parent obj.parent = undefined -- Create animation keys for t in startTime to endTime by nthFrame do ( animate on at time t ( obj.transform = at time t bone.transform ) ) ) </pre> <p>The magic in this script occurs in the "animate" context expression. Check out the <a href="http://docs.autodesk.com/3DSMAX/15/ENU/MAXScript-Help/files/GUID-CC2D2450-AECD-4732-BF93-4AA91ED0BC56.htm">MAXScript documentation on the animate keyword</a> to learn how it works. In short it acts like the "autokey" mode in 3ds Max. Any animatable property you change (such as the transform) is automatically associated with a new key.</p> <p>I hope the rest of the script is sufficiently clear for you to use and modify for your own work. It did the trick for Amer. :-)</p> <p href="http://www.youtube.com/playlist?list=PLnKw1txyYzRlxh1-BT4CifPXC5TBg2vUd&amp;feature=plcp">By the way, if you use 3ds Max at all you should check out Amer's <a href="http://www.youtube.com/playlist?list=PLnKw1txyYzRlxh1-BT4CifPXC5TBg2vUd&amp;feature=plcp">tutorial on rigging a character for games</a> that he just recently started posting. It is an amazing tutorial series that will have 40 parts once it is all online!</p>Tue, 02 Oct 2012 15:12:36 UTChttp://area.autodesk.com/blogs/chris/maxscript---baking-animation-transformsCalling Python from C# using XML RPCChristopher Diggins<p>I wanted a host .NET application (in this case 3ds Max, but it applies equally to any .NET API like AutoCAD) to inform a Python script running on the same machine but in a different process whenever a particular event occured.</p> <p>I first rejected a number of possible solutions that were low-level and that would prevent me from moving the client to another computer.</p> <ul> <li>Named pipes</li> <li>Memory mapped files</li> <li>Windows messages</li> <li>DLL function invocation&nbsp;</li> </ul> <p>Two remaining options seemed like possible candidates:</p> <ul> <li>Web sockets</li> <li>HTTP server running in the host</li> </ul> <p>I liked the Web sockets approach, but the libraries for using them in C# and Python are not quite as mature or easy to use as I had hoped. Running an HTTP server and having the Python application poll it repeatedly seemed like the best option. However, I was concered about all of the wasted resource for the Python client to ping the host application repeatedly not to mention the potential for poor responsiveness.</p> <p>After a bit of thought I realized that embedding the HTTP server in the Python application and treating the .NET application as the client would be a lot easier!&nbsp;</p> <p>With an HTTP server running in the Python application, I was with a new set of possibilities for communicating data from the host application to the Python client.</p> <ul> <li>Simple HTTP API using query strings</li> <li>REST API</li> <li>SOAP API</li> <li>XML RPC API</li> </ul> <p>After further investigation I decided the simplest out-of-the-box solution would be to use the <a href="/docs.python.org/library/simplexmlrpcserver.html">SimpleXmlRpcServer </a>module in Python and the <a href="http://msdn.microsoft.com/en-us/library/system.net.webrequest.aspx">System.Net.WebRequest</a> class in .NET. After quickly scanning the information on <a href="/en.wikipedia.org/wiki/Xmlrpc">XML RPC on Wikipedia</a> and hacking the example in the documentation for WebRequest and SimpleXmlRpcServer I ended up with a working prototype with almost no effort:</p> <p>Here is the sample .NET client:</p> <blockquote> <pre>using System; using System.Text; using System.Net; using System.IO; namespace SimpleXmlRpcClient { class Program { static void Main(string[] args) { WebRequest request = WebRequest.Create("http://localhost:8000/RPC2"); request.Method = "POST"; string postData = @"&lt;?xml version=""1.0""?&gt; &lt;methodCall&gt; &lt;methodName&gt;add &lt;params&gt; &lt;param&gt; &lt;value&gt;&lt;i4&gt;21&lt;/i4&gt;&lt;/value&gt; &lt;/param&gt; &lt;param&gt; &lt;value&gt;<i4>21</i4> &lt;/param&gt; &lt;/params&gt; &lt;/methodCall&gt;"; byte[] byteArray = Encoding.UTF8.GetBytes(postData); request.ContentType = "application/x-www-form-urlencoded"; request.ContentLength = byteArray.Length; Stream dataStream = request.GetRequestStream(); dataStream.Write(byteArray, 0, byteArray.Length); dataStream.Close(); WebResponse response = request.GetResponse(); Console.WriteLine(((HttpWebResponse)response).StatusDescription); dataStream = response.GetResponseStream(); StreamReader reader = new StreamReader(dataStream); string responseFromServer = reader.ReadToEnd(); Console.WriteLine(responseFromServer); reader.Close(); dataStream.Close(); response.Close(); Console.WriteLine("Press any key to continue ..."); Console.ReadKey(); } } } </pre> </blockquote> <p>Here is the sample Python host:</p> <blockquote> <pre>from SimpleXMLRPCServer import SimpleXMLRPCServer from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler # Restrict to a particular path. class RequestHandler(SimpleXMLRPCRequestHandler): rpc_paths = ('/RPC2',) # Create server server = SimpleXMLRPCServer(("localhost", 8000),requestHandler=RequestHandler) server.register_introspection_functions() # Register a function e def adder_function(x,y): return x + y server.register_function(adder_function, 'add') # Run the server's main loop server.serve_forever() </pre> </blockquote> <p>Hopefully this is enough to get your favorite .NET application talking to your favorite Python application. Happy hacking!</p>Wed, 19 Sep 2012 17:14:53 UTChttp://area.autodesk.com/blogs/chris/calling-python-from-c-using-xml-rpc