tag:blogger.com,1999:blog-42121500793140712232024-03-08T12:34:08.409+01:00Creative ScratchpadRandom maxscript snippets and sample toolsSwordslayerhttp://www.blogger.com/profile/09124250713006663760noreply@blogger.comBlogger41125tag:blogger.com,1999:blog-4212150079314071223.post-42110998716043486802019-07-28T21:35:00.044+02:002024-02-13T14:49:37.135+01:003ds Max SDK: First Steps for Scripters<p>Even experienced scripters may feel intimidated by the prospect of dipping their toes into the C++/SDK territory, especially when faced with the sheer volume of the documentation and all the topics covered. However, you don't have to go full C++ right away. In this walkthrough, I'll guide you through using the <a href="http://help.autodesk.com/view/3DSMAX/2020/ENU/?guid=__developer_3ds_max_sdk_features_function_publishing_html">Function Publishing</a> system to develop your own MAXScript functions. I will also demonstrate how to effectively incorporate these functions into a pair of sample scripted <a href="https://help.autodesk.com/view/3DSMAX/2020/ENU/?guid=GUID-7AAEEA29-A627-43CF-B2F8-8B8BBB20F5E4"><code>simpleMeshMods</code></a> to get the best of both worlds.</p>
<p>Some topics and features I will only touch on briefly to keep the breakdown concise and actionable. It's not necessary to grasp every little detail on the first read; rather, I would encourage you to come back to revisit parts of the walkthrough and use them as stepping stones to learn more over time.</p>
1. <a href="#vs_setup">Visual Studio</a><br>
2. <a href="#max_SDK">Max SDK</a><br>
3. <a href="#project_wizard">Max Plugin Wizard</a><br>
4. <a href="#project">Project Setup</a><br>
5. <a href="#build">First Build</a><br>
6. <a href="#core_interface">Core Interface</a><br>
7. <a href="#core_instance">Core Interface Instance</a><br>
8. <a href="#methods">Interface Methods</a><br>
9. <a href="#static_interface">Static Interface</a><br>
10. <a href="#methods2">Interface Methods Continued</a><br>
11. <a href="#the_core">THE Core Interface</a><br>
12. <a href="#convenient">Convenience Features</a><br>
<br>
<a name='more'></a>
<div style="font-size: 10pt; font-weight: bold; padding-bottom: 6px;" id="vs_setup">Visual Studio</div>
<p></p>
<p>To get started, download and install Visual Studio – I'll be using 2019 Community (available for download at <a href="https://www.visualstudio.com/thank-you-downloading-visual-studio/?sku=Community&rel=16
">visualstudio.com</a>) in the course of this article, and if your target is max 2018+, I suggest you do too. It is binary compatible with VS 2017 and a bit more friendly to C++ devs. That said, in the begining I will also provide instructions for those using VS 2017.</p>
<p>During the Visual Studio installation process, you will have to make some changes to the <a href="#vs_components">individual components</a> installed – though the <i>Desktop Development with C++</i> is a good start. At the very least, you need to pick the right Win 10 SDK and Platform Toolset versions – refer to the <a href="https://help.autodesk.com/view/3DSMAX/2020/ENU/?guid=__developer_about_the_3ds_max_sdk_sdk_requirements_html
">SDK Requirements</a> page for the intended Max version. For example when developing plugins for Max 2018/19/20, make sure to pick both Windows 10 SDK (<code>10.0.10586</code>) and (<code>10.0.17134.0</code>) and VC++ platform toolsets v140 and v141. VS 2017 provides these options during installation process; VS 2019 will require a separate Windows 10 SDK download for the older version – you can get it from the <a href="https://developer.microsoft.com/en-us/windows/downloads/sdk-archive">Windows SDK archive</a>.</p>
<p>You can also uncheck the <i>Visual C++ ATL</i> – there are still some MFC dependencies in the wizard but we'll get those sorted shortly. With such a long list of components, you might wonder whether to throw in a few extras before hitting the install button. No need to stress about it now. You can always come back to the installer later and tweak your component setup as you see fit.</p>
<p>When it comes to the C++ standard used, Max 2020 projects default to C++14, as does Visual Studio 2017. Technically, you may try and use C++17, since <code>/std:c++17</code> is supposed to be binary compatible with <code>/std:c++14</code> (and it seems to work without hitches) but you obviously better have a good reason for going that route in the first place. And if this is the first time you're hearing about different C++ versions, just make a mental note of it – the bottom line is that you can use tutorials that teach modern C++.</p>
<p>With that said, let's doublecheck the list:</p>
<div id="vs_components" class="separator" style="clear: both; text-align: center;"><img height="auto"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh86l-zcDGcy9pffornR_gyP_ZLlTTMbJWm9ETUMLvmFNpim1F6wWHVKvrBuStFwZiFyFwlALLn2_F1NqP335Qe9zkNwR5-t81HK9-DDV5LK75jtYANlPaQtdn8Q7Gz2aL4wUxjegH5NHg/s1600/installation_details_2019.png" /></div>
<p>For 2017, the component list might look like this instead:</p>
<div class="separator" style="clear: both; text-align: center;"><img height="auto" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-x-pH9Xx52qpZVxSDWVPDB2_3RAwaomYLNdb1IJBcgzQfhnwf099OBc_55fVn06gTirUHu23PCmobpnLzj6sXXNOBVstSi5f7fTnD54j9_9gIQjTmLekN5iVax1veEZ3oWWabLiqcdEI/s1600/installation_details.png" width="auto" /></div>
<br><div style="font-size: 10pt; font-weight: bold; padding-bottom: 6px;" id="max_SDK">Max SDK</div>
<p></p>
<p>You need to install the SDK for each Max version that you want to build your tools for. There are several ways to do this. If you have the installation media for your target Max version, either go through the <i>Instal Tools and Utilities</i> submenu of the main Max installer or execute the <code>msi</code> from inside the <code>x64\Tools\MAXSDK</code> folder of the installer source files. For Max version 2017 and up, you can download the SDK installer and other related files from the <a href="https://aps.autodesk.com/developer/overview/3ds-max#3dsmax-sdk">Autodesk Platform Services</a> page.</p>
<p>During the installation, I'd suggest that you change the destination folder for the SDK. The default location points into <code>Program Files</code>, and in the next steps you will need to edit a few files there. If you unpacked them into a protected folder, you'd have to <a href="https://www.howtogeek.com/301768/how-to-take-ownership-of-files-and-folders-in-windows/">take the ownership</a> of those files (or the whole folder) to be able to modify them. It's more of a nuisance than a deal-breaker – still, it's easier if you choose a location for which you already have the necessary permissions. It's a good idea to include the Max version in the folder name, as each compatibility-breaking Max release comes with a new SDK.</p>
<br><div style="font-size: 10pt; font-weight: bold; padding-bottom: 6px;" id="project_wizard">New Project Wizard</div>
<p></p>
<p>The next step is to add the 3ds Max Plugin wizard to Visual Studio. Inside the <code>maxsdk\howto\3dsmaxPluginWizard</code> folder you will find the <code>readme.txt</code> file that details what you need to change in the template, as well as the files that you need to modify - both VS 2015 and 2017 are covered, the only thing different for 2019 is that you need to bump up the version to <a href="https://help.autodesk.com/view/3DSMAX/2020/ENU/?guid=__developer_writing_plug_ins_creating_a_plug_in_project_using_appwizard_to_create_a_new__installing_the_plug_in_wizard_ap_html"><code>VsWizardEngine.16.0</code></a>.</p>
<p>On a fresh VS install, you might need to create the <code>vcprojects</code> folder to copy the edited files to, too. Alternatively, you can use the <code>%USERPROFILE%\Documents\<Visual Studio version>\Wizards folder</code> – again, the folder will have to be created if it doesn't exist. Once you have done this and relaunched Visual Studio, you should be able to pick the 3ds Max Plugin wizard when creating a new project.</p>
<p>In VS 2019 you'd have to turn off filtering by language (if active) to see it. Most likely it won't be the top item – if you can't see it right away, scroll down and look for a 3ds Max icon.</p>
<p>In VS 2017, you input the project name and optionally uncheck the <i>Create directory for this solution</i> box to keep the project self-contained (which I do here) right when you pick the wizard:</p>
<div class="separator" style="clear: both; text-align: center;"><img height="auto" width="500"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIoQp6wrK5Bg9I-IXCbUcWugsz7jLItG8253Zn4V1ZxVadiWoI6y8fWIOuZoZ4MWmRPjqWCJN_guybB-LixCgn5AxDh-_43Pg0mm17mxKtfTA7DJYDeNohZXYJtve2DkJgDIoRSfuIOFM/s1600/wizard_01.png" /></div>
<p>In vs 2019 a separate configuration windows pops up and the logic for the checkbox is reversed (I'm checking it, I have no plans to add other projects under the solution anyway). Bear in mind that the project name you enter will also be used as the class name by the wizard.</p>
<div class="separator" style="clear: both; text-align: center;"><img height="auto" width="500"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhceUHlkr5-ZnYqZA-Sj3A2JSTp9CI3zJr36PQu0lFGErxSR9590mq1XKPUiF0hkSkOYagyF6UQHyjsOb2pjGC7UgAsDcSC54jZpW-I94KMlmGCIttWfiJRnqatzzd1QOyO1qbyURSvMVM/s1600/wizard_01_2019.png" /></div>
<p>After confirming the project configuration, you should be greeted with the first page of the 3ds Max Plugin Wizard. Select <i>Global Utility Plug-Ins</i> as the plugin type. This is a plugin which does not provide a user interface, and is globally available right from the start of the application. Perfect for our custom MAXScript functions.</p>
<div class="separator" style="clear: both; text-align: center;"><img height="auto" width="500"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjR7mbycVy9j51RV0ttlRdQzRcVnLlA_A4aujIN1Aptw5NwkOQfK4bp8Ydwa4MRTvXuBXIvW_7fUJONgt_3R0wtd8AxAh_tBqGtn3kcJh5Y6OPxAdUx6Nrog0ujeeD0YBncrZulkyLS-E/s1600/wizard_02.png" /></div>
<p>The additional empty fields you'll be asked to fill in on the next page are not that important. To give you an idea, if you ask for the <code>.category</code> of a plugin in max, it will return what you fill in here. The full description will show up when you open the Plug-in Manager.</p>
<div class="separator" style="clear: both; text-align: center;"><img height="auto" width="500"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4PLI56OYe2ln9X5EyJjNcGBFBOOfCAL0Dx_xsHwtbfbXJqsXoND0wancKT6BrHhutoXrUXNYBYuzG2po73V6bnACWZjSlrezWRQeATk8iTNVTRZu70AFeoXRywPADkX9qgN5z_YNsXqI/s1600/wizard_03.png" /></div>
<p>At the last page, leave all the boxes unchecked and fill in the path using <a href="https://helpdeskgeek.com/how-to/create-custom-environment-variables-in-windows/">environment variables</a> (they should be created by the Max and SDK installers):</p>
<div class="separator" style="clear: both; text-align: center;"><img height="auto" width="500"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirwBQMHt3oTd3VL0_XpiG_FsbI6AzjQdTYymM1UAtr3gDDnApy3LT1dxNiMlf06k624EgfX_HT78kNakLtPriPDqtO1VqlzXLVWSyjr8lTfBR7Wl88GkAMzRIh5Kdvm9oETa4p79QMJyQ/s1600/wizard_04.png" /></div>
<p>For 3ds Max 2020, those would be:</p>
<pre class="notranslate">
MAXSDK path: $(ADSK_3DSMAX_SDK_2020)
ouput path: $(ADSK_3DSMAX_x64_2020)\Plugins
3dsmax.exe: $(ADSK_3DSMAX_x64_2020)
</pre>
<p>Once you click the Finish button, the skeleton project should be set up for you and ready to be compiled. In case you want to know more about the details of the setup – or if you need something more complex in the future and the wizard will no longer cut it – there's a <a href="https://help.autodesk.com/view/3DSMAX/2020/ENU/?guid=__developer_writing_plug_ins_creating_a_plug_in_project_manually_creating_a_new_plug_in__html">Manually Creating a New Plug-in Project</a> section of the 3ds Max developer reference. Don't get discouraged if it opens to a blank page, the chapter contents are available in the sidebar.</p>
<p>With the project created, the workspace should look something like this:</p>
<div class="separator" style="clear: both; text-align: center;"><img height="auto" width="auto"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjL0JXg1H5XmYy_4-Cdjbn1fwPu3-OO14yO2YYcLXUgKvK2rtqkSH4HjR2mgq01cDNqjx-w2_GGU67zv7kS0SPKuuxHj6hWiluDuxhECI8wNJic6HRzig7vTXqewhEn_4ivEoZdyeo5fS4/s1600/initial_workspace.png" /></div>
<p><br>Since it's the only project in the solution, you can right-click the project name and choose <i>Scope to This</i>. It doesn't change the project confifguration in any way, you can think of it as removing one level of indentation in the folder tree so that a bit more fits in.</p>
<p>Now comes the important part to make it possible to actually build something. Click the 'Debug' dropdown in the toolbar and switch to the <i>Hybrid</i> config.</p>
<div class="separator" style="clear: both; text-align: center;"><img height="auto" width="auto"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwoGm3eCVtOQoOlDKdlKsWQ7gmMoKDef0ac05Z7H3QrEgD7zdsllbz80IBqNePHhLsRwAhntjTdJ8eI8Vq4yfvxkG8UYwCP-FH8t20NdNc1_cqhpSg8LFEtXEthWOwZbIS739b0hs80FY/s1600/initial_workspace_fixed.png" /></div>
<p>You might be used to running in Debug while developing but when you start out, you will be building against the release version of 3ds Max. Plugins built in Release mode obviously work with it, but for debugging purposes you are limited to the Hybrid config; optimizations are turned off and asserts are enabled – and to make the experience as nice as possible, Autodesk provides public debugging symbols for 3ds Max – not something you'll need right now if you're just dipping your toes, but it's worth keeping in mind for future reference. For the detailed walkthrough, refer to the <a href="https://getcoreinterface.typepad.com/blog/2018/09/3ds-max-public-debug-symbols-updated.html">3ds Max Public Debug Symbols</a> article.</p>
<p>And in case you're wondering why is the Debug config even there, it's because when you are tracking down some obscure bugs, you want to get as much information and possible, and a debug version of 3ds Max is handy for that. It is available for development and testing purposes through the Autodesk Developer Network. There are several ways to get the <a href="https://www.autodesk.com/developer-network/membership-options">ADN Standard Membership</a> to get access to it. For one, as an 'underfunded start-up developer' to quote the website, you can apply for a free ADN Standard membership. You can also get a one-year membership as a part of the <a href="https://www.augi.com/about-augi/membership/levels/professional
">AUGI (Autodesk User Group International) Professional Membership</a> for individuals (see the <a href="https://www.augi.com/adn-membership-offer">terms for the ADN offer</a>), it also comes as a benefit of the <a href="https://s3.amazonaws.com/adsk-designacademy-content-live/s3fs-public/Student%20Expert_Achievement%20Guide.pdf
">Autodesk Student Expert Membership</a>, and there's special pricing available on demand for authors of learning materials (books/videos/online).</p>
<br><div style="font-size: 10pt; font-weight: bold; padding-bottom: 6px;" id="project">Project Setup</div>
<p></p>
<p>This is where we actually start touching the contents of the project that the wizard created. I tend to leave most of the auto-generated files as is, only delete the TODO <code>#pragma messages</code> from DllEntry.cpp. For what we do, we pretty much just need an empty gup plugin so there's nothing to do there and the TODOs would only pollute the error/warning list. Since I won't be providing any localization for the function printout either, I also remove the <code>MaxSDK::Util::UseLanguagePackLocale();</code> call in the same file.</p>
<p>There's another TODO item in the same file, this time in the form of comment, <code><i>//TODO: Must change this number when adding a new class</i></code>. For our use case, the number will always be 1. While you can technically have multiple plugins inside one file – even of different types – it's not something you should ever need to do anyway.</p>
<p>The other cpp file is named the same as your project. As before, you can get rid of the TODO <code>#pragma messages</code> here as well. The wizard generated unique <code>Class_ID</code> for your plugin, and I might be happy to use it if weren't for the comment <code><i>// Slapped together random num gen</i></code> which doesn't exactly inspire confidence that there won't be a collision with other plugins. So I always generate a new one with the tools provided by Max – either directly within Max via <code>genClassID()</code> or with the help of the <code>gencid.exe</code> inside the <code>maxsdk\help</code> directory). This is up to you, I like to err on the side of caution.</p>
<p>What really matters, however, is that the line where it says <code><i>// Returns fixed parsable name (scripter-visible name)</i></code> refers to the plugin name as seen by MAXScript – or rather, its MAXScript alias. Chances are you've named your project the way you want to access the published function interface (variations on <code>MyFunctions</code> are a natural choice, provided that it's an identifier that doesn't already exist and is not likely to cause a conflict with other devs' naming). Depending on your preference, you may want to have a single interface with all functions (the aforementioned <code>MyFunctions</code>), in which case Core Interface would be the better choice. Alternatively, you may prefer to group multiple interfaces under one common identifier, such as <code>MyFunctions.MeshTools</code>, <code>MyFunctions.SplineTools</code>, and <code>MyFunctions.Math</code>.</p>
<p>If the latter, everything is okay as is. You can skim through the Core Interface chapter and focus on the Static Interface one. If the former, you don't really want the property-less utility (that you cannot use in any way from MAXScript) to block the interface of the same name (identical names means one would be shadowed by the other). In that case, I tend to append "Util" to the name (it's a global utility plugin after all). Here, that would make it <code>_T("<a href="#class_desc" id="class_name">MXSExposureUtil</a>")</code>.</p>
<p>There's one other location where you also have to edit the string (and if you are familiar with the VS interface you can skip <a href="#name_edits">right there</a>), but before we get to that, you might have noticed something else while editing the first one. In VS 2019, once you start making the edits, lots of squiggly lines will appear due to <i>Code Analysis</i> running in the background:</p>
<div id="class_desc" class="separator" style="clear: both; text-align: center;"><img height="auto" width="550"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjibkunHQZJ-DXjbfyi9vLdLfqe2Btmwm3Sq7X3By9f13pAcDLzPXbM5GHxInljXp_4QUK7pvbDQ-RUm7DushtJV9opZ7fSZ1kNqU6MCBK7dJFl6ddDCUvhUCTeM76cnECZIAbsbRUdfTk/s1600/squiggly.png" /></div>
<p>They mark the warnings emitted by checking the code against the rules used by Code Analysis (by default its the C++ Core Guidelines) and provide hints that you can hover over (as you can see from the tooltip) and sometimes offer matching FixIts. While certainly helpful while writing new code, I don't think anyone is terribly keen to see warnings for code that's out of their control. Especially in the <i>Error List</i> window (accessible through <i>View</i> > <i>Error List</i> or by clicking the stop sign/exclamation mark icon in VS 2019) they can actually drown the warnings that apply to your project (you can filter by current document but sometimes you really want to see a complete list of potential issues in your project without flipping through each and every file):</p>
<div class="separator" style="clear: both; text-align: center;"><img height="auto" width="550"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjOGTm4o1wEnhY1Ot7sNGTuIfjGVyhXVQ-tSpg3eXOzcE1M1VXF8u__TxlQFbNron4MQXjCpoWo7HyZfPQn_2whtFK1D25f5VVHH9igsUSFI5uWc3UtCD1yN2oqYok0LIz157AyvS8LkA/s1600/error_list.png" /></div>
<p>In VS 2017, you'd have to explicitly run Code Analysis to see this – and since it's a good practice to get into, I suggest you set <i>Tools</i> > <i>Options</i> > <i>Text Editor</i> > <i>C/C++</i> > <i>Experimental</i> > <i>Disable Background Code Analysis</i> to <b>False</b> so that you get the updated error/warning list every time you save your files instead of only on demand. In VS 2019, this happens automatically on the fly by default.</p>
<p>The next step is to filter out the SDK warnings without removing warnings for our code. Since the main include file is <code>#include</code>d in all the autogenerated project files that we won't likely need to touch (other than to cleanup those warnings), we can paste these lines above the default includes to turn the warnings off for all the files using it:</p>
<pre class="notranslate">#include <codeanalysis\warnings.h>
#pragma warning (disable : ALL_CODE_ANALYSIS_WARNINGS)</pre>
<div class="separator" style="clear: both; text-align: center;"><img height="auto" width="550"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbXeXOVTF82ipDujKa_2R7JW6UlGnSGSuLrcLVAAs2x6EfBfE_RJpxz8UP9MRlI8IqQX_pxwUTLi6mbqPba-cqYFfFpshhJrUBJvpBA55OhN_kVNhS188PGwjZcV6qXOg5lMh-qUdN6ho/s1600/code_analysis_skip.png" /></div>
<p>Saving the file should result in the warnings being removed (it may take a little while) and you should be left with a clean slate again. If that's not the case, try turning the Code Analysis off and on again (by toggling and applying <i>Tools</i> > <i>Options</i> > <i>Text Editor</i> > <i>C/C++</i> > <i>Advanced</i> > <i>Code Analysis</i> > <i>Disable C++ Code Analysis Experience</i> twice):</p>
<div class="separator" style="clear: both; text-align: center;"><img height="auto" width="550"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDap7wAg5DScE-1WqnPuQEq3vbO0bp2zbqoSeEyTfH_Hx_FZ-s6ctQQvmOJtOuaomO5FU8U8JpDBqLi0tfYGKpweaL_SYjspV6wDv5PUn4qKOgLE5Lq3kDeOi5IUgf1Gqb0qvOnIg0ZHc/s1600/code_analysis_2020.png" /></div>
<p id="name_edits">Time to pick up where we left off, with the name edits. The plugin className that will also be exposed to MAXScript and could shadow your interface name is taken from the value of <code>IDS_CLASS_NAME</code>, defined inside the resource file in the Resource Files folder. So let's have a look at it.</p>
<p>You might instinctively double-click it and expect it to open, but if you remember how I mentioned unchecking the MFC tools and you did just that before (or you went directly to the list of components and handpicked them one by one without checking this one), you will only get an error message – no dialog window for you. What dialog, you ask? Let me show you.</p>
<p>Right-click that .rc file and choose <i>Open With...</i> <i>C++ Source Editor</i>. The <code>afxres.h</code> header is a part of the MFC Library which works as an easier-to-use enhancement of Win32. Since you can use MAXScript/pySide for the UI part, we won't need it. Still, it's useful to know how to deal with it. Aside from defining symbols used by the MFC framework, <code>afxres.h</code> <code>#include</code>s <code>winres.h</code> that's needed by the Visual C++ generated .rc files. So, let's skip the MFC-specific parts and put back only what's needed. Go ahead and find and replace <code>afxres.h</code> with <code>winres.h</code> and save and close the <code>.rc</code> file.</p>
<p>Now you should be able to double-click the .rc file, and navigating to the dialog inside the treeview that opens and double-clicking it should open in the designer.</p>
<div class="separator" style="clear: both; text-align: center;"><img height="auto" width="500"
src=https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuqlWZffr9i4exi8d3pbU96ujyN4e-tJMKQGc0H2kYNg-MYuNmOBclVD0B4yqbKRTpTw4d7zspRjA-k4HP_h60MsKC38UKdZB_CZYe5ZgTIERKG0O3_gz4N9zCdOZe_QHghRIiu72U5Z0/s1600/rc_dialog.png" /></div>
<p>It could be useful as a starting point when you're making regular utility plugin that shows up in the utility panel but since all I care about now is publishing functions, I can delete that without regrets – one regret maybe: if you do that through the UI, it will insert an empty language block for your language. You can safely delete that when you reopen the file with source code editor:</p>
<div class="separator" style="clear: both; text-align: center;"><img height="auto" width="500"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixS07WYQdJEZmthbony4CC-byPHhhpc3k64EtPFYQiNQI47ywN3LMquXWItg_uByBrK71m7VcvW8aD82N185mGtboHBoF1-RpcwllY0lYh2icy_NpU-BcNHoe3mXIlpRIbpHiBJEkrfWg/s1600/lang_block.png" /></div>
<p>While you're inside the <code>.rc</code> file, if you want to start with the Core Interface (and I recommend that, or rather I recommend you try both) don't forget to replace the string that corresponds to the IDS_CLASS_NAME, too. I'll put there <code>"MXSExposureUtil"</code> once more (if you can think of a reason to make the className and the MAXScript alias different, feel free to pick another one):</p>
<div class="separator" style="clear: both; text-align: center;"><img height="auto" width="auto"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2DnYEEdr01pZfu-m10FtqKpZEBIN7DdON9HULFREZOVLDGHTc7Q466kte10y9NMIq7RcJ3iVdeB9g9Hbj-jpKw38xQP_eGTvaFEvvQmGYIF6dAH6j3tu7W9nld-LQj3QSoN6zdavfczc/s1600/classname.png" /></div>
<p><br>And since we have no use for localization, let's turn off the <code>.mui</code> file postbuild event, too. Right-click the project name, choose <i>Properties</i> and navigate to <i>Configuration Properties</i> > <i>Build Events > Post-Build Event</i>:</p>
<div class="separator" style="clear: both; text-align: center;"><img height="auto" width="500"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUduyB_qdkZMyyE7GaDo39rU7l0sw3Jpb-VCrjCRdfg0X7wejeXc7iERRBVn97wYmKUbnuSezYfCx-VIfwdf7c2yAbuu-tJetC2cPxwo1gUti1rF6t9oJSxkNmhmqd6d-LenAPe4igpTs/s1600/postbuild_mui.png" /></div>
<p>You can make the change apply only to the current configuration (Hybrid) or to All Configurations.</p>
<div style="font-size: 10pt; font-weight: bold; padding-bottom: 6px;" id="build">First Build</div>
<p></p>
<p>There's one last thing to get off the table before building the project. The default output location for the compiled plugin is the <i>Plugins</i> folder. While this sounds straightforward, it may trip you up at first. Since you'll want to be able to write into that folder, you have to <a href="https://www.howtogeek.com/301768/how-to-take-ownership-of-files-and-folders-in-windows/">take ownership</a> of it. Another option is to add an entry in <code>plugin.ini</code> that points to a directory you have access to, and change the build properties accordingly.<p>
<p>The modern alternative is to use the <a href="https://help.autodesk.com/view/3DSMAX/2020/ENU/?guid=__developer_writing_plug_ins_packaging_plugins_html">Autodesk Application Plug-in Package</a> (you can find the standards plugins using it in the <code>ApplicationPlugins</code> folder in the 3ds Max root directory). This is something you should be aware of and make use of it once you're more comfortable with the whole development process, once you want to start distributing your plugins. For now, let's keep it simple and stick with the wizard defaults.</p>
<p>With this part done, you should be able to Build the plugin, <i>Build</i> > <i>Build Solution</i>. If all permissions for all the folders are set correctly, the build should succeed and you can run Max the way you're used to or from VS via <i>Debug</i> > <i>Start Without Debugging</i>.</p>
<p>By default, if you <i>Start</i> this way and the project has been changed in the meantime, it will be rebuilt (that way if you want to build and run, all you need to do is press <code>Ctrl+F5</code>) - if you don't like that, you can change it under <i>Tools</i> > <i>Options</i> > <i>Projects and Solutions</i> > <i>Build and Run</i>, in the first dropdown (by default <i>Always build</i>). When you open the MAXScript Listener, you should be able to query the utility <code>category</code> and <code>class</code>:</p>
<div class="separator" style="clear: both; text-align: center;"><img height="auto" width="500"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiItAbKrCIZHWpZJ5eMGbnUnUKT_F8B1x-2J8EdiKBXZmVWvnoUpf3ZGFdUr86rIaD6QIQufjQXPbZGCTzQBYN_MEn-1ObuzBva3cqdwnhvUxIgEJXKv_uh5XftyqCozbSpb3PxU7UnC1Y/s1600/empty_utility.png" /></div>
<p><br>If you're using version control, now is the time for the celebratory clean-slate commit!</p>
<p>If you change anything in the project and try to rebuild now while max is running, the build will fail because the plugin is loaded in max. You can avoid having to kill it manually by adding a Pre-Build Event through <i>Configuration Properties</i> > <i>Build Events</i>:</p>
<div class="separator" style="clear: both; text-align: center;"><img height="auto" width="500"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwTj1HkhHlX56P4GJ-vzktSvr9KtrOtUpucbS4P1TRSryh3sWS8YquSC6gp58cz3niAezCknZFRp001yLgkNUNMwjVte7bwsP2QygijArwW45RszaREOf_0MpCajhCGf6VYU0lQ6Q0agc/s1600/prebuild_event.png" /></div>
<pre class="notranslate">WMIC PROCESS WHERE (Name='3dsmax.exe' and ExecutablePath LIKE '%25%252020%25%25') call TERMINATE</pre>
<p>The <code>%25%252020%25%25</code> part actually evaluates to <code>%%2020%%</code> and in batch mode this translates yet again to <code>%2020%</code> – which is what you'd use when at command prompt. It's there to kill only those 3dsmax.exe processes that have 2020 in their path; you can match simply against <code>(Name='3dsmax.exe')</code> if you don't want to discriminate.</p>
<br><div style="font-size: 10pt; font-weight: bold; padding-bottom: 6px;" id="core_interface">Core Interface</div>
<p></p>
<p>If you followed all the steps, the plugin should load and be accessible by MAXScript at this point. All that remains is to make it do something as well. For that let's add a new class to the project, Right-click the project name in the <i>Solution Explorer</i> and pick <i>Add</i> > <i>Class...</i> For the class name, I tend to prefix the plugin class name with <code>'I'</code> for Interface (since it will be eventually exposed as one of the <a href="http://help.autodesk.com/view/3DSMAX/2020/ENU/?guid=GUID-240CBB0C-EF58-4A82-9C0F-A59200F58A19">Core Interfaces</a>). Fill in only the two fields framed by the blue rectangle, the class name of your choice and <code>FPInterfaceDesc</code> that the class will inherit from, leave the rest at their default (or autocompleted) values.</p>
<div class="separator" style="clear: both; text-align: center;"><img height="auto" width="500"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh08Djrbm9XkFRcNqixMHi3P1zFfm6hdma27QbiRrDu3UqISC1ENX2HyhcyBtPAT0AUx37SGm5X5FxAVmnrX3h5MDwl88EkNcDE8lhlwfZ_p6WBJ-JcmwyiGQQ652sukuUI9o8h4K_2uLg/s1600/add_class.png" /></div>
<p>This is what the class <code>.cpp</code> file might look like, depending on your current VS configuration and version:</p>
<pre class="notranslate" style="font-family:Consolas;font-size:13px;color:gainsboro;background:#1e1e1e;"><span style="color:#9b9b9b;">#include</span> <span style="color:#d69d85;">"IMXSExposure.h"</span>
<span style="color:#4ec9b0;">IMXSExposure</span><span style="color:#b4b4b4;">::</span><span style="color:#c8c8c8;">IMXSExposure</span><span style="color:#b4b4b4;">()</span> <span style="color:#b4b4b4;">{ }</span>
<span style="color:#4ec9b0;">IMXSExposure</span><span style="color:#b4b4b4;">::</span><span style="color:#c8c8c8;">~</span><span style="color:#c8c8c8;">IMXSExposure</span><span style="color:#b4b4b4;">()</span> <span style="color:#b4b4b4;">{ }</span>
</pre>
<p>Or it might be an empty file with just the <code>#include "YourClassName.h"</code> on the first line in which case you don't need to do anything with it. If there's a constructor and a destructor of the class like here, I want you to delete everything but the first line. The only thing we care about now is that the first line <code>#include</code>s the matching class header file.</p>
<p>What the header files actually are, and how you should structure your code around them, is a topic for another discussion (with lots of strong opinions along the way, even more so now that <a href="https://medium.com/@dmitrygz/brief-article-on-c-modules-f58287a6c64">modules</a> are almost here). Let's just say that you can usually think of them as sort of contract saying 'these are the prototypes of the data structures and functions I'll be using, they'll be implemented in a <code>cpp</code> source file that <code>#include</code>s this header somewhere along the way'. You can (and will) <a href="https://docs.microsoft.com/en-us/cpp/preprocessor/hash-include-directive-c-cpp?view=vs-2019"><code>#include</code></a> header files in other headers, and since this can nest pretty deep, there's a handy way to prevent duplicate <code>#include</code>s with a directive which Visual Studio will automatically insert into each new header file for you, <code>#pragma once</code> (you'll also often see <a href="https://gcc.gnu.org/onlinedocs/cpp/Once-Only-Headers.html">guard macros</a> in older files from before this was supported).</p>
<p>In the case of the SDK headers found in the <code>maxsdk\include</code> folder, this means that you can include them in your code and work as if your project were part of the max project. There's more to it, especially when it comes to actually building the project – we'll get to that later.</p>
<p>Keep in mind that while you'll find other max header files in the <code>maxsdk\samples</code> folder, you should only treat them as such, as samples to further your understanding of how things are done max-side. Everything outside the <code>include</code> and <code>lib</code> folders is subject to change, so if you included any of those header files, your plugin may break after a point update.</p>
<p>The wizard puts header files and source files in separate directories when it creates the project (and when you add a new class). You don't have to abide to that, some people prefer flat structure instead. In fact, your entire project structure could be just the <code>DllEntry.cpp</code> (or – by convention – <code>main.cpp</code> if you were building an executable), it just wouldn't be all that practical.</p>
<p>The contents of the initial header file might look similar to this:</p>
<pre class="notranslate" style="font-family:Consolas;font-size:13px;color:gainsboro;background:#1e1e1e;"><span style="color:#9b9b9b;">#pragma</span> <span style="color:#9b9b9b;">once</span>
<span style="color:#9b9b9b;">#include</span> <span style="color:#d69d85;">"C:\maxsdk20\include\ifnpub.h"</span>
<span style="color:#569cd6;">class</span> <span style="color:#4ec9b0;">IMXSExposure</span> <span style="color:#b4b4b4;">:</span>
<span style="color:#569cd6;">public</span> <span style="color:#4ec9b0;">FPInterfaceDesc</span>
<span style="color:#b4b4b4;">{</span>
<span style="color:#569cd6;">public</span><span style="color:#b4b4b4;">:</span>
<span style="color:#c8c8c8;">IMXSExposure</span><span style="color:#b4b4b4;">();</span>
<span style="color:#c8c8c8;">~</span><span style="color:#c8c8c8;">IMXSExposure</span><span style="color:#b4b4b4;">();</span>
<span style="color:#b4b4b4;">};</span>
</pre>
<p>You can see VS was clever enough to find the file to include based on the class we inherit from. Still, I prefer to replace it with a shorter and more descriptive <code><ifnpub.h></code>. The 'shorter' part is rather obvious (it's in the include path so no problems with discovery here), as for 'descriptive', I'm talking about the angle brackets here that indicate it's a non-local header file.</p>
<p>We don't need the explicit destructor for our use case either, there's no mess we'd be leaving behind. And since we've already removed it from the <code>.cpp</code> file before, that's one error going away. To get rid of the other one, we'll inline the constructor (this is just to make things simpler for us, though, it won't be a small and nice method where it'd make sense from an optimization point of view). If there's no constructor added in your file, write a new one – do note that you want it to come after the <code>public</code> access specifier. Add one if it's not there – by default if it wasn't specified, it would be private for C++ classes.</p>
<p>Finally, I'll add the base class constructor explicitly. It should now look something like (don't miss the final empty pair of curly braces):</p>
<pre class="notranslate" style="font-family:Consolas;font-size:13px;color:gainsboro;background:#1e1e1e;"><span style="color:#9b9b9b;">#pragma</span> <span style="color:#9b9b9b;">once</span>
<span style="color:#9b9b9b;">#include</span> <span style="color:#d69d85;"><ifnpub.h></span>
<span style="color:#569cd6;">class</span> <span style="color:#4ec9b0;">IMXSExposure</span> <span style="color:#b4b4b4;">:</span> <span style="color:#569cd6;">public</span> <span style="color:#4ec9b0;">FPInterfaceDesc</span>
<span style="color:#b4b4b4;">{</span>
<span style="color:#569cd6;">public</span><span style="color:#b4b4b4;">:</span>
<span style="color:#c8c8c8;">IMXSExposure</span><span style="color:#b4b4b4;">()</span> <span style="color:#b4b4b4;">:</span> <span style="color:#4ec9b0;">FPInterfaceDesc</span><span style="color:#b4b4b4;">()</span> <span style="color:#b4b4b4;">{</span> <span style="color:#b4b4b4;">};</span>
<span style="color:#b4b4b4;">};</span></pre>
<p>Since including a bare header #include like this will again trigger the Code Analysis, the warnings are back again. But now we want to disable them only for the SDK includes and restore them right after that so that our code gets checked. To do this, let's create a pair of macros that explain the intent. Right-click the <i>Header Files</i> folder, <i>Add</i> > <i>New Item...</i> and pick <i>Header file (.h)</i>. The first one will be called <i>warnings_disabled.h</i>; delete the <code>#pragma once</code> directive – we want this to be always inserted – and paste this instead:</p>
<pre class="notranslate" style="font-family:Consolas;font-size:13px;color:gainsboro;background:#1e1e1e;"><span style="color:#9b9b9b;">#include</span> <span style="color:#d69d85;"><codeanalysis\warnings.h></span>
<a href="https://www.viva64.com/en/b/0391/#ID0EBEMM"><span style="color:#9b9b9b;">#pragma</span> <span style="color:#9b9b9b;">warning</span> <span style="color:#b4b4b4;">(</span><span style="color:#9b9b9b;">push</span><span style="color:#b4b4b4;">)</span></a>
<span style="color:#9b9b9b;">#pragma</span> <span style="color:#9b9b9b;">warning</span> <span style="color:#b4b4b4;">(</span><span style="color:#9b9b9b;">disable</span> <span style="color:#b4b4b4;">:</span> <span style="color:#bd63c5;">ALL_CODE_ANALYSIS_WARNINGS</span><span style="color:#b4b4b4;">)</span></pre>
<p>For the other new file, <i>warnings_restored.h</i>, the entire contents of the file will be (again without the <code>#pragma once</code>):</p>
<pre class="notranslate" style="font-family:Consolas;font-size:13px;color:gainsboro;background:#1e1e1e;"><span style="color:#9b9b9b;">#pragma</span> <span style="color:#9b9b9b;">warning</span> <span style="color:#dbe4e8;">(</span><span style="color:#9b9b9b;">pop</span><span style="color:#dbe4e8;">)</span>
</pre>
<p>After wrapping the SDK #includes with these two headers, the file looks like this:</p>
<pre class="notranslate" style="font-family:Consolas;font-size:13px;color:gainsboro;background:#1e1e1e;">
<span style="color:#9b9b9b;">#pragma</span> <span style="color:#9b9b9b;">once</span>
<span style="color:#9b9b9b;">#include</span> <span style="color:#d69d85;">"warnings_disabled.h"</span>
<span style="color:#9b9b9b;">#include</span> <span style="color:#d69d85;"><ifnpub.h></span>
<span style="color:#9b9b9b;">#include</span> <span style="color:#d69d85;">"warnings_restored.h"</span>
<span style="color:#569cd6;">class</span> <span style="color:#4ec9b0;">IMXSExposure</span> <span style="color:#b4b4b4;">:</span> <span style="color:#569cd6;">public</span> <span style="color:#4ec9b0;">FPInterfaceDesc</span>
<span style="color:#b4b4b4;">{</span>
<span style="color:#569cd6;">public</span><span style="color:#b4b4b4;">:</span>
<span style="color:#c8c8c8;">IMXSExposure</span><span style="color:#b4b4b4;">()</span> <span style="color:#b4b4b4;">:</span> <span style="color:#4ec9b0;">FPInterfaceDesc</span><span style="color:#b4b4b4;">()</span> <span style="color:#b4b4b4;">{</span> <span style="color:#b4b4b4;">};</span>
<span style="color:#b4b4b4;">};</span></pre>
<p>Is there a better way? That depends, there are <a href="https://devblogs.microsoft.com/cppblog/broken-warnings-theory/
">experimental command line switches</a> to set the warning level for external headers (you can set it to zero to eliminate them) that you can add to project properties, <i>C\C++</i> > <i>Command Line</i> > <i>Additional Options</i>. For example:</p>
<pre class="notranslate">
/experimental:external /external:anglebrackets /external:W0
</pre>
<p>But since that's compiler-level, it won't rid you of the cascade of Intellisense warnings in the Error List. As far as I know, there's nothing like this for the built-in analyzer –
though it may be supported in the future, once the option gets out of experimental. </p>
<div style="font-size: 10pt; font-weight: bold; padding-bottom: 6px;" id="core_instance">Core Interface Instance</div>
<p></p>
<p>Try to build and run to confirm you didn't miss any step. Functionally, nothing changes on the Max side, since we still haven't registered our interface – it doesn't even have a name. That's the next step (unchanged code in gray):</p>
<pre class="notranslate" style="font-family: Consolas; font-size: 13px; color: gray; background: #1e1e1e;">#pragma once
#include "warnings_disabled.h"
#include <ifnpub.h>
#include "warnings_restored.h"
<span style="color: #569cd6;">extern</span> <span style="color: #569cd6;">const</span> <span style="color: #4ec9b0;">Interface_ID</span> <span style="color: #c8c8c8;">MXSEXPOSURE_INTERFACE_ID</span><span style="color: #b4b4b4;">;</span> <span style="color: #408080;">// not specified here, just made available for callers</span>
class IMXSExposure : public FPInterfaceDesc
{
public:
IMXSExposure() :
FPInterfaceDesc(
<span style="color: #c8c8c8;">MXSEXPOSURE_INTERFACE_ID</span><span style="color: #b4b4b4;">,</span> <span style="color: #bd63c5;">_M</span><span style="color: #b4b4b4;">(</span><span style="color: #d69d85;">"MXSExposure"</span><span style="color: #b4b4b4;">),</span> <span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">nullptr</span><span style="color: #b4b4b4;">,</span> <span style="color: #bd63c5;">FP_CORE</span>
<span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">p_end</span>) { };
};</pre>
<p>To register it, you need several things. Here are all the parameters explained:
<ul>
<li>a unique interface ID represented by the <code><span style="color: white;">MXSEXPOSURE_INTERFACE_ID</span></code> placeholder</li>
<li>a name for the interface which will be different from the <a href="#class_name">exposed plugin className</a>; here I'm using <code><span style="color: #bd63c5;">_M</span><span style="color: #b4b4b4;">(</span><span style="color: #d69d85;">"MXSExposure"</span><span style="color: #b4b4b4;">)</span></code> – the <code><span style="color: #bd63c5;">_M</span></code> macro is used to make the string conform with how Unicode is handled now in Max</li>
<li>the <span style="color: #b5cea8;">zero</span> stands for <i>'no ID to lookup in the .rc stringtable'</i>; if nonzero, it would be a localizable description which we don't provide here</li>
<li>the <code><span style="color: #569cd6;">nullptr</span></code> stands in place of a pointer to ClassDesc2, which isn't needed for Core Interfaces</li>
<li><code><span style="color: #bd63c5;">FP_CORE</span></code> is a flag that describes the type of the interface – <code>Core</code> for interface that can be called directly, which is perfect for general purpose methods</li>
<li>the <code><span style="color: #b8d7a3;">p_end</span></code> marks the end of the parameters passed to the base class constructor.</li></ul></p>
<p>Let's examine the other new line. The <code><span style="color: #569cd6;">const</span> <span style="color: #4ec9b0;">Interface_ID</span></code> bit indicates this is a value that won't change (you will often see <code>#define</code> used for that purpose in older code), and the <code><span style="color: #569cd6;">extern</span></code> keyword makes the compiler look elsewhere for the actual definition. Where macros would have been used before, you'll now often see <code>const</code> or <code>contexpr</code>, and although there are certain differences, I follow the rule to make them express the intent behind using one or the other. I.e. <code>extern static const</code> in header file for something that you want to make available but don't need to know the actual value of, and <code>constexpr</code> for something you initialize on the spot with a meaningful value that gives you some information (say number of ticks in a second).</p>
<p>If you build now, you still won't see anything new when in max – for that, it's necessary to assign the ID and create an instance of the <code>IMXSExposure</code> class first. Let's switch to the <code>.cpp</code> file and do just that:</p>
<pre class="notranslate" style="font-family: Consolas; font-size: 13px; color: gray; background: #1e1e1e;">#include "IMXSExposure.h"
<span style="color: #569cd6;">const</span> <span style="color: #4ec9b0;">Interface_ID</span> <span style="color: #c8c8c8;">MXSEXPOSURE_INTERFACE_ID</span><span style="color: #b4b4b4;">(</span><span style="color: #b5cea8;">0x445ddd85</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">0x24dd2aa1</span><span style="color: #b4b4b4;">);</span>
<span style="color: #569cd6;">static</span> <span style="color: #4ec9b0;">IMXSExposure</span> <span style="color: #c8c8c8;">interfaceSingleton</span><span style="color: #b4b4b4;">;</span></pre>
<p>The empty interface should then be successfully registered when you run the built solution:</p>
<div class="separator" style="clear: both; text-align: center;"><img height="auto" width="550"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9VrIKIC9xaymG49yK4UliB7u6Mfy676jUy_S81_uAITiN36PmApjRsgc4lSwUFT393ys5bHh7L1-yUEXi7zQqX4vpomDfIHnXU6Di0on1aQ9r0Az1esGF2R6D5rpLRE9fkXK9s0L8vjM/s1600/interface_empty.png" /></div>
<p>Since you will get warnings here (if you are using the C++ Core Guidelines checker) that you can't act on, let me digress a bit and mention another way to suppress them – and that's the <code>suppress</code> warning specifier that applies to the following line only:</p>
<pre class="notranslate" style="font-family: Consolas; font-size: 13px; color: gray; background: #1e1e1e;">#include "IMXSExposure.h"
<span style="color: #9b9b9b;">#pragma</span> <span style="color: #9b9b9b;">warning</span><span style="color: #b4b4b4;">(</span><span style="color: #c2c2c2;">suppress</span><span style="color: #b4b4b4;">:</span> <span style="color: #b5cea8;">26426</span><span style="color: #b4b4b4;">)</span> <span style="color:#408080;"><i>// non-constexpr constructor</i></span>
const Interface_ID MXSEXPOSURE_INTERFACE_ID(0x445ddd85, 0x24dd2aa1);
<span style="color: #9b9b9b;">#pragma</span> <span style="color: #9b9b9b;">warning</span><span style="color: #b4b4b4;">(</span><span style="color: #c2c2c2;">suppress</span><span style="color: #b4b4b4;">:</span> <span style="color: #b5cea8;">26426</span><span style="color: #b4b4b4;">)</span> <span style="color:#408080;"><i>// non-constexpr constructor</i></span>
static IMXSExposure interfaceSingleton;</pre>
<p>Done this way, it serves to document that we are aware of the warning and have knowingly chosen to suppress it for this particular line of the code.</p>
<br><div style="font-size: 10pt; font-weight: bold; padding-bottom: 6px;" id="methods">Interface Methods</div>
<p></p>
<p>As with the folder structure, there are no strict rules or generally accepted guidelines when it comes to code style and naming conventions either (and the same goes for <a href="https://isocpp.org/wiki/faq/style-and-techniques#whitespace">whitespace</a>). I stick to naming public methods and member variables with an initial capital letter (<code>HasMapChannel</code>), private member variables and helper functions not declared in header files with an initial lowercase letter (<code>bendAroundX</code>), and macros and constants (used the way <code>#define</code> would be used before) with all-caps snake case (<code>MXSEXPOSURE_INTERFACE_ID</code>).</p>
<p>To prepare for adding the methods, you need to provide an enumeration of identifiers for each function, as well as an implementation of the <a href="https://help.autodesk.com/cloudhelp/2020/ENU/Max-Developer-Help/files/cpp_ref/class_f_p_interface.html#aaf2447544c9cf17a08581868a3a4b62c"><code>_dispatch_fn</code></a> memeber function that works behind the scenes to unbundle the parameters from the indirect call parameter structure, forward them to the correct implementation method, and bundle the return value into an <code>FPValue</code> – which is fortunately handled for us if we use the <a href="https://help.autodesk.com/cloudhelp/2020/ENU/Max-Developer-Help/files/cpp_ref/ifnpub_8h.html#a14d66d18eedfb7ce2fb5c399bddae3f0"><code>FUNCTION_MAP</code></a> macros:</p>
<pre class="notranslate" style="font-family: Consolas; font-size: 13px; color: gray; background: #1e1e1e;">#pragma once
#include "warnings_disabled.h"
#include <ifnpub.h>
#include "warnings_restored.h"
extern const Interface_ID MXSEXPOSURE_INTERFACE_ID; <i>// not specified here, just made available for callers</i>
class IMXSExposure : public FPInterfaceDesc
{
public:
<span style="color: #569cd6;">enum</span> <span style="color: #4ec9b0;">functionID</span> <span style="color: #b4b4b4;">:</span> <span style="color: #4ec9b0;">FunctionID</span> <span style="color: #b4b4b4;">{</span> <span style="color: #b4b4b4;">};</span>
IMXSExposure() :
FPInterfaceDesc(
MXSEXPOSURE_INTERFACE_ID, _M("MXSExposure"), 0, nullptr, FP_CORE
, p_end) { };
<span style="color: #bd63c5;">BEGIN_FUNCTION_MAP</span>
<span style="color: #bd63c5;">END_FUNCTION_MAP</span>
};</pre>
<p>To demonstrate, I'm going to make a <i>UV Seam Select</i> modifier. For that I need to be able to select some edges first. To do that, it's enough to set the proper selection level of the mesh you get inside a <code>simpleMeshMod</code>. Since the function will directly modify the mesh and won't have anything to return, the return type is <code>void</code>, and the parameters are the <code>Mesh</code> pointer and the desired selection level. The resulting method will not modify the interface class in any way so it can also be declared as a <code>const</code> method (you will see it used in the SDK samples and headers, and it helps being aware of the meaning behind it):
<pre class="notranslate"><span style="color: #569cd6;">void</span> <span style="color: #c8c8c8;">SetMeshSelLevel</span><span style="color: #b4b4b4;">(</span><span style="color: #4ec9b0;">Mesh</span><span style="color: #b4b4b4;">*</span> <span style="color: #7f7f7f;">mesh</span><span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">int</span> <span style="color: #7f7f7f;">level</span><span style="color: #b4b4b4;">)</span> <span style="color: #569cd6;">const</span><span style="color: #b4b4b4;">;</span></pre>
<p>Within the function map block, we'll utilize a <code>VFN_2</code> macro for <a id="void_function"><code>V</code>oid <code>F</code>u<code>N</code>ction</a> with <code>2</code> parameters, and give it an ID (which refers to the <code>functionID</code> enum), the function name itself, and the types of its two arguments.</p>
<pre class="notranslate"><span style="color: #bd63c5;">VFN_2</span><span style="color: #b4b4b4;">(</span><span style="color: #b8d7a3;">setMeshSelLevel_id</span><span style="color: #b4b4b4;">,</span> <span style="color: #c8c8c8;">SetMeshSelLevel</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_MESH</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_INT</span><span style="color: #b4b4b4;">)</span></pre>
<p>Don't forget to add the <code>setMeshSelLevel_id</code> to the <code>functionID</code> enum.</p>
<p>Finally, inside the constructor body we need to call the <a id="append_function" href="https://help.autodesk.com/cloudhelp/2020/ENU/Max-Developer-Help/files/cpp_ref/class_f_p_interface_desc.html#a555b87fd7c416169ab427bf5936fa303"><code>AppendFunction</code></a> method, and provide it with:
<ul>
<li>the function ID</li>
<li>the name that you want to use when calling the function</li>
<li><code>zero</code> to indicate there's no descriptor string resource ID</li>
<li>the return type of the function</li>
<li>flags – we'll get to those later, for now the default empty flag (zero) will suffice</li>
<li>the number of parameters that will follow.</li>
</ul>
Although all that <i>could</i> have been included in the <code>FPInterfaceDesc</code> constructor, splitting it into separate function calls makes it easier to edit and less prone to errors, albeit more verbose:</p>
<pre class="notranslate"><span style="color: #b8d7a3;">setMeshSelLevel_id</span><span style="color: #b4b4b4;">,</span> <span style="color: #bd63c5;">_M</span><span style="color: #b4b4b4;">(</span><span style="color: #d69d85;">"SetMeshSelLevel"</span><span style="color: #b4b4b4;">),</span> <span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_VOID</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">2</span></pre>
<p>After that follow the parameters. Each parameter lists a name, resource string (<code>zero</code> again) and its type:</p>
<pre class="notranslate"> <span style="color: #b4b4b4;">,</span> <span style="color: #bd63c5;">_M</span><span style="color: #b4b4b4;">(</span><span style="color: #d69d85;">"mesh"</span><span style="color: #b4b4b4;">),</span> <span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_MESH</span>
<span style="color: #b4b4b4;">,</span> <span style="color: #bd63c5;">_M</span><span style="color: #b4b4b4;">(</span><span style="color: #d69d85;">"level"</span><span style="color: #b4b4b4;">),</span> <span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_INT</span></pre>
<p>You may notice I didn't put the comma at the end of the previous line and instead begin each line of parameters with one – it's a convention that makes it simpler to add/remove parameters without having to take care of the leftover trailing commas. You can find more <a href="https://pvs-studio.com/en/blog/posts/cpp/0391/#IDB861DE2A39:~:text=That%27s%20why%20I%20would%20again%20recommend%20formatting%20the%20table%20in%20the%20following%20way%3A">arguments in favor of that style</a>, but ultimately it's up to you to choose what suits you best.</p>
<p>Ultimately, the argument list always ends with the <code><span style="color: #b8d7a3;">p_end</span></code> tag. This is mandatory as it marks the end of variable arguments.</p>
<p>Putting it all together:</p>
<pre class="notranslate" style="font-family: Consolas; font-size: 13px; color: gray; background: #1e1e1e;">#pragma once
#include "warnings_disabled.h"
#include <ifnpub.h>
#include "warnings_restored.h"
extern const Interface_ID MXSEXPOSURE_INTERFACE_ID; <i>// not specified here, just made available for callers</i>
class IMXSExposure : public FPInterfaceDesc
{
public:
enum functionID : FunctionID {
<span style="color: #b8d7a3;">setMeshSelLevel_id</span><span style="color: #b4b4b4;">,</span>
};
IMXSExposure() :
FPInterfaceDesc(
MXSEXPOSURE_INTERFACE_ID, _M("MXSExposure"), 0, nullptr, FP_CORE
, p_end) {
<span style="color: #c8c8c8;">AppendFunction</span><span style="color: #b4b4b4;">(</span>
<span style="color: #b8d7a3;">setMeshSelLevel_id</span><span style="color: #b4b4b4;">,</span> <span style="color: #bd63c5;">_M</span><span style="color: #b4b4b4;">(</span><span style="color: #d69d85;">"SetMeshSelLevel"</span><span style="color: #b4b4b4;">),</span> <span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_VOID</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">2</span>
<span style="color: #b4b4b4;">,</span> <span style="color: #bd63c5;">_M</span><span style="color: #b4b4b4;">(</span><span style="color: #d69d85;">"mesh"</span><span style="color: #b4b4b4;">),</span> <span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_MESH</span>
<span style="color: #b4b4b4;">,</span> <span style="color: #bd63c5;">_M</span><span style="color: #b4b4b4;">(</span><span style="color: #d69d85;">"level"</span><span style="color: #b4b4b4;">),</span> <span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_INT</span>
<span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">p_end</span><span style="color: #b4b4b4;">);</span>
};
BEGIN_FUNCTION_MAP
<span style="color: #bd63c5;">VFN_2</span><span style="color: #b4b4b4;">(</span><span style="color: #b8d7a3;">setMeshSelLevel_id</span><span style="color: #b4b4b4;">,</span> <span style="color: #c8c8c8;">SetMeshSelLevel</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_MESH</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_INT</span><span style="color: #b4b4b4;">)</span>
END_FUNCTION_MAP
<span style="color: #569cd6;">void</span> <span style="color: #c8c8c8;">SetMeshSelLevel</span><span style="color: #b4b4b4;">(</span><span style="color: #4ec9b0;">Mesh</span><span style="color: #b4b4b4;">*</span> <span style="color: #7f7f7f;">mesh</span><span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">int</span> <span style="color: #7f7f7f;">level</span><span style="color: #b4b4b4;">)</span> <span style="color: #569cd6;">const</span><span style="color: #b4b4b4;">;</span>
<span style="color: #b4b4b4;">};</span></pre>
<p>And because I'm a lazy guy, I also put in two convenience macros to save me from copy-pasting and editing everything by hand anytime I rename a function. It's not perfect, the identifier inside the enum won't be autorenamed, but the other ones will and for me that's enough to justify that:</p>
<pre class="notranslate" style="font-family: Consolas; font-size: 13px; color: gray; background: #1e1e1e;">#pragma once
#include "warnings_disabled.h"
#include <ifnpub.h>
#include "warnings_restored.h"
<span style="color: #c2c2c2;">#define</span> <span style="color: #bd63c5;">FUNC_STR</span><span style="color: #b4b4b4;">(</span><span style="color: gainsboro;">func</span><span style="color: #b4b4b4;">)</span> <span style="color: #bd63c5;">_M</span><span style="color: #b4b4b4;">(#</span><span style="color: gainsboro;">func</span><span style="color: #b4b4b4;">)</span> <span style="color: #408080;"><i>// stringifies the passed variable</i></span>
<span style="color: #c2c2c2;">#define</span> <span style="color: #bd63c5;">FUNC_ID</span><span style="color: #b4b4b4;">(</span><span style="color: gainsboro;">func</span><span style="color: #b4b4b4;">)</span> <span style="color: gainsboro;">func</span><span style="color: #b4b4b4;">##</span><span style="color: gainsboro;">_id</span> <span style="color: #408080;"><i>// concatenates the variable name with _id</i></span>
extern const Interface_ID MXSEXPOSURE_INTERFACE_ID; <i>// not specified here, just made available for callers</i>
class IMXSExposure : public FPInterfaceDesc
{
public:
enum functionID : FunctionID {
<span style="color: #bd63c5;">FUNC_ID</span><span style="color: #b4b4b4;">(</span><span style="color: #c8c8c8;">SetMeshSelLevel</span><span style="color: #b4b4b4;">),</span>
};
IMXSExposure() :
FPInterfaceDesc(
MXSEXPOSURE_INTERFACE_ID, _M("MXSExposure"), 0, nullptr, FP_CORE
, p_end) {
AppendFunction(
<span style="color: #bd63c5;">FUNC_ID</span><span style="color: #b4b4b4;">(</span><span style="color: #c8c8c8;">SetMeshSelLevel</span><span style="color: #b4b4b4;">)</span>, <span style="color: #bd63c5;">FUNC_STR</span><span style="color: #b4b4b4;">(</span><span style="color: #c8c8c8;">SetMeshSelLevel</span><span style="color: #b4b4b4;">)</span>, 0, TYPE_VOID, 0, 2
, _M("mesh"), 0, TYPE_MESH
, _M("level"), 0, TYPE_INT
, p_end);
};
BEGIN_FUNCTION_MAP
VFN_2(<span style="color: #bd63c5;">FUNC_ID</span><span style="color: #b4b4b4;">(</span><span style="color: #c8c8c8;">SetMeshSelLevel</span><span style="color: #b4b4b4;">)</span>, SetMeshSelLevel, TYPE_MESH, TYPE_INT)
END_FUNCTION_MAP
void SetMeshSelLevel(Mesh* mesh, int level) const;
};
</pre>
<p>Now is the time to add the function definition. As you might expect, you can do it via <i>Quick Actions</i> (or <code>Alt-Enter</code> if you're on the line of the method declaration) > <i>Create Definition of 'SetMeshSelLevel' in matching .cpp</i>. If you want to do that by hand to get a feel for it, copy-paste the declaration into your <code>cpp</code> file, prepend <code>ClassName::</code> to the method name and you add a body instead of the semicolon. I've also taken the liberty of adding a check if the pointer we get is valid (you can compare it to nullptr instead, both ways are idiomatic):</p>
<pre class="notranslate" style="font-family: Consolas; font-size: 13px; color: gray; background: #1e1e1e;">#include "IMXSExposure.h"
#pragma warning(suppress: 26426) <i>// non-constexpr constructor</i>
const Interface_ID MXSEXPOSURE_INTERFACE_ID(0x445ddd85, 0x24dd2aa1);
#pragma warning(suppress: 26426) <i>// non-constexpr constructor</i>
static IMXSExposure interfaceSingleton;
<span style="color: #569cd6;">void</span> <span style="color: #4ec9b0;">IMXSExposure</span><span style="color: #b4b4b4;">::</span><span style="color: #c8c8c8;">SetMeshSelLevel</span><span style="color: #b4b4b4;">(</span><span style="color: #4ec9b0;">Mesh</span><span style="color: #b4b4b4;">*</span> <span style="color: #7f7f7f;">mesh</span><span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">int</span> <span style="color: #7f7f7f;">level</span><span style="color: #b4b4b4;">)</span> <span style="color: #569cd6;">const</span> <span style="color: #b4b4b4;">{</span>
<span style="color: #569cd6;">if</span> <span style="color: #b4b4b4;">(!</span><span style="color: #7f7f7f;">mesh</span><span style="color: #b4b4b4;">)</span> <span style="color: #569cd6;">return</span><span style="color: #b4b4b4;">;</span>
<span style="color: #b4b4b4;">}</span></pre>
<p>However, if you now start writing code expecting to get autocomplete suggestions for the mesh methods, you are in for some bad news – you'll only get a <i>pointer to incomplete class type is not allowed</i> error. Reason behind that is that there's no <code>#include</code> that'd provide the necessary info. How do you find the right one? In this case, Visual Studio comes to the rescue again - you can see that the <code>Mesh</code> type is properly highlighted and when you hover over it and press <code>CTRL</code>, wait for it to turn into a hyperlink and click it, you'll be redirected to the right header file - in this case <code>mesh.h</code>. Let's <code>#include</code> it, within the guarding disable/restore <code>include</code>s pair to prevent warning creep.</p>
<p>With that done, we should be able to leverage the help of the autocomplete to find the desired <code>selLevel</code> property and with it make the method actually do something:</p>
<pre class="notranslate" style="font-family: Consolas; font-size: 13px; color: gray; background: #1e1e1e;">
<span style="color:#c2c2c2;">#include</span> <span style="color:#d69d85;">"warnings_disabled.h"</span>
<span style="color: #c2c2c2;">#include</span> <span style="color: #d69d85;"><mesh.h></span>
<span style="color:#c2c2c2;">#include</span> <span style="color:#d69d85;">"warnings_restored.h"</span>
#include "IMXSExposure.h"
#pragma warning(suppress: 26426) <i>// non-constexpr constructor</i>
const Interface_ID MXSEXPOSURE_INTERFACE_ID(0x445ddd85, 0x24dd2aa1);
#pragma warning(suppress: 26426) <i>// non-constexpr constructor</i>
static IMXSExposure interfaceSingleton;
void IMXSExposure::SetMeshSelLevel(Mesh* mesh, int level) const {
<span style="color: #569cd6;">if</span> <span style="color: #b4b4b4;">(</span><span style="color: #c2c2c2;">mesh</span><span style="color: #b4b4b4;">)</span> <span style="color: #c2c2c2;">mesh</span><span style="color: #b4b4b4;">-></span><span style="color: #dadada;">selLevel</span> <span style="color: #b4b4b4;">=</span> <span style="color: #c2c2c2;">level</span><span style="color: #b4b4b4;">;</span>
}</pre>
<p>As an(other) aside, if you've never been exposed to pointers before, it's time to get familiar with them (otherwise you can <a href="#first_method">skip ahead</a>). There's a great <a href="https://www.ida.liu.se/opendsa/Books/TDIU20S19/html/index.html">Introduction to Pointers for C++</a> that should help you understand the basics. Don't despair if you don't get them right away, what you need to get started pretty much boils down to this:</p>
<li style="margin-left:3%; line-height:1.6;">when passing arguments to a function, if it's not a pointer or a reference, an independent copy will be made (don't let arrays fool you, they're pointers in 'disguise'):</li>
<pre class="notranslate" style="font-family:Consolas;font-size:13px;color:gainsboro;background:#1e1e1e;"><span style="color:#569cd6;">int</span> <span style="color:#b4b4b4;">*</span><span style="color:#c8c8c8;">ints</span> <span style="color:#b4b4b4;">=</span> <span style="color:#569cd6;">new</span> <span style="color:#569cd6;">int</span><span style="color:paleturquoise;">[</span><span style="color:#b5cea8;">5</span><span style="color:paleturquoise;">]</span><span style="color:#b4b4b4;">;</span> <span style="font-style:italic;color:#408080;">// dynamically allocates memory for 5 integers</span>
</pre>
<li style="margin-left:3%; line-height:1.6;">if you have a pointer variable (like <code>Mesh* mesh here</code>), use the <a href="https://www.quora.com/What-does-mean-in-C-C++-programming">arrow operator</a> in the same way you would use the dot operator:</li>
<pre class="notranslate" style="font-family:Consolas;font-size:13px;color:gainsboro;background:#1e1e1e;"><span style="color:#569cd6;">auto</span> <span style="color:#c8c8c8;">objectState</span> <span style="color:#b4b4b4;">=</span> <span style="color:#7f7f7f;">node</span><span style="color:#b4b4b4;">-></span><span style="color:#c8c8c8;">EvalWorldState</span><span style="color:paleturquoise;">(</span><span style="color:#dadada;">ip</span><span style="color:#b4b4b4;">-></span><span style="color:#c8c8c8;">GetTime</span><span style="color:powderblue;">()</span><span style="color:#b4b4b4;">,</span> <span style="color:#569cd6;">true</span><span style="color:paleturquoise;">)</span><span style="color:#b4b4b4;">;</span> <span style="font-style:italic;color:#408080;">// node and ip are pointers</span>
</pre>
<li style="margin-left:3%; line-height:1.6;">prefer to instantiate objects with automatic storage duration (so that the destructor – if public – is automatically called when the object goes out of scope):</li>
<pre class="notranslate" style="font-family:Consolas;font-size:13px;color:gainsboro;background:#1e1e1e;"><span style="color:#4ec9b0;">MNMesh</span> <span style="color:#c8c8c8;">poly</span><span style="color:paleturquoise;">(</span><span style="color:#b4b4b4;">*</span><span style="color:#7f7f7f;">mesh</span><span style="color:paleturquoise;">)</span><span style="color:#b4b4b4;">;</span> <span style="font-style:italic;color:#408080;">// local variable that you better not return as a pointer, intialized with a dereferenced pointer</span>
<span style="color:#c8c8c8;">poly</span><span style="color:#b4b4b4;">.</span><span style="color:#c8c8c8;">MakePolyMesh</span><span style="color:paleturquoise;">(</span><span style="color:#b5cea8;">0</span><span style="color:#b4b4b4;">,</span> <span style="color:#569cd6;">false</span><span style="color:paleturquoise;">)</span><span style="color:#b4b4b4;">;</span> <span style="font-style:italic;color:#408080;">// using the dot operator</span></pre>
<li style="margin-left:3%; line-height:1.6;">in the context of returning a pointer to MAXScript (as a new object to be taken care of by the MAXScript garbage collector in the future), don't hesitate to use <code>new</code>:</li>
<pre class="notranslate" style="font-family:Consolas;font-size:13px;color:gainsboro;background:#1e1e1e;"><span style="color:#569cd6;">auto</span> <span style="color:#c8c8c8;">newMesh</span> <span style="color:#b4b4b4;">=</span> <span style="color:#569cd6;">new</span> <span style="color:#4ec9b0;">Mesh</span><span style="color:paleturquoise;">(</span><span style="color:#b4b4b4;">*</span><span style="color:#7f7f7f;">mesh</span><span style="color:paleturquoise;">)</span><span style="color:#b4b4b4;">;</span> <span style="font-style:italic;color:#408080;">// make a copy from the mesh pointer</span>
...
<span style="color:#569cd6;">return</span> <span style="color:#c8c8c8;">newMesh</span><span style="color:#b4b4b4;">;</span></pre>
<li style="margin-left:3%; line-height:1.6;"><code>&</code> and <code>*</code> are inverse to each other (unless either of them is overloaded); if <code>p</code> is a pointer <code>&*p</code> is that same pointer again. This is best presented in a table form, as taken from the <a href="http://www.cplusplus.com/doc/tutorial/classes/">cplusplus.com tutorial on classes</a>:</li>
<br><table style="width:90%; margin-left:4%; margin-right:6%;">
<tr><th style="padding:4px;">expression</th><th style="padding:4px;">can be read as</th></tr>
<tr><td style="padding:4px;"><code>*x</code></td><td style="padding:4px;">pointed to by <code>x</code></td></tr>
<tr><td style="padding:4px;"><code>&x</code></td><td style="padding:4px;">address of <code>x</code></td></tr>
<tr><td style="padding:4px;"><code>x.y</code></td><td style="padding:4px;">member <code>y</code> of object <code>x</code></td></tr>
<tr><td style="padding:4px;"><code>x->y</code></td><td style="padding:4px;">member <code>y</code> of object pointed to by <code>x</code></td></tr>
<tr><td style="padding:4px;"><code>(*x).y</code></td><td style="padding:4px;">member <code>y</code> of object pointed to by <code>x</code> (equivalent to the previous one)</td></tr>
</table>
<li style="margin-left:3%; line-height:1.6;">if you want to express the possibility of passing no object, you may use pointers (and pass <code>nullptr</code> the same way you'd pass <code>undefined</code> in MAXScript), otherwise references are preferable (<code>const</code> ones for input-only parameters)</li>
<br><p>I'll try and show some common scenarios with two more example functions soon, which might be more helpful than just learning the theory of it. For now, let's return to the task at hand.</p>
<p>Rebuilding the project finally gets us somewhere:</p>
<div id="first_method" class="separator" style="clear: both; text-align: center;"><img height="auto" width="550"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxL7a8LLCgkrRA61UUeMdOe5V4nsFzN3i7t3yKWwwKUUr5sF3Kf6KhxY0sv3TXeumvv5bv1umLIlxQWQdnhJZdxxokw7oBAHjcLP01GbG_dkTDStrH2khGikZMJAmrFvgINAx3Spbgolo/s1600/interface_01.png" /></div>
<p>And just like that, we can now create our first SDK-enabled modifier using the function to do what we couldn't do with pure MAXScript before. For the time being, it will just select all edges and set the current stack subobject level to the edge mode:</p>
<pre class="notranslate">
<code><span class="code-keywords1">plugin</span> simpleMeshMod UVSeamSelect</code>
<code> name<span class="code-symbol">:</span><span class="code-string">"UV Seam Select"</span></code>
<code> classID<span class="code-symbol">:#(</span><span class="code-number">0x34c4905c</span><span class="code-symbol">,</span> <span class="code-number">0x106b1548</span><span class="code-symbol">)</span></code>
<code><span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">on</span> modifyMesh <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> setEdgeSelection <span class="code-keywords3">mesh</span> <span class="code-symbol">(</span><span class="code-identifier">mesh</span><span class="code-symbol">.</span><span class="code-identifier">edges </span><span class="code-keywords1">as</span> bitArray<span class="code-symbol">)</span></code>
<code> MXSExposure<span class="code-symbol">.</span><span class="code-identifier">SetMeshSelLevel</span> <span class="code-keywords3">mesh</span> <span class="code-number">8</span></code>
<code> <span class="code-symbol">)</span></code>
<code><span class="code-symbol">)</span></code>
</pre>
<div class="separator" style="clear: both; text-align: center;"><img height="auto" width="450"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4WXQ5TPAqHCQRG_vTRtCAzeW3G9vKkArA1OdJOOqTehqrEk0VnEUZ-KTTlRV8FO2PYU9n4fgsOQxBFWUkUsxYihs9HhYd96-LJepe86IqhvGfgR0h6_-HHjJeTB9JpmjAYq6Vz29XBfM/s1600/select_edges.png" /></div>
<br><p>As you've probably noticed, I'm using the magic number eight for edge mode – no worries, that's yet another thing that I will address later. Why eight? The Mesh selection level bit flag for edges level is <code>1<<3</code> (MAXscript equivalent would be <code>bit.shift 1 3</code>). Hard to tell why they're flags in the first place, maybe there used to be a plan to support multiple active subobject levels at the same time. Anyway, using hardcoded values like this is okay for quick and dirty testing, but if you can help it, it better not find its way into the production environment.</p>
<p>There are other things you may question, and question them you should as I wouldn't like to encourage cargo-cult programming here. For example, the only reason I put an asterisk next to the type instead of the variable name is that that way it's easier for me to tell at a quick glance that I'm using a pointer at all – I know it doesn't make a type, I never declare multiple pointers per line ever anyway, and the 'space from each side' variant throws me off every time. Depending on the style guide you follow, your code might look slightly different but the core concepts will carry over.</p>
<br><div style="font-size: 10pt; font-weight: bold; padding-bottom: 6px;" id="static_interface">Static Interface</div>
<p></p>
<p>With that accomplishment under our belts, let's go back to the theory for a while and see how Static Interfaces fit into the picture.</p>
<p>Fortunately, there are not that many differences between the two approaches to require a complete rewrite. We can easily convert our current project to use the Static Interface instead. The plugin name will revert back to <code>MXSExposure</code> without the <code>-Util</code> suffix, and the <code>IMXSExposure</code> class will become <code>IMeshTools</code>.</p>
<p>Underlined are the <code>InternalName</code> and <code>ClassName</code> of the utility plugin inside the <code>MXSExposure.cpp</code> which now need to reflect the desired name, and the <code>GetDesc</code> function which returns the pointer to the <code>ClassDesc</code> instance itself that we will need to get:</p>
<div class="separator" style="clear: both; text-align: center;"><img height="auto" width="550"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8ShbPok0PB9g7-ZPmNdUYViTQTvflNEZjcyhzGDqIpxjIFdwLz4d6eDRLoaFWYUMzY30GCeYqRA3Msv9Hh-2PlooSaLUcBO_9DAtef8T4rPjUp69Bzzn1IabZvh7moaaauGCcQ1uohNo/s1600/get_descriptor.png" /></div>
<p>That's the function we want to call; but if you go to the matching header file (<code>MXSExposure.h</code>), you'll find that it's not declared there - and even if it were, we wouldn't want to include this one because it turns off the Code Analysis warnings without saving the previous state beforehand. The thing is, we don't have to.</p>
<p>Let's make our own specialized header file (Header Files > Add > New Item...), I'll append <code>'Desc'</code> to the filename making it <code>MXSExposureDesc</code> in the context of my project. Copy the function signature and paste it into the empty header file and add a semicolon at the end (function declaration needs one, just like statements do). And if VS complains about not being able to recognize the <code>ClassDesc2</code> type, CTRL+click through the type from the function definition next to the original class to see it's declared in <code>iparamb2.h</code>, and #include that. This will work:</p>
<pre class="notranslate" style="font-family:Consolas;font-size:13px;color:gainsboro;background:#1e1e1e;"><span style="color:#9b9b9b;">#pragma</span> <span style="color:#9b9b9b;">once</span>
<span style="color:#9b9b9b;">#include</span> <span style="color:#d69d85;"><iparamb2.h></span>
<span style="color:#4ec9b0;">ClassDesc2</span><span style="color:#b4b4b4;">*</span> <span style="color:#c8c8c8;">GetMXSExposureDesc</span><span style="color:#b4b4b4;">();</span></pre>
<p>Those of you who are already familiar with the language may note that since the return type is a pointer, you might forward declare the <code>class ClassDesc2;</code> instead – well, yes and no, and above all – don't make it needlessly hard on your yourself. For one, if the header file in question would be <code>#include</code>d elsewhere within the same translation unit, it won't make a difference (assuming that it's guarded against multiple includes); this is true for the main class file but not our interface one. But what the FPInterfaceDesc constructor accepts isn't really a pointer to <code>ClassDesc2</code>, it's a pointer to <code>ClassDesc</code> from which it inherits. And even if it weren't, it's not significant enough to agonize over that. Either way, it may have shed some light on why you'll often see class declarations like this elsewhere.</p>
<p>With that settled, let's include this header into the file where the <code>GetDesc</code> function is defined. This way, we've exposed the function to anyone who now <code>#include</code>s this header.</p>
<div class="separator" style="clear: both; text-align: center;"><img height="auto" width="550"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyTzv-IRAH79cq9R8eFkvXKx0pEXIpBuQLwZCJDRS40Y1WoSQsxOFrlDeikKAyj660rjvc_9O9iz5uTAprUQi3Jc6udjSpFu4pXdbNongqYrEKW4s6VD2IjaXOMoN88j_KVxxuu_2s9Lo/s1600/header_desc.png" /></div>
<br><p>Now that you've done that, <code>#include</code> it into the <code>IMeshTools</code> class file. In place of the <code>nullptr</code>, use the pointer returned by the <code>GetDesc</code> function. The <code>FP_STATIC_METHODS</code> flag specifies that the interface can be called on the supplied <code>ClassDesc</code> itself, i.e. it doesn't need an instance of an object created by the <code>ClassDesc</code>. That's the GlobalUtilityPlugin that we gave the <code>'Util'</code> suffix when using Core Interface because we wouldn't be using it. Here it will group all the interfaces under one roof for us.</p>
<p>The edited <code>IMeshTools</code> file should now look roughly like this:</p>
<pre class="notranslate" style="font-family: Consolas; font-size: 13px; color: gray; background: #1e1e1e;">
#pragma once
#include "warnings_disabled.h"
#include <ifnpub.h>
#include "warnings_restored.h"
<span style="color: #c2c2c2;">#include</span> <span style="color: #d69d85;">"MXSExposureDesc.h"</span>
#define FUNC_STR(func) _M(#func) <i>// stringifies the passed variable</i>
#define FUNC_ID(func) func##_id <i>// concatenates the variable name with _id </i>
extern const Interface_ID <span style="color: #c8c8c8;">MESHTOOLS_INTERFACE_ID</span>
class <span style="color: #4ec9b0;">IMeshTools</span> : public FPInterfaceDesc
{
public:
enum functionId : FunctionID {
FUNC_ID(SetMeshSelLevel),
};
<span style="color: #c8c8c8;">IMeshTools</span><span style="color: #b4b4b4;">()</span> <span style="color: #b4b4b4;">:</span>
FPInterfaceDesc(
<span style="color: #c8c8c8;">MESHTOOLS_INTERFACE_ID</span><span style="color: #b4b4b4;">,</span> <span style="color: #bd63c5;">_M</span><span style="color: #b4b4b4;">(</span><span style="color: #d69d85;">"MeshTools"</span><span style="color: #b4b4b4;">),</span> 0<span style="color: #b4b4b4;">,</span> <span style="color: #c8c8c8;">GetMXSExposureDesc</span><span style="color: #b4b4b4;">(),</span> <span style="color: #bd63c5;">FP_STATIC_METHODS</span>
, p_end) {
AppendFunction(
FUNC_ID(SetMeshSelLevel), FUNC_STR(SetMeshSelLevel), 0, TYPE_VOID, 0, 2
, _M("mesh"), 0, TYPE_MESH
, _M("level"), 0, TYPE_INT
, p_end);
};
BEGIN_FUNCTION_MAP
VFN_2(FUNC_ID(SetMeshSelLevel), SetMeshSelLevel, TYPE_MESH, TYPE_INT)
END_FUNCTION_MAP
void SetMeshSelLevel(Mesh* mesh, int level) const;
};</pre>
<p>After you have built the project and run Max, you should be able to query and access it:</p>
<div class="separator" style="clear: both; text-align: center;"><img height="auto" width="550"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgknVTP56nbJdOdK1vR-N1INs2vqj3YhrjjNbEBKuv97_CeqBZeSq8NbXw_2ZmydNfcyChJR8pFs1HRdjkNE_k_soq9OECPKh6BQF_VDmpECBQ54Qu2F8BUD1P3FVqdXYAs3TakNgr_aVY/s1600/static_interface.png" /></div>
<br><p>It's up to you whether you want to keep adding the methods to the Static or Core interface version of the project. As you can see there's no difference other than the way how the interfaces are accessed. All of my code samples that will follow will use the Core interface.</p>
<br><div style="font-size: 10pt; font-weight: bold; padding-bottom: 6px;" id="methods2">Interface Methods Continued</div>
<p></p>
<p>The next method to make the <i>UV Seam Select</i> modifier work should give us the seam edges to work with. We could set the selection directly in the Mesh we receive and return <code>void</code> but to make things more interesting, let's return a BitArray that will hold the seam edge indices. Having a helper method that returns something we use in MAXScript would often make more sense and be more flexible. As for the parameters, we need to pass the actual Mesh, and of course the map channel we'd like to get the edges for:</p>
<pre class="notranslate">
<span style="color: #4ec9b0;">BitArray</span><span style="color: #b4b4b4;">*</span> <span style="color: #c8c8c8;">GetMeshMapSeams</span><span style="color: paleturquoise;">(</span><span style="color: #4ec9b0;">Mesh</span><span style="color: #b4b4b4;">*</span> <span style="color: #7f7f7f;">mesh</span><span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">int</span> <span style="color: #7f7f7f;">mapChannel</span><span style="color: paleturquoise;">)</span> <span style="color: #569cd6;">const</span><span style="color: #b4b4b4;">;</span>
</pre>
<p>For the function map, we'll use the <code>FN_2</code> macro since we're returning something now. And that's also the only difference from the <a href="#void_function"><code>VFN_2</code></a> macro used earlier – before the function itself comes the type of the return value, here that corresponds to <code>TYPE_BITARRAY</code>:</p>
<pre class="notranslate">
<span style="color: #bd63c5;">FN_2</span><span style="color: paleturquoise;">(</span><span style="color: #bd63c5;">FUNC_ID</span><span style="color: powderblue;">(</span><span style="color: #c8c8c8;">GetMeshMapSeams</span><span style="color: powderblue;">)</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_BITARRAY</span><span style="color: #b4b4b4;">,</span> <span style="color: #c8c8c8;">GetMeshMapSeams</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_MESH</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_INT</span><span style="color: paleturquoise;">)</span>
</pre>
<p>Within the AppendFunction call, the function description parameters on the first line follow the same pattern as with the <a href="#append_function">previous function</a>, with the exception of nonzero flafs this time. For the sake of illustration to show more features, I'm using the option to turn off automatic redraw here (the <code>FP_NO_REDRAW</code> flag):</p>
<pre class="notranslate">
<span style="color: #bd63c5;">FUNC_ID</span><span style="color: skyblue;">(</span><span style="color: #c8c8c8;">GetMeshMapSeams</span><span style="color: skyblue;">)</span><span style="color: #b4b4b4;">,</span> <span style="color: #bd63c5;">FUNC_STR</span><span style="color: skyblue;">(</span><span style="color: #c8c8c8;">GetMeshMapSeams</span><span style="color: skyblue;">)</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_BITARRAY</span><span style="color: #b4b4b4;">,</span> <span style="color: #bd63c5;">FP_NO_REDRAW</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">2</span>
</pre>
<p>The parameter names and types complete the picture here (as always, the <code><span style="color: #b8d7a3;">p_end</span></code> tag comes at the very end):</p>
<pre class="notranslate">
<span style="color: #b4b4b4;">,</span> <span style="color: #bd63c5;">_M</span><span style="color: skyblue;">(</span><span style="color: #d69d85;">"mesh"</span><span style="color: skyblue;">)</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_MESH</span>
<span style="color: #b4b4b4;">,</span> <span style="color: #bd63c5;">_M</span><span style="color: skyblue;">(</span><span style="color: #d69d85;">"mapChannel"</span><span style="color: skyblue;">)</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_INT</span>
<span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">p_end</span><span style="color: powderblue;">)</span><span style="color: #b4b4b4;">;</span>
</pre>
<p>And don't forget to add an ID to the <code>functionID</code> enum:</p>
<pre class="notranslate">
<span style="color: #bd63c5;">FUNC_ID</span><span style="color: powderblue;">(</span><span style="color: #c8c8c8;">GetMeshMapSeams</span><span style="color: powderblue;">)</span>
</pre>
<p>This is how it all looks in context of the header file:</p>
<pre class="notranslate" style="font-family: Consolas; font-size: 13px; color: gray; background: #1e1e1e;">#pragma once
#include "warnings_disabled.h"
#include <ifnpub.h>
#include "warnings_restored.h"
#define FUNC_STR(func) _M(#func) <i>// stringifies the passed variable</i>
#define FUNC_ID(func) func##_id <i>// concatenates the variable name with _id</i>
extern const Interface_ID MXSEXPOSURE_INTERFACE_ID; <i>// not specified here, just made available for callers</i>
class IMXSExposure : public FPInterfaceDesc
{
public:
enum functionID : FunctionID {
FUNC_ID(SetMeshSelLevel),
<span style="color: #bd63c5;">FUNC_ID</span><span style="color: powderblue;">(</span><span style="color: #c8c8c8;">GetMeshMapSeams</span><span style="color: powderblue;">)</span><span style="color: #b4b4b4;">,</span>
};
IMXSExposure() :
FPInterfaceDesc(
MXSEXPOSURE_INTERFACE_ID, _M("MXSExposure"), 0, nullptr, FP_CORE
, p_end) {
AppendFunction(
FUNC_ID(SetMeshSelLevel), FUNC_STR(SetMeshSelLevel), 0, TYPE_VOID, 0, 2
, _M("mesh"), 0, TYPE_MESH
, _M("level"), 0, TYPE_INT
, p_end);
<span style="color: #c8c8c8;">AppendFunction</span><span style="color: powderblue;">(</span>
<span style="color: #bd63c5;">FUNC_ID</span><span style="color: skyblue;">(</span><span style="color: #c8c8c8;">GetMeshMapSeams</span><span style="color: skyblue;">)</span><span style="color: #b4b4b4;">,</span> <span style="color: #bd63c5;">FUNC_STR</span><span style="color: skyblue;">(</span><span style="color: #c8c8c8;">GetMeshMapSeams</span><span style="color: skyblue;">)</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_BITARRAY</span><span style="color: #b4b4b4;">,</span> <span style="color: #bd63c5;">FP_NO_REDRAW</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">2</span>
<span style="color: #b4b4b4;">,</span> <span style="color: #bd63c5;">_M</span><span style="color: skyblue;">(</span><span style="color: #d69d85;">"mesh"</span><span style="color: skyblue;">)</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_MESH</span>
<span style="color: #b4b4b4;">,</span> <span style="color: #bd63c5;">_M</span><span style="color: skyblue;">(</span><span style="color: #d69d85;">"mapChannel"</span><span style="color: skyblue;">)</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_INT</span>
<span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">p_end</span><span style="color: powderblue;">)</span><span style="color: #b4b4b4;">;</span>
}
BEGIN_FUNCTION_MAP
VFN_2(FUNC_ID(SetMeshSelLevel), SetMeshSelLevel, TYPE_MESH, TYPE_INT)
<span style="color: #bd63c5;">FN_2</span><span style="color: paleturquoise;">(</span><span style="color: #bd63c5;">FUNC_ID</span><span style="color: powderblue;">(</span><span style="color: #c8c8c8;">GetMeshMapSeams</span><span style="color: powderblue;">)</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_BITARRAY</span><span style="color: #b4b4b4;">,</span> <span style="color: #c8c8c8;">GetMeshMapSeams</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_MESH</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_INT</span><span style="color: paleturquoise;">)</span>
END_FUNCTION_MAP
void SetMeshSelLevel(Mesh* mesh, int level) const;
<span style="color: #4ec9b0;">BitArray</span><span style="color: #b4b4b4;">*</span> <span style="color: #c8c8c8;">GetMeshMapSeams</span><span style="color: paleturquoise;">(</span><span style="color: #4ec9b0;">Mesh</span><span style="color: #b4b4b4;">*</span> <span style="color: #7f7f7f;">mesh</span><span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">int</span> <span style="color: #7f7f7f;">mapChannel</span><span style="color: paleturquoise;">)</span> <span style="color: #569cd6;">const</span><span style="color: #b4b4b4;">;</span>
};</pre>
<p>Once again, let's add the definition for the method. This is what the FixIts make super easy:</p>
<img height="auto" width="500" style="margin-left:2%;"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6o-wwbpm9dVISHA-Kr41D77KbutaJpJbHcYvF1aMfpP957i9F43bgmsuIG7G9jNKf2onK9bvntM3yvG97rJxLWIPeeenjdQNHshekmB9ZrTr-kBRmjuNEFd15Ar1XhaOnU_LnrVfqfhw/s1600/create_definition.gif" />
<p>If you're not a fan of the tiny workspace that pops up, you can promote the Peek View to document just as easily:</p>
<img height="auto" width="500" style="margin-left:2%;"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEio6E9VgKJkMm34jUP9KJntgCjR9yUGMVU62B3AD9EVvA3Y3Uk0sZgcVq5tiPSu_nVvAdGZVyUUk-e5E1wh7wdWDYeSheliVEgSc4Z67XgnEeg-2fRtQkgZSBIgToG3C0VCM81rrqVLygfjgsBGrwU1iE5gLqI668DC72gs97SASc5wRmSTZcRZrVlGeDQ/s1600/promote_to_document.gif"/>
<p>Implementing the function will be a bit more complex and educational this time:</p>
<pre class="notranslate" style="font-family: Consolas; font-size: 13px; color: gray; background: #1e1e1e;">#include "warnings_disabled.h"
#include <mesh.h>
<span style="color: #c2c2c2;">#include</span> <span style="color: #d69d85;"><mnmesh.h></span>
#include "warnings_restored.h"
#include "IMXSExposure.h"
#pragma warning(suppress: 26426) <i>// non-constexpr constructor</i>
const Interface_ID MXSEXPOSURE_INTERFACE_ID(0x445ddd85, 0x24dd2aa1);
#pragma warning(suppress: 26426) <i>// non-constexpr constructor</i>
static IMXSExposure interfaceSingleton;
void IMXSExposure::SetMeshSelLevel(Mesh* mesh, int level) const {
if (mesh) mesh->selLevel = level;
}
<span style="color: #4ec9b0;">BitArray</span><span style="color: #b4b4b4;">*</span> <span style="color: #4ec9b0;">IMXSExposure</span><span style="color: #b4b4b4;">::</span><span style="color: #c8c8c8;">GetMeshMapSeams</span><span style="color: #dbe4e8;">(</span><span style="color: #569cd6;">const</span> <span style="color: #4ec9b0;">Mesh</span><span style="color: #b4b4b4;">*</span> <span style="color: #7f7f7f;">mesh</span><span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">int</span> <span style="color: #7f7f7f;">mapChannel</span><span style="color: #dbe4e8;">)</span> <span style="color: #569cd6;">const</span> <span style="color: #dbe4e8;">{</span>
<span style="color: #569cd6;">if</span> <span style="color: paleturquoise;">(</span><span style="color: #b4b4b4;">!</span><span style="color: #7f7f7f;">mesh</span> <span style="color: #b4b4b4;">||</span> <span style="color: #b4b4b4;">!</span><span style="color: #7f7f7f;">mesh</span><span style="color: #b4b4b4;">-></span><span style="color: #c8c8c8;">mapSupport</span><span style="color: powderblue;">(</span><span style="color: #7f7f7f;">mapChannel</span><span style="color: powderblue;">)</span><span style="color: paleturquoise;">)</span>
<span style="color: #569cd6;">return</span> <span style="color: #569cd6;">nullptr</span><span style="color: #b4b4b4;">;</span> <span style="font-style: italic; color: #408080;">// translates to '</span><span style="color: #009c8c;">undefined</span><span style="font-style: italic; color: #408080;">' in MAXScript</span>
<span style="color: #4ec9b0;">MNMesh</span> <span style="color: #c8c8c8;">poly</span><span style="color: paleturquoise;">(</span><span style="color: #b4b4b4;">*</span><span style="color: #7f7f7f;">mesh</span><span style="color: paleturquoise;">)</span><span style="color: #b4b4b4;">;</span> <span style="font-style: italic; color: #408080;">// dereferencing the pointer</span>
<span style="color: #4ec9b0;">Mesh</span> <span style="color: #c8c8c8;">meshCopy</span><span style="color: paleturquoise;">(</span><span style="color: #b4b4b4;">*</span><span style="color: #7f7f7f;">mesh</span><span style="color: paleturquoise;">)</span><span style="color: #b4b4b4;">;</span>
<span style="color: #569cd6;">if</span> <span style="color: paleturquoise;">(</span><span style="color: #b4b4b4;">!</span><span style="color: #c8c8c8;">poly</span><span style="color: #b4b4b4;">.</span><span style="color: #dadada;">nume</span><span style="color: paleturquoise;">)</span>
<span style="color: #569cd6;">return</span> <span style="color: #569cd6;">nullptr</span><span style="color: #b4b4b4;">;</span> <span style="font-style: italic; color: #408080;">// without edges, there are no seams</span>
<span style="color: #c8c8c8;">poly</span><span style="color: #b4b4b4;">.</span><span style="color: #c8c8c8;">ClearEFlags</span><span style="color: paleturquoise;">(</span><span style="color: #bd63c5;">MN_SEL</span><span style="color: paleturquoise;">)</span><span style="color: #b4b4b4;">;</span>
<span style="color: #c8c8c8;">poly</span><span style="color: #b4b4b4;">.</span><span style="color: #c8c8c8;">SetMapSeamFlags</span><span style="color: paleturquoise;">(</span><span style="color: #7f7f7f;">mapChannel</span><span style="color: paleturquoise;">)</span><span style="color: #b4b4b4;">;</span>
<span style="color: #c8c8c8;">poly</span><span style="color: #b4b4b4;">.</span><span style="color: #c8c8c8;">PropegateComponentFlags</span><span style="color: paleturquoise;">(</span><span style="color: #b8d7a3;">MNM_SL_EDGE</span><span style="color: #b4b4b4;">,</span> <span style="color: #bd63c5;">MN_SEL</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">MNM_SL_EDGE</span><span style="color: #b4b4b4;">,</span> <span style="color: #bd63c5;">MN_EDGE_MAP_SEAM</span><span style="color: paleturquoise;">)</span><span style="color: #b4b4b4;">;</span>
<span style="color: #c8c8c8;">poly</span><span style="color: #b4b4b4;">.</span><span style="color: #c8c8c8;">OutToTri</span><span style="color: paleturquoise;">(</span><span style="color: #c8c8c8;">meshCopy</span><span style="color: paleturquoise;">)</span><span style="color: #b4b4b4;">;</span>
<span style="color: #569cd6;">if</span> <span style="color: paleturquoise;">(</span><span style="color: #7f7f7f;">mesh</span><span style="color: #b4b4b4;">-></span><span style="color: #dadada;">numFaces</span> <span style="color: #b4b4b4;">!=</span> <span style="color: #c8c8c8;">meshCopy</span><span style="color: #b4b4b4;">.</span><span style="color: #dadada;">numFaces</span><span style="color: paleturquoise;">)</span>
<span style="color: #569cd6;">return</span> <span style="color: #569cd6;">nullptr</span><span style="color: #b4b4b4;">;</span> <span style="font-style: italic; color: #408080;">// topology changed when converting to poly</span>
<span style="color: #569cd6;">return</span> <span style="color: #569cd6;">new</span> <span style="color: #4ec9b0;">BitArray</span><span style="color: paleturquoise;">(</span><span style="color: #c8c8c8;">meshCopy</span><span style="color: #b4b4b4;">.</span><span style="color: #dadada;">edgeSel</span><span style="color: paleturquoise;">)</span><span style="color: #b4b4b4;">;</span>
<span style="color: #dbe4e8;">}</span></pre>
<p>You may have noticed the mesh argument now points to a <code>const Mesh</code>, because we're not modifying the mesh in any way, nor are we calling any of its methods that might be non-const. If we instead opted for setting the selection directly on the mesh, we'd have to drop the <code>const</code> keyword.</p>
<p>After the initial early-exit null check we also check if the <code>mapChannel</code> is supported, and if not return <code>undefined</code> (if the caller is MAXScript code). You could <a href="https://help.autodesk.com/view/3DSMAX/2020/ENU/?guid=__developer_3ds_max_sdk_features_function_publishing_exception_handling_html">throw an exception</a> with a descriptive message instead, if you prefer that.</p>
<p>Next, a new <code>MNMesh</code> is created from the <code>Mesh</code> pointer passed to the method. <code>MNMesh</code> is a winged-edge/polygonal mesh class (i.e. what Editable_Poly uses under the hood), and the constructor accepts a <code>Mesh</code> reference – since we have a pointer, we need to dereference it first. A copy of the original <code>Mesh</code> is created in a similar manner – both are local variables that will be automatically deallocated at the end of the enclosing code block. This also means that it wouldn't be a good idea to return their addresses or addresses of any of their members as they will be destroyed when the function returns.</p>
<p>If the number of poly edges is zero, it's time to return undefined again (or throw an exception). It's more descriptive to check against zero; I only chose to write it this way to demonstrate something you will see pretty often, too.</p>
<p>Normally you'd also call <code><a href="https://help.autodesk.com/cloudhelp/2020/ENU/Max-Developer-Help/files/cpp_ref/class_m_n_mesh.html#ac3e82c16a5597e3d01a4ec833e33ef09">MakePolyMesh</a></code> on the MNMesh created from triangular <code>Mesh</code>. Yes, you can still have triangle faces with invisible (yet selectable) edges in Editable poly as well - it used to be a longstanding issue of the Quadify Mesh modifier (you had to add Turn to Poly or convert to mesh, then to poly again to get rid of the invisible edges). Since we don't care about this and only want to query some edge flags, we can safely skip that step.</p>
<p>To protect against the possibility that some of the edges has already been selected, it's better to clear the selection flags. Once this is done, map seam flags for the <code>mapChannel</code> are set, and propagated to selection flags on the next line – selection will be kept during the conversion back to <code>Mesh</code> which is needed here because the indexing is different between the two. Now that we're done with the poly operations, we can output the updated <code>Mesh</code> to the <code>meshCopy</code> variable.</p>
<p>Another <code>if</code> test is there to make sure the updated <code>meshCopy</code> has the same number of edges as the mesh we want to apply the edge selection to in the end. The local <code>meshCopy</code> uses the dot operator directly, for the pointer variable we have to use the arrow operator (or dereference manually and then use the dot operator). For a Mesh, number of edges is always number of faces times three so the comparison will yield the same result for both.</p>
<p>At the end, a new <code>BitArray</code> is dynamically allocated and returned, copying the contents of the <code>meshCopy</code> edge selection. As you remember, <code>meshCopy</code> is local to the function body and will be destroyed once out of scope.</p>
<pre class="notranslate" style="font-family:Consolas;font-size:13px;color:gainsboro;background:#1e1e1e;"><span style="color:#408080;"><i>// can be returned by value (a copy is made, local is destroyed)</i></span>
<span style="color:#408080;"><i>// but that's not very efficient; and MXS expects a *pointer val</i></span>
<span style="color:#408080;"><i>// for most of reasonably complex types, primitive values are OK</i></span>
<span style="color:#408080;"><i>// if you returned &localVar address, it would point to garbage </i></span>
<span style="color:#4ec9b0;">BitArray</span> <span style="color:#c8c8c8;">localVar</span><span style="color:#b4b4b4;">(</span><span style="color:#c8c8c8;">size</span><span style="color:#b4b4b4;">);</span>
<span style="color:#408080;"><i>// can return straight to MAXScript, comes with responsibility</i></span>
<span style="color:#408080;"><i>// if method gives you pointer it may come with 'needDel' bool</i></span>
<span style="color:#408080;"><i>// if true, you are the one who is responsible for the cleanup</i></span>
<span style="color:#4ec9b0;">BitArray</span><span style="color:#b4b4b4;">*</span> <span style="color:#c8c8c8;">dynamicVar</span> <span style="color:#b4b4b4;">=</span> <span style="color:#569cd6;">new</span> <span style="color:#4ec9b0;">BitArray</span><span style="color:#b4b4b4;">(</span><span style="color:#c8c8c8;">size</span><span style="color:#b4b4b4;">);</span></pre>
<p>To clear up why checking if the face counts are the same was necessary in the first place, let me explain a few peculiarities that Mesh allows, which are impossible in poly and would get lost in translation. For example, the <code>Teapot</code> primitive is built with rows of face pairs that share an invisible edges to form a quad. Instead of having a special case to generate triangles on the lid top (and the bottom of the body), the 'quads' in the last row are made by one regular triangular face and one zero-area face defined by two vertices (and they still share invisible edges). The two-vert face has three edges like all the other faces, it's just that for one of the edges both its vertex indices point to the same vertex, the top one.</p>
<div class="separator" style="clear: both; text-align: center;"><img height="auto" width="500"
src=https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjY0LQy3GlQyylm6fK25F3C8Y6WwAKouzvBGgboO_ROvpMinSrFO_x9zNytHCcDi9nqgT7gUmuzkMdNfVxQ3dGBz-LUCiJGIBR-uESGZkaIlqsZpSoZAUYbWIH4yFJvwDJy9m9ko0_l_dg/s1600/teapot_faces.png" /></div>
<p>This is illegal in poly world so you'd get a random-looking result if you didn't check for this case and applied the renumbered edge selection. Null edges are not the only possible issue; for example poly edges can have at maximum two adjacent faces – you can't take an edge in the middle of a surface and shift-drag it to create new face, that only works if it's open edge. In meshes, two vertices can be shared among an unlimited number of faces.</p>
<p>The main reason I chose to go the poly route here – rather than with an uneventful and safe loop without loopholes – was to illustrate some roadblocks you might encounter along the way, which will become obvious once you try to build the project. And if I didn't mention <code>#includ</code>ing <code>mnmesh.h</code> this time around, it's because I trust you'll be able to work it out for yourself. Let's do that and try and see what happens when we build the project:</p>
<pre class="notranslate" style="font-family: Consolas; font-size: 13px; color: #ddd; background: #1e1e1e;">
1>IMXSExposure.obj : error LNK2019: unresolved external symbol "public: virtual __cdecl MNMesh::~MNMesh(void)" (??1MNMesh@@UEAA@XZ) referenced in function "public: class BitArray * __cdecl IMXSExposure::GetMeshMapSeams(class Mesh *,int)const " (?GetMeshMapSeams@IMXSExposure@@QEBAPEAVBitArray@@PEAVMesh@@H@Z)
1>IMXSExposure.obj : error LNK2019: unresolved external symbol "public: void __cdecl MNMesh::Init(void)" (?Init@MNMesh@@QEAAXXZ) referenced in function "public: __cdecl MNMesh::MNMesh(class Mesh const &)" (??0MNMesh@@QEAA@AEBVMesh@@@Z)
1>IMXSExposure.obj : error LNK2019: unresolved external symbol "public: void __cdecl MNMesh::Clear(void)" (?Clear@MNMesh@@QEAAXXZ) referenced in function "public: void __cdecl MNMesh::SetFromTri(class Mesh const &)" (?SetFromTri@MNMesh@@QEAAXAEBVMesh@@@Z)
1>IMXSExposure.obj : error LNK2019: unresolved external symbol "public: int __cdecl MNMesh::PropegateComponentFlags(int,unsigned long,int,unsigned long,bool,bool)" (?PropegateComponentFlags@MNMesh@@QEAAHHKHK_N0@Z) referenced in function "public: class BitArray * __cdecl IMXSExposure::GetMeshMapSeams(class Mesh *,int)const " (?GetMeshMapSeams@IMXSExposure@@QEBAPEAVBitArray@@PEAVMesh@@H@Z)
1>IMXSExposure.obj : error LNK2019: unresolved external symbol "public: void __cdecl MNMesh::AddTri(class Mesh const &)" (?AddTri@MNMesh@@QEAAXAEBVMesh@@@Z) referenced in function "public: void __cdecl MNMesh::SetFromTri(class Mesh const &)" (?SetFromTri@MNMesh@@QEAAXAEBVMesh@@@Z)
1>IMXSExposure.obj : error LNK2019: unresolved external symbol "public: void __cdecl MNMesh::OutToTri(class Mesh &)" (?OutToTri@MNMesh@@QEAAXAEAVMesh@@@Z) referenced in function "public: class BitArray * __cdecl IMXSExposure::GetMeshMapSeams(class Mesh *,int)const " (?GetMeshMapSeams@IMXSExposure@@QEBAPEAVBitArray@@PEAVMesh@@H@Z)
1>IMXSExposure.obj : error LNK2019: unresolved external symbol "public: void __cdecl MNMesh::FillInMesh(void)" (?FillInMesh@MNMesh@@QEAAXXZ) referenced in function "public: __cdecl MNMesh::MNMesh(class Mesh const &)" (??0MNMesh@@QEAA@AEBVMesh@@@Z)
1>IMXSExposure.obj : error LNK2019: unresolved external symbol "public: void __cdecl MNMesh::SetMapSeamFlags(int)" (?SetMapSeamFlags@MNMesh@@QEAAXH@Z) referenced in function "public: class BitArray * __cdecl IMXSExposure::GetMeshMapSeams(class Mesh *,int)const " (?GetMeshMapSeams@IMXSExposure@@QEBAPEAVBitArray@@PEAVMesh@@H@Z)
1>IMXSExposure.obj : error LNK2001: unresolved external symbol "public: virtual class BaseInterface * __cdecl MNMesh::GetInterface(class Interface_ID)" (?GetInterface@MNMesh@@UEAAPEAVBaseInterface@@VInterface_ID@@@Z)
1>MXSExposure.gup : fatal error LNK1120: 9 unresolved externals
</pre>
<p>Well, that was underwhelming. When you look up <a href="https://docs.microsoft.com/en-us/cpp/error-messages/tool-errors/linker-tools-error-lnk2019?view=vs-2019">LNK2019</a> in the build reference, the first possible cause listed is <i>'The object file or library that contains the definition of the symbol is not linked'</i>. This is what the <code>.lib</code> files from the <code>maxsdk\lib\</code> folder are for, and the basic set is already pre-filled by the wizard when you first set up the project.</p>
<p>There are several ways to find out which one is missing; I'll use the good old command prompt. For the command to work, you must either specify the full path to <code>dumpbin</code> executable or add the <code><a href="https://docs.microsoft.com/en-us/cpp/build/reference/dumpbin-reference?view=vs-2019">dumpbin.exe</a></code> path to the <code>PATH</code> environment variable. To find it, go to the <code>Microsoft Visual Studio</code> folder in <code>Program Files (x86)</code> and search for <code>dumpbin.exe</code>; either one should work, I used the path to the <code>HostX64\x64 one</code>.</p>
<p>Once you have taken care of that, open Windows Explorer and navigate to the <code>lib\x64\Release</code> folder in the maxsdk directory. Paste the following line into the address bar:
<pre class="notranslate">
cmd /S /K "for %i in (*.lib) do @dumpbin /exports "%i" | findstr /i "SetMapSeamFlags" > nul && echo %i"
</pre>
<img height="auto" width="505" style="margin-left:2%;"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9aEt2nKtmWBzCKtFZygAsFp2QksPGkbz_FYlfiMNCW9sxC-FRZH7cOp4-w75_ys9kKrzFLvVKHFlahx_iXfBDY5cZqqDqlceweoUi8kONBhB5nVAdOiyQH63Kd7BsdBjdMZSCZFJPLsRxFgyyRvSWKRzSWIli8f0vtAV0QDE39a-fjz_1b5JnM-SzM8E/s1600/maxSDK_lib_folder.png" />
<p>When you hit enter, it opens the command line prompt and executes the command after the <code>/k</code> switch, which in turn calls <code>dumpbin</code> to list all exported definitions for each of the <code>.lib</code> files, and the result is filtered by <code><a href="https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/findstr">findstr</a></code> matching against <code>'SetMapSeamFlags'</code> (that's the method we wanted to use, and one of the unresolved symbols listed in the build Output) while <code>/i</code>gnoring case. The <code>findstr</code> output is dropped by being redirected to <code>nul</code>, and if the findstr succeeds, the name of the <code>.lib</code> file is printed to the command prompt window using <code>echo</code>:</p>
<img height="auto" width="540" style="margin-left:0;"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi24rq0UsZwo9aOm_TPjBxdX9wzMfAkpaV0b_VwhHQSiNd5VLD4PzaCoBAX_-WjvhBc19oVxFGXea4ZM1qZtB6KB8irYjiMLb_tHe4WHCF20L36b1BmU6yKKcej8sQdX1UN805NfOYe25aYMQpjqVZvtP6R0jpTOCMmEjjLRF2WRpd8aJ5Y6cMNjYl7rsw/s1600/MNMath_found.png" />
<p>If you want to make sure you got the right file that contains the right methods, you can check the filtered dumpbin output for the <code>.lib</code> file that matches the query:</p>
<img height="auto" width="540" style="margin-left:0;"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-kKNf5ecv2XHVy0yU_cLv4xax14YG8Ef9D2ytWt3HRWtP1fWBSO8fxsvM7kYDFfhi5PfGtyeTyX8qT4wqL_rCPz1C8hWYsjYDJp0Y234itFGBI9ZT9h8wJxzbc53mvCFom9vMIUjKzH57QBVO_I_EcVbAg_BqYYfwAwLgMTWQLG4GkG9ZnKxcPDhgsxU/s1600/MNMath_dumpbin.png" />
<br><p>So with that sorted, you can now edit the project properties, navigate to <i>Linker</i> > <i>Input</i> > <i>Additional Dependencies</i> and add the lib file (in our case <code>MNMath.lib</code>) to the list – either by directly clicking on the line and editing it or by selecting <i>Edit...</i> from the dropdown menu. The project should now build successfully.</p>
<p>That means that right after testing and confirming that it works, we should be able to use it in our modifier:</p>
<pre class="notranslate">
<code><span class="code-keywords1">plugin</span> simpleMeshMod UVSeamSelect</code>
<code> name<span class="code-symbol">:</span><span class="code-string">"UV Seam Select"</span></code>
<code> classID<span class="code-symbol">:#(</span><span class="code-number">0x34c4905c</span><span class="code-symbol">,</span> <span class="code-number">0x106b1548</span><span class="code-symbol">)</span></code>
<code><span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">parameters</span> main <span class="code-keywords1">rollout</span><span class="code-symbol">:</span><span class="code-identifier">params</span></code>
<code> <span class="code-symbol">(</span></code>
<code> mapChannel type<span class="code-symbol">:</span><span class="code-string">#integer</span> <span class="code-identifier">ui</span><span class="code-symbol">:</span><span class="code-identifier">spnMapChannel default</span><span class="code-symbol">:</span><span class="code-number">1</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords1">rollout</span> params <span class="code-string">"Parameters"</span></code>
<code> <span class="code-symbol">(</span></code>
<code> spinner spnMapChannel <span class="code-string">"Map Channel:"</span> type<span class="code-symbol">:#</span><span class="code-identifier">integer range</span><span class="code-symbol">:[</span><span class="code-number">1</span><span class="code-symbol">,</span><span class="code-number">99</span><span class="code-symbol">,</span><span class="code-number">1</span><span class="code-symbol">]</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords1">on</span> modifyMesh <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> channelEdges <span class="code-symbol">=</span> MXSExposure<span class="code-symbol">.</span><span class="code-identifier">GetMeshMapSeams</span> <span class="code-keywords3">mesh</span> mapChannel</code>
<code> <span class="code-keywords1">if</span> channelEdges <span class="code-symbol">!=</span> <span class="code-keywords2">undefined</span> <span class="code-keywords1">do</span> setEdgeSelection <span class="code-keywords3">mesh</span> channelEdges</code>
<code> MXSExposure<span class="code-symbol">.</span><span class="code-identifier">SetMeshSelLevel mesh </span><span class="code-number">8</span></code>
<code> <span class="code-symbol">)</span></code>
<code><span class="code-symbol">)</span></code>
</pre>
<p>Indeed, the selection is set and passed up the stack, so you can use it for example to extrude the map seam edges:</p>
<div class="separator" style="clear: both; text-align: center;"><img height="auto" width="505"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgicNR7p71fMkJL5mwo5AFyv0t1LUpWCdEoaUi6jWMYb5QeBD3ndMz3nflN5lT2YZ02Sk_OV7ZGMWS0d0ZaPiuKHmtnl5xXNX0qz97xTLBcoaxc6CCJYWaNaDCNeGsuMa0IwGMDqGkISUI/s1600/seam_extrude.gif" /></div>
<br><div style="font-size: 10pt; font-weight: bold; padding-bottom: 6px;" id="the_core">THE Core Interface</div>
<p></p>
<p>These were both rather straightforward functions, but sometimes you need additional input not given by the user. An example would be getting the current time for time-dependent functions. As usual, there are many ways to go about that, and I will start with the more universal one to illustrate the concept of using <code>COREInterface</code> methods.</p>
<p><code>GetCOREInterface()</code>/<code>UtilGetCOREInterface()</code> (and their subsequent numbered variants added in later max versions) give you access to the interface for calling <a href="https://help.autodesk.com/view/3DSMAX/2020/ENU/?guid=__cpp_ref_class_interface_html">various useful methods</a>.As such, it's useful enough that you'll see the <code>'ip'</code> variable scattered throughout the SDK sample files.</p>
<p>Since you'd probably use it repeatedly, you could use a static variable inside the function, but it's highly likely that more functions would use it – having the <code>ip</code> accessible as a private class member certainly sounds handy:</p>
<pre class="notranslate" style="font-family: Consolas; font-size: 13px; color: gray; background: #1e1e1e; height: 400px;">#pragma once
#include "warnings_disabled.h"
#include <ifnpub.h>
<span style="color: #c2c2c2;">#include</span> <span style="color: #d69d85;"><systemutilities.h></span>
#include "warnings_restored.h"
#define FUNC_STR(func) _M(#func) <em>// stringifies the passed variable</em>
#define FUNC_ID(func) func##_id <em>// concatenates the variable name with _id </em>
extern const Interface_ID MXSEXPOSURE_INTERFACE_ID; <em>// not specified here, just made available for callers</em>
class IMXSExposure : public FPInterfaceDesc
{
<span style="color: #4ec9b0;">Interface</span><span style="color: #b4b4b4;">*</span> <span style="color: #dadada;">ip</span> <span style="color: #b4b4b4;">=</span> <span style="color: #c8c8c8;">UtilGetCOREInterface</span><span style="color: #b4b4b4;">();</span>
public:
enum functionId : FunctionID {
FUNC_ID(SetMeshSelLevel),
FUNC_ID(GetMeshMapSeams),
};
IMXSExposure() :
FPInterfaceDesc(
MXSEXPOSURE_INTERFACE_ID, _M("MXSExposure"), 0, nullptr, FP_CORE + FP_STATIC_METHODS
, p_end) {
AppendFunction(
FUNC_ID(SetMeshSelLevel), FUNC_STR(SetMeshSelLevel), 0, TYPE_VOID, 0, 2
, _M("mesh"), 0, TYPE_MESH
, _M("level"), 0, TYPE_INT
, p_end);
AppendFunction(FUNC_ID(GetMeshMapSeams), FUNC_STR(GetMeshMapSeams), 0, TYPE_BITARRAY, FP_NO_REDRAW, 2
, _M("mesh"), 0, TYPE_MESH
, _M("mapChannel"), 0, TYPE_INT
, p_end);
};
BEGIN_FUNCTION_MAP
VFN_2(FUNC_ID(SetMeshSelLevel), SetMeshSelLevel, TYPE_MESH, TYPE_INT)
FN_2(FUNC_ID(GetMeshMapSeams), TYPE_BITARRAY, GetMeshMapSeams, TYPE_MESH, TYPE_INT)
END_FUNCTION_MAP
void SetMeshSelLevel(Mesh* mesh, int level) const;
BitArray* GetMeshMapSeams(const Mesh * mesh, int mapChannel) const;
};
</pre>
<p>First, the question of the <code>#include</code> and which one to choose – totally up to you. I went with this one because I also use <code>mesh.h</code> which <code>#include</code>s <code>utillib.h</code> where <code>systemutilities.h</code> is <code>#include</code>d, too – but in the future, I may need to process scene nodes and will add <code>inode.h</code> which uses <code>GetCOREInterface.h</code>, and the point would be moot... It's good to be aware that the choice is there, but nothing bad will happen whether you choose one or the other. Second, as you can see I'm initializing the variable right as I declare it – while this wasn't possible before, since C++11 you can initialize member variables in-class like this – no reason to shy away from that, especially if it makes your code easier to read.</p>
<p>Without further ado, let's add a method that needs this interface – and in our example, this is going to be a simple ripple deform with a wave shift over time:</p>
<pre class="notranslate" style="font-family:Consolas; font-size:13px; color:gray; background:#1e1e1e;">
<span style="color: #569cd6;">void</span> <span style="color: #c8c8c8;">RippleMeshDeform</span><span style="color: #b4b4b4;">(</span><span style="color: #4ec9b0;">Mesh</span><span style="color: #b4b4b4;">*</span> <span style="color: #7f7f7f;">mesh</span><span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">const</span> <span style="color: #4ec9b0;">Point3</span><span style="color: #b4b4b4;">&</span> <span style="color: #7f7f7f;">center</span><span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">float</span> <span style="color: #7f7f7f;">speed</span><span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">float</span> <span style="color: #7f7f7f;">frequency</span><span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">float</span> <span style="color: #7f7f7f;">amplitude</span><span style="color: #b4b4b4;">);</span>
</pre>
<p>As you can see from its signature, it doesn't return anything, it operates on the given mesh and in addition to that and a few numeric variables to control wave frequency, amplitude and shift speed, it expects a <code>Point3</code> value by reference (<code>const</code> meaning we promise not to change it so function calls are forbidden, property access allowed). Now, my motivation behind this choice was first and foremost illustrative but the fact is that using it this way is not unheard of (point in case being several Edit Poly modifier methods). If you decide to use by-reference parameters, you have to also pick a matching type for the function map macro:</p>
<pre class="notranslate" style="font-family:Consolas; font-size:13px; color:gray; background:#1e1e1e;">
<span style="color: #bd63c5;">VFN_5</span><span style="color: #b4b4b4;">(</span><span style="color: #bd63c5;">FUNC_ID</span><span style="color: #b4b4b4;">(</span><span style="color: #c8c8c8;">RippleMeshDeform</span><span style="color: #b4b4b4;">),</span> <span style="color: #c8c8c8;">RippleMeshDeform</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_MESH</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_POINT3_BR</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_FLOAT</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_FLOAT</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_FLOAT</span><span style="color: #b4b4b4;">)</span>
</pre>
<p>The <code>_BR</code> suffix in <code>TYPE_POINT3_BR</code> denotes pass-by-reference. There are others like _BV and _BP (by value and by pointer), _TAB for collections of the types, and combinations of the two. Refer to the <a href="https://help.autodesk.com/view/3DSMAX/2020/ENU/?guid=__developer_3ds_max_sdk_features_function_publishing_supported_types_html">Supported Types</a> and <a href="https://help.autodesk.com/view/3DSMAX/2020/ENU/?guid=__developer_3ds_max_sdk_features_function_publishing_symbolic_enumerations_added_base_types_html">Added Base Types</a> chapters for more.</p>
<p>The rest of the code follows the same pattern as before:</p>
<pre class="notranslate" style="font-family:Consolas; font-size:13px; color:gray; background:#1e1e1e; height:400px;">
#pragma once
#include "warnings_disabled.h"
#include <ifnpub.h>
#include <systemutilities.h>
#include "warnings_restored.h"
#define FUNC_STR(func) _M(#func) <em>// stringifies the passed variable</em>
#define FUNC_ID(func) func##_id <em>// concatenates the variable name with _id </em>
extern const Interface_ID MXSEXPOSURE_INTERFACE_ID; <em>// not specified here, just made available for callers</em>
class IMXSExposure : public FPInterfaceDesc
{
Interface* ip = UtilGetCOREInterface();
public:
enum functionId : FunctionID {
FUNC_ID(SetMeshSelLevel),
FUNC_ID(GetMeshMapSeams),
<span style="color: #bd63c5;">FUNC_ID</span><span style="color: #b4b4b4;">(</span><span style="color: #c2c2c2;">RippleMeshDeform</span><span style="color: #b4b4b4;">),</span>
};
IMXSExposure() :
FPInterfaceDesc(
MXSEXPOSURE_INTERFACE_ID, _M("MXSExposure"), 0, nullptr, FP_CORE + FP_STATIC_METHODS
, p_end) {
AppendFunction(
FUNC_ID(SetMeshSelLevel), FUNC_STR(SetMeshSelLevel), 0, TYPE_VOID, 0, 2
, _M("mesh"), 0, TYPE_MESH
, _M("level"), 0, TYPE_INT
, p_end);
AppendFunction(FUNC_ID(GetMeshMapSeams), FUNC_STR(GetMeshMapSeams), 0, TYPE_BITARRAY, FP_NO_REDRAW, 2
, _M("mesh"), 0, TYPE_MESH
, _M("mapChannel"), 0, TYPE_INT
, p_end);
<span style="color: #c8c8c8;">AppendFunction</span><span style="color: #b4b4b4;">(</span>
<span style="color: #bd63c5;">FUNC_ID</span><span style="color: #b4b4b4;">(</span><span style="color: #c8c8c8;">RippleMeshDeform</span><span style="color: #b4b4b4;">),</span> <span style="color: #bd63c5;">FUNC_STR</span><span style="color: #b4b4b4;">(</span><span style="color: #c8c8c8;">RippleMeshDeform</span><span style="color: #b4b4b4;">),</span> <span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_VOID</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">5</span>
<span style="color: #b4b4b4;">,</span> <span style="color: #bd63c5;">_M</span><span style="color: #b4b4b4;">(</span><span style="color: #d69d85;">"mesh"</span><span style="color: #b4b4b4;">),</span> <span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_MESH</span>
<span style="color: #b4b4b4;">,</span> <span style="color: #bd63c5;">_M</span><span style="color: #b4b4b4;">(</span><span style="color: #d69d85;">"center"</span><span style="color: #b4b4b4;">),</span> <span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_POINT3_BR</span>
<span style="color: #b4b4b4;">,</span> <span style="color: #bd63c5;">_M</span><span style="color: #b4b4b4;">(</span><span style="color: #d69d85;">"speed"</span><span style="color: #b4b4b4;">),</span> <span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_FLOAT</span>
<span style="color: #b4b4b4;">,</span> <span style="color: #bd63c5;">_M</span><span style="color: #b4b4b4;">(</span><span style="color: #d69d85;">"frequency"</span><span style="color: #b4b4b4;">),</span> <span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_FLOAT</span>
<span style="color: #b4b4b4;">,</span> <span style="color: #bd63c5;">_M</span><span style="color: #b4b4b4;">(</span><span style="color: #d69d85;">"amplitude"</span><span style="color: #b4b4b4;">),</span> <span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_FLOAT</span>
<span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">p_end</span><span style="color: #b4b4b4;">);</span>
};
BEGIN_FUNCTION_MAP
VFN_2(FUNC_ID(SetMeshSelLevel), SetMeshSelLevel, TYPE_MESH, TYPE_INT)
FN_2(FUNC_ID(GetMeshMapSeams), TYPE_BITARRAY, GetMeshMapSeams, TYPE_MESH, TYPE_INT)
<span style="color: #bd63c5;">VFN_5</span><span style="color: #b4b4b4;">(</span><span style="color: #bd63c5;">FUNC_ID</span><span style="color: #b4b4b4;">(</span><span style="color: #c8c8c8;">RippleMeshDeform</span><span style="color: #b4b4b4;">),</span> <span style="color: #c8c8c8;">RippleMeshDeform</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_MESH</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_POINT3_BR</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_FLOAT</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_FLOAT</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_FLOAT</span><span style="color: #b4b4b4;">)</span>
END_FUNCTION_MAP
void SetMeshSelLevel(Mesh* mesh, int level) const;
BitArray* GetMeshMapSeams(const Mesh * mesh, int mapChannel) const;
<span style="color: #569cd6;">void</span> <span style="color: #c8c8c8;">RippleMeshDeform</span><span style="color: #b4b4b4;">(</span><span style="color: #4ec9b0;">Mesh</span><span style="color: #b4b4b4;">*</span> <span style="color: #7f7f7f;">mesh</span><span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">const</span> <span style="color: #4ec9b0;">Point3</span><span style="color: #b4b4b4;">&</span> <span style="color: #7f7f7f;">center</span><span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">float</span> <span style="color: #7f7f7f;">speed</span><span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">float</span> <span style="color: #7f7f7f;">frequency</span><span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">float</span> <span style="color: #7f7f7f;">amplitude</span><span style="color: #b4b4b4;">);</span>
};
</pre>
<p>In the function implementation, we start with the usual null check and then in the same step we make sure there are vertices to deform. Once this has been confirmed, we proceed to use the <code>ip</code> pointer. To be able to call any of the functions of the interface, the <code>maxapi</code> header has to be present – don't worry, Visual Studio is very helpful in this regard and will warn you if you forget, and then it's one click-through from the declaration to see which file you need. The <code>TicksToSec</code> macro converts the time (which is returned in ticks) for us into a meaningful, self-documenting value that we can then multiply by the desired speed:<p>
<pre class="notranslate" style="font-family: Consolas; font-size: 13px; color: gray; background: #1e1e1e;">#include "warnings_disabled.h"
<span style="color: #c2c2c2;">#include</span> <span style="color: #d69d85;"><maxapi.h></span>
#include <mesh.h>
#include <mnmesh.h>
#include "warnings_restored.h"
#include "IMXSExposure.h"
<br />...
<span style="color: #569cd6;">float</span> <span style="color: #c8c8c8;">get2DLength</span><span style="color: #b4b4b4;">(</span><span style="color: #569cd6;">float</span> <span style="color: #7f7f7f;">x</span><span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">float</span> <span style="color: #7f7f7f;">y</span><span style="color: #b4b4b4;">)</span> <span style="color: #b4b4b4;">{</span>
<span style="color: #569cd6;">return</span> <span style="color: #c8c8c8;">sqrt</span><span style="color: #b4b4b4;">(</span><span style="color: #7f7f7f;">x</span> <span style="color: #b4b4b4;">*</span> <span style="color: #7f7f7f;">x</span> <span style="color: #b4b4b4;">+</span> <span style="color: #7f7f7f;">y</span> <span style="color: #b4b4b4;">*</span> <span style="color: #7f7f7f;">y</span><span style="color: #b4b4b4;">);</span>
<span style="color: #b4b4b4;">}</span>
<span style="color: #569cd6;">void</span> <span style="color: #4ec9b0;">IMXSExposure</span><span style="color: #b4b4b4;">::</span><span style="color: #c8c8c8;">RippleMeshDeform</span><span style="color: #b4b4b4;">(</span><span style="color: #4ec9b0;">Mesh</span><span style="color: #b4b4b4;">*</span> <span style="color: #7f7f7f;">mesh</span><span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">const</span> <span style="color: #4ec9b0;">Point3</span><span style="color: #b4b4b4;">&</span> <span style="color: #7f7f7f;">center</span><span style="color: #b4b4b4;">,</span>
<span style="color: #569cd6;">float</span> <span style="color: #7f7f7f;">speed</span><span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">float</span> <span style="color: #7f7f7f;">frequency</span><span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">float</span> <span style="color: #7f7f7f;">amplitude</span><span style="color: #b4b4b4;">)</span>
<span style="color: #b4b4b4;">{</span>
<span style="color:#569cd6;">if</span> <span style="color:#b4b4b4;">(!</span><span style="color:#7f7f7f;">mesh</span> <span style="color:#b4b4b4;">||</span> <span style="color:#b4b4b4;">!</span><span style="color:#7f7f7f;">mesh</span><span style="color:#b4b4b4;">-></span><span style="color:#dadada;">numVerts</span><span style="color:#b4b4b4;">)</span> <span style="color:#569cd6;">return</span><span style="color:#b4b4b4;">;</span>
<span style="color: #569cd6;">const</span> <span style="color: #569cd6;">float</span> <span style="color: #c8c8c8;">shift</span> <span style="color: #b4b4b4;">=</span> <span style="color: #bd63c5;">TicksToSec</span><span style="color: #b4b4b4;">(</span><span style="color: #dadada;">ip</span><span style="color: #b4b4b4;">-></span><span style="color: #c8c8c8;">GetTime</span><span style="color: #b4b4b4;">())</span> <span style="color: #b4b4b4;">*</span> <span style="color: #7f7f7f;">speed</span><span style="color: #b4b4b4;">;</span>
<span style="color: #569cd6;">auto</span> <span style="color: #c8c8c8;">vert</span> <span style="color: #b4b4b4;">=</span> <span style="color: #b4b4b4;">&(</span><span style="color: #7f7f7f;">mesh</span><span style="color: #b4b4b4;">-></span><span style="color: #c8c8c8;">getVert</span><span style="color: #b4b4b4;">(</span><span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">));</span>
<span style="color: #569cd6;">for</span> <span style="color: #b4b4b4;">(</span><span style="color: #569cd6;">int</span> <span style="color: #c8c8c8;">v</span> <span style="color: #b4b4b4;">=</span> <span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">,</span> <span style="color: #c8c8c8;">numVerts</span> <span style="color: #b4b4b4;">=</span> <span style="color: #7f7f7f;">mesh</span><span style="color: #b4b4b4;">-></span><span style="color: #dadada;">numVerts</span><span style="color: #b4b4b4;">;</span> <span style="color: #c8c8c8;">v</span> <span style="color: #b4b4b4;"><</span> <span style="color: #c8c8c8;">numVerts</span><span style="color: #b4b4b4;">;</span> <span style="color: #b4b4b4;">++</span><span style="color: #c8c8c8;">v</span><span style="color: #b4b4b4;">,</span> <span style="color: #b4b4b4;">++</span><span style="color: #c8c8c8;">vert</span><span style="color: #b4b4b4;">)</span>
<span style="color: #c8c8c8;">vert</span><span style="color: #b4b4b4;">-></span><span style="color: #dadada;">z</span> <span style="color: #b4b4b4;">+=</span> <span style="color: #7f7f7f;">amplitude</span> <span style="color: #b4b4b4;">*</span> <span style="color: #c8c8c8;">sin</span><span style="color: #b4b4b4;">(</span><span style="color: #7f7f7f;">frequency</span> <span style="color: #b4b4b4;">*</span> <span style="color: #c8c8c8;">get2DLength</span><span style="color: #b4b4b4;">(</span><span style="color: #c8c8c8;">vert</span><span style="color: #b4b4b4;">-></span><span style="color: #dadada;">x</span> <span style="color: #b4b4b4;">-</span> <span style="color: #7f7f7f;">center</span><span style="color: #b4b4b4;">.</span><span style="color: #dadada;">x</span><span style="color: #b4b4b4;">,</span> <span style="color: #c8c8c8;">vert</span><span style="color: #b4b4b4;">-></span><span style="color: #dadada;">y</span> <span style="color: #b4b4b4;">-</span> <span style="color: #7f7f7f;">center</span><span style="color: #b4b4b4;">.</span><span style="color: #dadada;">y</span><span style="color: #b4b4b4;">)</span> <span style="color: #b4b4b4;">-</span> <span style="color: #c8c8c8;">shift</span><span style="color: #b4b4b4;">);</span>
<span style="color: #b4b4b4;">}</span>
</pre>
<p>And now let's see if you did your homework and familiarized yourself with pointers. A <code>Mesh</code> is a super simple structure with most of its data neatly packed in simple arrays. And if you remember how arrays work, you'll recall that when you receive an array, you essentially get a pointer to the first item. Increment that pointer and you have a pointer to the second item, and so on. So when you ask for the first vertex and take its address, you have the address of the beginning of the array. Alternatively, we could have just as well used <code><span style="color:#569cd6;">auto</span> <span style="color:#c8c8c8;">vert</span> <span style="color:#b4b4b4;">=</span> <span style="color:#7f7f7f;">mesh</span><span style="color:#b4b4b4;">-></span><span style="color:#dadada;">verts</span><span style="color:#b4b4b4;">;</span></code></p>
<p>This is all pretty clean and safe, just bear in mind that you'll see <a href="https://code.tutsplus.com/articles/c-succinctly-casting-in-c--mobile-22058">C-style casts</a> scattered over the samples and snippets all over the web – the rule with using C-style casts and C++ is simple – don't. When you want to use a cast, chances are you want <code>dynamic_cast</code> (in case you missed this tidbit from the documentation, I'm gonna quote <a href="https://help.autodesk.com/view/3DSMAX/2020/ENU/?guid=__developer_best_practices_general_best_practices_html">General Best Practices</a> here: <i>Use dynamic_cast instead of using the unsafe static_cast and always check the result for NULL to make sure that it succeeded</i>).
<p>Now, let's take a peek at the <code>for</code> loop. It's a bit on the lengthy side – if I were to actually use that in this form, I'd at least split it at each semicolon – and it does many things at once. The first initialization part is executed only once at the very beginning and sets the counter variable (that then gets compared against the total number of verts), and the total number of verts to check against. The second part is the actual comparison being evaluated, which happens repeatedly as a condition before executing the loop body. And the final part increments both the loop counter and the vertex pointer, right after the body is finished executing. There's also <a href="https://docs.microsoft.com/en-us/cpp/cpp/range-based-for-statement-cpp?view=vs-2019">range-based loop</a> variant that's worth getting acquainted with but you can't use that when all you have is an array pointer. An elegant solution is using spans – but that's only available in the Guideline Support Library or if you wait for C++20.</p>
<p>The loop body itself is in fact pretty uneventful compared to the previous line. The <code>z</code> value of the current vert is incremented by a <code>sin</code> of the horizontal distance from the current vert to the center position, multiplied by the frequency, and shifted by the product of time and speed. The <code>get2DLength</code> function, which calculates the distance in the XY plane, is defined right before the RippleMeshDeform function. And that's it for now for the C++ part.</p>
<p>You already know the rest of the drill, CTRL+F5 and put it to the test in Max. For that, I've prepared another <code>simpleMeshMod</code>:</p>
<pre class="notranslate">
<code><span class="code-keywords1">plugin</span> simpleMeshMod SimpleRipple</code>
<code> name<span class="code-symbol">:</span><span class="code-string">"Simple Ripple"</span></code>
<code> classID<span class="code-symbol">:#(</span><span class="code-number">0x68a11be6</span><span class="code-symbol">,</span> <span class="code-number">0x4ec696e8</span><span class="code-symbol">)</span></code>
<code> usePBValidity<span class="code-symbol">:</span><span class="code-keywords1">off</span> <span class="code-comment">-- always trigger update on time change</span></code>
<code><span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">parameters</span> main <span class="code-keywords1">rollout</span><span class="code-symbol">:</span><span class="code-identifier">params</span></code>
<code> <span class="code-symbol">(</span></code>
<code> speed type<span class="code-symbol">:</span><span class="code-string">#float</span> <span class="code-identifier">ui</span><span class="code-symbol">:</span><span class="code-identifier">spnSpeed default</span><span class="code-symbol">:</span><span class="code-number">10</span></code>
<code> frequency type<span class="code-symbol">:</span><span class="code-string">#float</span> <span class="code-identifier">ui</span><span class="code-symbol">:</span><span class="code-identifier">spnFrequency default</span><span class="code-symbol">:</span><span class="code-number">1</span></code>
<code> amplitude type<span class="code-symbol">:</span><span class="code-string">#worldUnits</span> <span class="code-identifier">ui</span><span class="code-symbol">:</span><span class="code-identifier">spnAmplitude default</span><span class="code-symbol">:</span><span class="code-number">1</span></code>
<code> source type<span class="code-symbol">:</span><span class="code-string">#node</span> <span class="code-identifier">ui</span><span class="code-symbol">:</span><span class="code-identifier">pbSource useNodeTmValidity</span><span class="code-symbol">:</span><span class="code-keywords1">on</span></code>
<code> _dummy type<span class="code-symbol">:</span><span class="code-string">#maxObjectTab</span> <span class="code-identifier">tabSizeVariable</span><span class="code-symbol">:</span><span class="code-keywords1">on</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords1">rollout</span> params <span class="code-string">"Parameters"</span></code>
<code> <span class="code-symbol">(</span></code>
<code> pickButton pbSource <span class="code-string">"NONE"</span> width<span class="code-symbol">:</span><span class="code-number">140</span> autoDisplay<span class="code-symbol">:</span><span class="code-keywords1">on</span></code>
<code> spinner spnSpeed <span class="code-string">"Speed: "</span> type<span class="code-symbol">:</span><span class="code-string">#float</span> <span class="code-identifier">range</span><span class="code-symbol">:[</span><span class="code-number">0</span><span class="code-symbol">,</span><span class="code-number">1e6</span><span class="code-symbol">,</span><span class="code-number">0</span><span class="code-symbol">]</span></code>
<code> spinner spnFrequency <span class="code-string">"Frequency: "</span> type<span class="code-symbol">:</span><span class="code-string">#float</span> <span class="code-identifier">range</span><span class="code-symbol">:[</span><span class="code-number">0</span><span class="code-symbol">,</span><span class="code-number">1e6</span><span class="code-symbol">,</span><span class="code-number">1</span><span class="code-symbol">]</span></code>
<code> spinner spnAmplitude <span class="code-string">"Amplitude: "</span> type<span class="code-symbol">:</span><span class="code-string">#worldUnits</span> <span class="code-identifier">range</span><span class="code-symbol">:[</span><span class="code-number">-1e6</span><span class="code-symbol">,</span><span class="code-number">1e6</span><span class="code-symbol">,</span><span class="code-number">1</span><span class="code-symbol">]</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords1">on</span> attachedToNode node <span class="code-keywords1">do</span> <span class="code-keywords1">if</span> isValidNode node <span class="code-keywords1">do</span></code>
<code> append this<span class="code-symbol">.</span><span class="code-identifier">_dummy </span><span class="code-symbol">(</span><span class="code-identifier">NodeTransformMonitor node</span><span class="code-symbol">:</span><span class="code-identifier">node</span><span class="code-symbol">)</span> <span class="code-comment">-- explicitly trigger update whenever node transform changes</span></code>
<code></code>
<code> <span class="code-keywords1">on</span> modifyMesh <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> center <span class="code-symbol">=</span> <span class="code-keywords1">if</span> isValidNode source <span class="code-keywords1">then</span> <span class="code-symbol">(</span><span class="code-identifier">source</span><span class="code-symbol">.</span><span class="code-identifier">transform </span><span class="code-symbol">*</span> inverse owningNode<span class="code-symbol">.</span><span class="code-identifier">objectTransform</span><span class="code-symbol">).</span><span class="code-identifier">pos </span><span class="code-keywords1">else</span> <span class="code-symbol">[</span><span class="code-number">0</span><span class="code-symbol">,</span><span class="code-number">0</span><span class="code-symbol">,</span><span class="code-number">0</span><span class="code-symbol">]</span></code>
<code> MXSExposure<span class="code-symbol">.</span><span class="code-identifier">RippleMeshDeform</span> <span class="code-keywords3">mesh</span><span class="code-identifier"> center speed frequency amplitude</span></code>
<code> <span class="code-symbol">)</span></code>
<code><span class="code-symbol">)</span></code>
</pre>
<p>Since we are always using the current time to calculate the wave shift, don't forget to use <code>usePBValidity:off</code>, otherwise an update would only be triggered if any of the params of the parameter block used an animated controller at that time.</p>
<p>With that in place, the time-dependent changes should work as desired:</p>
<div class="separator" style="clear: both; text-align: center;"><img height="auto" width="500"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWviSCRKFgAJdWH-WdCYuoAoGA8Fz9e6koGnKLrclzDAxDC6Xv-NvoeDWfjmJ-bB-ms4roH68W_pBWS6fqCtoWd87ulbkddyiOONXIfM5bO36NX9swAvtPAmQHe7SO-IOEtjcHZ7oyh9Y/s1600/simple_ripple.gif" /></div>
<p></p>
<div style="font-size: 10pt; font-weight: bold; padding-bottom: 6px;" id="convenient">Convenience Features</div>
<p></p>
<p>So far, we've done all the necessary checks ourselves (if any – <code>SetMeshSelLevel</code> never checks if it received a valid level!). If you were thinking there must be a better way, you're right. Let's start with the <code>GetMeshMapSeams</code>, it would make sense if you weren't allowed to pass a map channel number that's outside the regularly used <code>1..99</code> range. To do that, it's enough to add a <code>f_range</code> tag to the parameter in question, followed by the lower and upper bounds within the AppendFunction call:<p>
<pre class="notranslate" style="font-family:Consolas;font-size:13px;color:gainsboro;background:#1e1e1e;"><span style="color:#c8c8c8;">AppendFunction</span><span style="color:#b4b4b4;">(</span>
<span style="color:#bd63c5;">FUNC_ID</span><span style="color:#b4b4b4;">(</span><span style="color:#c8c8c8;">GetMeshMapSeams</span><span style="color:#b4b4b4;">),</span> <span style="color:#bd63c5;">FUNC_STR</span><span style="color:#b4b4b4;">(</span><span style="color:#c8c8c8;">GetMeshMapSeams</span><span style="color:#b4b4b4;">),</span> <span style="color:#b5cea8;">0</span><span style="color:#b4b4b4;">,</span> <span style="color:#b8d7a3;">TYPE_BITARRAY</span><span style="color:#b4b4b4;">,</span> <span style="color:#bd63c5;">FP_NO_REDRAW</span><span style="color:#b4b4b4;">,</span> <span style="color:#b5cea8;">2</span>
<span style="color:#b4b4b4;">,</span> <span style="color:#bd63c5;">_M</span><span style="color:#b4b4b4;">(</span><span style="color:#d69d85;">"mesh"</span><span style="color:#b4b4b4;">),</span> <span style="color:#b5cea8;">0</span><span style="color:#b4b4b4;">,</span> <span style="color:#b8d7a3;">TYPE_MESH</span>
<span style="color:#b4b4b4;">,</span> <span style="color:#bd63c5;">_M</span><span style="color:#b4b4b4;">(</span><span style="color:#d69d85;">"mapChannel"</span><span style="color:#b4b4b4;">),</span> <span style="color:#b5cea8;">0</span><span style="color:#b4b4b4;">,</span> <span style="color:#b8d7a3;">TYPE_INT</span><span style="color:#b4b4b4;">,</span> <span style="color:#b8d7a3;">f_range</span><span style="color:#b4b4b4;">,</span> <span style="color:#b5cea8;">1</span><span style="color:#b4b4b4;">,</span> <span style="color:#b5cea8;">99</span>
<span style="color:#b4b4b4;">,</span> <span style="color:#b8d7a3;">p_end</span><span style="color:#b4b4b4;">);</span></pre>
<div class="separator" style="clear: both; text-align: center;"><img height="auto" width="550"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_nvAy00HEbhAWgFNFt0U-ZCMoqpb4ebW0PfCmUFReImbmLor8neDBJPTraKcMziqyfavY8HOS5A1QCr5UmyaQJTEjmgxBX18kbRnpb8ee0dngX2iySkqCH0_d-XseXeUFcsXsKLqHUxQ/s1600/range_validation.png" /></div>
<br><p>Super simple and super handy. A bit limited, though, because sometimes you may want to validate a predefined set of values, values that are not inherently floats or ints, or values like Point3. That's why there's also <code>f_validator</code> for your own custom validator function. We'll need to give it a pointer to our validator class instance, and that class we first have to create. I'll call mine <code>Point3Validator</code>:
<div class="separator" style="clear: both; text-align: center;"><img height="auto" width="500"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitTUARSfn_wpxWdo3_S93K28rbI7b6G179089iYcvSRM6JrQfOCXoZB564oBMWtpImWzyBgR8q79eDLLHiYn1fNYUPYKIn55pU5xbM1GoyMriR8B7FxxVVJzX5UoqMdLmLcapBPx1uW4E/s1600/validator_class.png" /></div>
<br><p>Now let's go ahead and implement the inherited method right away (via Quick Actions, either through right-click or <code>CTRL+.</code>):</p>
<div class="separator" style="clear: both; text-align: center;"><img height="auto" width="500"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgG8P6hAG-6TEW6xniOoUur6DHIW3eE9-PtnjIPRX9wAGXyTvKIz_jlJif8lQwBmQuT89EG2ybcjEhJJXBOa6DxDEQ71sBLh6xbUCnxvz1PNZECVSoLi33oVo6HV9MnzbH-Q90j-i0q6p0/s1600/validator_validate.gif" /></div>
<br><p>Here's an example of how you might approach it:</p>
<pre class="notranslate" style="font-family:Consolas;font-size:13px;color:gainsboro;background:#1e1e1e;"><span style="color:#9b9b9b;">#include</span> <span style="color:#d69d85;"><point3.h></span>
<span style="color:#9b9b9b;">#include</span> <span style="color:#d69d85;">"Point3Validator.h"</span>
<span class="notranslate" style="color:#569cd6;">bool</span> <span style="color:#4ec9b0;">Point3Validator</span><span style="color:#b4b4b4;">::</span><span style="color:#c8c8c8;">Validate</span><span style="color:#b4b4b4;">(</span><span style="color:#4ec9b0;">FPInterface</span><span style="color:#b4b4b4;">*,</span> <span style="color:#4ec9b0;">FunctionID</span><span style="color:#b4b4b4;">,</span> <span style="color:#569cd6;">int</span><span style="color:#b4b4b4;">,</span> <span style="color:#4ec9b0;">FPValue</span><span style="color:#b4b4b4;">&</span> <span style="color:#7f7f7f;">val</span><span style="color:#b4b4b4;">,</span> <span style="color:#4ec9b0;">MSTR</span><span style="color:#b4b4b4;">&</span> <span style="color:#7f7f7f;">msg</span><span style="color:#b4b4b4;">)</span> <span style="color:#b4b4b4;">{</span>
<span style="color:#569cd6;">const</span> <span style="color:#569cd6;">bool</span> <span style="color:#c8c8c8;">valid</span> <span style="color:#b4b4b4;">=</span> <span style="color:#c8c8c8;">isfinite</span><span style="color:#b4b4b4;">(</span><span style="color:#7f7f7f;">val</span><span style="color:#b4b4b4;">.</span><span style="color:#dadada;">p</span><span style="color:#b4b4b4;">-></span><span style="color:#dadada;">x</span><span style="color:#b4b4b4;">)</span> <span style="color:#b4b4b4;">&&</span> <span style="color:#c8c8c8;">isfinite</span><span style="color:#b4b4b4;">(</span><span style="color:#7f7f7f;">val</span><span style="color:#b4b4b4;">.</span><span style="color:#dadada;">p</span><span style="color:#b4b4b4;">-></span><span style="color:#dadada;">y</span><span style="color:#b4b4b4;">)</span> <span style="color:#b4b4b4;">&&</span> <span style="color:#c8c8c8;">isfinite</span><span style="color:#b4b4b4;">(</span><span style="color:#7f7f7f;">val</span><span style="color:#b4b4b4;">.</span><span style="color:#dadada;">p</span><span style="color:#b4b4b4;">-></span><span style="color:#dadada;">z</span><span style="color:#b4b4b4;">);</span>
<span style="color:#569cd6;">if</span> <span style="color:#b4b4b4;">(!</span><span style="color:#c8c8c8;">valid</span><span style="color:#b4b4b4;">)</span> <span style="color:#7f7f7f;">msg</span> <span style="color:#b4b4b4;">=</span> <span style="color:#bd63c5;">_T</span><span style="color:#b4b4b4;">(</span><span style="color:#d69d85;">"Center must be a valid position."</span><span style="color:#b4b4b4;">);</span>
<span style="color:#569cd6;">return</span> <span style="color:#c8c8c8;">valid</span><span style="color:#b4b4b4;">;</span>
<span style="color:#b4b4b4;">}</span>
<span style="color:#4ec9b0;">Point3Validator</span><span style="color:#b4b4b4;">*</span> <span style="color:#c8c8c8;">GetPoint3Validator</span><span style="color:#b4b4b4;">()</span>
<span style="color:#b4b4b4;">{</span>
<span style="color:#569cd6;">static</span> <span style="color:#4ec9b0;">Point3Validator</span> <span style="color:#c8c8c8;">point3Validator</span><span style="color:#b4b4b4;">;</span>
<span style="color:#569cd6;">return</span> <span style="color:#b4b4b4;">&</span><span style="color:#c8c8c8;">point3Validator</span><span style="color:#b4b4b4;">;</span>
<span style="color:#b4b4b4;">}</span></pre>
<p>Since we'll be working with <code>Point3</code> values, a <code>point3.h</code> header file is needed. For the <code>Validate</code> function itself, the first thing you may notice is that the first three parameters no longer have names – since we won't be using them within the function body, the compiler would warn us about that otherwise (<code><a href="https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-4-c4100?view=vs-2019">C4100</a>: <i>unreferenced formal parameter</i></code>), and this way, you can make your intentions clear. Next comes the actual validation, here it is checking if all three parts are finite (neither infinite nor NaN). Since the <code><a href="https://github.com/mathieumg/inf4715/blob/master/Exporter/maxsdk/include/ifnpub.h#L1152
">FPValue</a></code> is sort of a catch-all container, you have to access its member variable matching to the type you're checking – the <code><a href="https://github.com/mathieumg/inf4715/blob/master/Exporter/maxsdk/include/ifnpub.h#L1173
">p</a></code> in <code>val.p</code> gives you <code>Point3*</code>. If it's not valid, set the <code>msg</code> to a descriptive message, and return the <code>valid</code> bool.</p>
<p>As mentioned before, we need a pointer to supply with the <code>f_validator</code> tag, and for that there's the other function, analogous to the <code>GetDesc</code> function we've seen before. Put its declaration to the class header file, and include the header in the interface class file. For completeness sake, here's the updated header file:</p>
<pre class="notranslate" style="font-family:Consolas;font-size:13px;color:gainsboro;background:#1e1e1e;"><span style="color:#9b9b9b;">#pragma</span> <span style="color:#9b9b9b;">once</span>
<span style="color:#9b9b9b;">#include</span> <span style="color:#d69d85;"><ifnpub.h></span>
<span style="color:#569cd6;">class</span> <span style="color:#4ec9b0;">Point3Validator</span> <span style="color:#b4b4b4;">:</span> <span style="color:#569cd6;">public</span> <span style="color:#4ec9b0;">FPValidator</span> <span style="color:#b4b4b4;">{</span>
<span style="color:#569cd6;">virtual</span> <span style="color:#569cd6;">bool</span> <span style="color:#c8c8c8;">Validate</span><span style="color:#b4b4b4;">(</span><span style="color:#4ec9b0;">FPInterface</span><span style="color:#b4b4b4;">*</span> <span style="color:#7f7f7f;">fpi</span><span style="color:#b4b4b4;">,</span> <span style="color:#4ec9b0;">FunctionID</span> <span style="color:#7f7f7f;">fid</span><span style="color:#b4b4b4;">,</span> <span style="color:#569cd6;">int</span> <span style="color:#7f7f7f;">paramNum</span><span style="color:#b4b4b4;">,</span> <span style="color:#4ec9b0;">FPValue</span><span style="color:#b4b4b4;">&</span> <span style="color:#7f7f7f;">val</span><span style="color:#b4b4b4;">,</span> <span style="color:#4ec9b0;">MSTR</span><span style="color:#b4b4b4;">&</span> <span style="color:#7f7f7f;">msg</span><span style="color:#b4b4b4;">)</span> <span style="color:#569cd6;">override</span><span style="color:#b4b4b4;">;</span>
<span style="color:#b4b4b4;">};</span>
<span style="color:#4ec9b0;">Point3Validator</span><span style="color:#b4b4b4;">*</span> <span style="color:#c8c8c8;">GetPoint3Validator</span><span style="color:#b4b4b4;">();</span></pre>
<p>After that, this should compile and work as expected:</p>
<pre class="notranslate" style="font-family: Consolas; font-size: 13px; color: gray; background: #1e1e1e; height:520px">#pragma once
#include "warnings_disabled.h"
#include <ifnpub.h>
#include <systemutilities.h>
#include "warnings_restored.h"
<span style="color: #c2c2c2;">#include</span> <span style="color: #d69d85;">"Point3Validator.h"</span>
#define FUNC_STR(func) _M(#func) // stringifies the passed variable
#define FUNC_ID(func) func##_id // concatenates the variable name with _id
extern const Interface_ID MXSEXPOSURE_INTERFACE_ID; // not specified here, just made available for callers
class IMXSExposure : public FPInterfaceDesc
{
Interface* ip = UtilGetCOREInterface();
public:
enum functionId : FunctionID {
FUNC_ID(SetMeshSelLevel),
FUNC_ID(GetMeshMapSeams),
FUNC_ID(RippleMeshDeform),
};
IMXSExposure() :
FPInterfaceDesc(
MXSEXPOSURE_INTERFACE_ID, _M("MXSExposure"), 0, nullptr, FP_CORE + FP_STATIC_METHODS
, p_end) {
...
AppendFunction(
FUNC_ID(RippleMeshDeform), FUNC_STR(RippleMeshDeform), 0, TYPE_VOID, 0, 5
, _M("mesh"), 0, TYPE_MESH
, _M("center"), 0, TYPE_POINT3_BR, <span style="color: #b8d7a3;">f_validator</span><span style="color: #b4b4b4;">,</span> <span style="color: #c8c8c8;">GetPoint3Validator</span><span style="color: #b4b4b4;">()</span>
, _M("speed"), 0, TYPE_FLOAT
, _M("frequency"), 0, TYPE_FLOAT
, _M("amplitude"), 0, TYPE_FLOAT
, p_end);
};
BEGIN_FUNCTION_MAP
VFN_2(FUNC_ID(SetMeshSelLevel), SetMeshSelLevel, TYPE_MESH, TYPE_INT)
FN_2(FUNC_ID(GetMeshMapSeams), TYPE_BITARRAY, GetMeshMapSeams, TYPE_MESH, TYPE_INT)
VFN_5(FUNC_ID(RippleMeshDeform), RippleMeshDeform, TYPE_MESH, TYPE_POINT3_BR, TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT)
END_FUNCTION_MAP
void SetMeshSelLevel(Mesh* mesh, int level) const;
BitArray* GetMeshMapSeams(const Mesh * mesh, int mapChannel) const;
void RippleMeshDeform(Mesh* mesh, const Point3& center, float speed, float frequency, float amplitude);
};</pre>
<p>Take a look at what happens when an invalid position is passed as an argument:</p>
<div class="separator" style="clear: both; text-align: center;"><img height="auto" width="550"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSXVGcRDLqPh11MZvUyWpc0o3xW_XIu7Eva1ELi-69Nr9tgIUIkq7uURqu0Y5mmzD17xnUMefSqowe062PiBmpoK-92u0tfWUt4E5Nk0-4qewyZti_IZSMRqL-OLlReP_gCF04HOBUH0I/s1600/pos_validator.png" /></div>
<br><p>Seeing that <code>showInterface</code> printout, one more thing is bothering me. It says <i>center is In and Out parameter</i> but we never change it, so it gives the wrong impression. Luckily, there's another tag for that, and the tags can be chained so we can do this to change it to <code>In</code> parameter only:</p>
<pre class="notranslate" style="font-family: Consolas; font-size: 13px; color: gray; background: #1e1e1e;">AppendFunction(
FUNC_ID(RippleMeshDeform), FUNC_STR(RippleMeshDeform), 0, TYPE_VOID, 0, 5
, _M("mesh"), 0, TYPE_MESH
<span style="color: #b4b4b4;">,</span> <span style="color: #bd63c5;">_M</span><span style="color: #b4b4b4;">(</span><span style="color: #d69d85;">"center"</span><span style="color: #b4b4b4;">),</span> <span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_POINT3_BR</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">f_inOut</span><span style="color: #b4b4b4;">,</span> <span style="color: #bd63c5;">FPP_IN_PARAM</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">f_validator</span><span style="color: #b4b4b4;">,</span> <span style="color: #c8c8c8;">GetPoint3Validator</span><span style="color: #b4b4b4;">()</span>
, _M("speed"), 0, TYPE_FLOAT
, _M("frequency"), 0, TYPE_FLOAT
, _M("amplitude"), 0, TYPE_FLOAT
, p_end);</pre>
<p>Likewise, you can use <code>f_keyArgDefault</code> to mark optional keyword arguments. All you have to do is make sure that no other non-keyword argument follows it in the list of arguments, and you have to provide the default value:</p>
<pre class="notranslate" style="font-family: Consolas; font-size: 13px; color: gray; background: #1e1e1e;">AppendFunction(
FUNC_ID(GetMeshMapSeams), FUNC_STR(GetMeshMapSeams), 0, TYPE_BITARRAY, FP_NO_REDRAW, 2
, _M("mesh"), 0, TYPE_MESH
<span style="color: #b4b4b4;">,</span> <span style="color: #bd63c5;">_M</span><span style="color: #b4b4b4;">(</span><span style="color: #d69d85;">"mapChannel"</span><span style="color: #b4b4b4;">),</span> <span style="color: #b5cea8;">0</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">TYPE_INT</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">f_range</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">1</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">99</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">f_keyArgDefault</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">1</span>
, p_end);</pre>
<div class="separator" style="clear: both; text-align: center;"><img height="auto" width="550"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjfI_xyJ27YLdOQa6tCYFL3fE-3E0pcMvod4V4gL4wMX2XkRPEcfynT_eaixKlEcvTdI8u5eijFgf-9adQb60V9P5yY4O4z6MsPln1pEtqxUmWs2rtnPnMMNehM48lnt88DLkWjbkYZu_g/s1600/keyword_argument.png" /></div>
<br><p>In this particular case, it's a rather contrived example but should be enough to give you an idea or two how to work with the tags. Notice also how the <code>center</code> has changed to <code>In</code> parameter type only.</p>
<p>However, we still haven't done anything about the <code>SetMeshSelLevel</code> argument validation – yes, we could use a validator but there's a better, self-documenting way, and that's to use a <a href="https://help.autodesk.com/view/3DSMAX/2020/ENU/?guid=__developer_3ds_max_sdk_features_function_publishing_symbolic_enumerations_html">symbolic enumeration</a>:</p>
<pre class="notranslate" style="font-family: Consolas; font-size: 12px; color: gray; background: #1e1e1e; height:650px;">
...
class IMXSExposure : public FPInterfaceDesc
{
Interface* ip = UtilGetCOREInterface();
public:
enum functionId : FunctionID {
...,
};
<span style="color: #569cd6;">enum</span> <span style="color: #4ec9b0;">enumID</span> <span style="color: #b4b4b4;">:</span> <span style="color: #4ec9b0;">EnumID</span> <span style="color: #b4b4b4;">{</span>
<span style="color: #b8d7a3;">selLevelID</span><span style="color: #b4b4b4;">,</span>
...
IMXSExposure() :
FPInterfaceDesc(
MXSEXPOSURE_INTERFACE_ID, _M("MXSExposure"), 0, nullptr, FP_CORE + FP_STATIC_METHODS
, p_end) {
AppendFunction(
FUNC_ID(SetMeshSelLevel), FUNC_STR(SetMeshSelLevel), 0, TYPE_VOID, 0, 2
, _M("mesh"), 0, TYPE_MESH
, _M("level"), 0, <span style="color: #b8d7a3;">TYPE_ENUM</span><span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">selLevelID</span>
, p_end);
AppendFunction(
...);
<span style="color: #c8c8c8;">AppendEnum</span><span style="color: #b4b4b4;">(</span>
<span style="color: #b8d7a3;">selLevelID</span><span style="color: #b4b4b4;">,</span> <span style="color: #b5cea8;">4</span>
<span style="color: #b4b4b4;">,</span> <span style="color: #bd63c5;">_M</span><span style="color: #b4b4b4;">(</span><span style="color: #d69d85;">"object"</span><span style="color: #b4b4b4;">),</span> <span style="color: #bd63c5;">MESH_OBJECT</span>
<span style="color: #b4b4b4;">,</span> <span style="color: #bd63c5;">_M</span><span style="color: #b4b4b4;">(</span><span style="color: #d69d85;">"vertex"</span><span style="color: #b4b4b4;">),</span> <span style="color: #bd63c5;">MESH_VERTEX</span>
<span style="color: #b4b4b4;">,</span> <span style="color: #bd63c5;">_M</span><span style="color: #b4b4b4;">(</span><span style="color: #d69d85;">"edge"</span><span style="color: #b4b4b4;">),</span> <span style="color: #bd63c5;">MESH_EDGE</span>
<span style="color: #b4b4b4;">,</span> <span style="color: #bd63c5;">_M</span><span style="color: #b4b4b4;">(</span><span style="color: #d69d85;">"face"</span><span style="color: #b4b4b4;">),</span> <span style="color: #bd63c5;">MESH_FACE</span>
<span style="color: #b4b4b4;">,</span> <span style="color: #b8d7a3;">p_end</span><span style="color: #b4b4b4;">);</span>
};
BEGIN_FUNCTION_MAP
VFN_2(FUNC_ID(SetMeshSelLevel), SetMeshSelLevel, TYPE_MESH, <span style="color: #b8d7a3;">TYPE_ENUM</span>)
FN_2(FUNC_ID(GetMeshMapSeams), TYPE_BITARRAY, GetMeshMapSeams, TYPE_MESH, TYPE_INT)
VFN_5(FUNC_ID(RippleMeshDeform), RippleMeshDeform, TYPE_MESH, TYPE_POINT3_BR, TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT)
END_FUNCTION_MAP
void SetMeshSelLevel(Mesh* mesh, int level) const;
BitArray* GetMeshMapSeams(const Mesh * mesh, int mapChannel) const;
void RippleMeshDeform(Mesh* mesh, const Point3& center, float speed, float frequency, float amplitude);
};</pre>
<p>Just like functions, enums must have IDs, but since the enum definition happens within the <code>AppendEnum</code> call, I'm using a fixed ID. For the <code>AppendEnum</code>, we need to pass number of members and their names and values, and we can directly use the flags from <code>mesh.h</code> for the values here. The only other change is from the TYPE_INT to TYPE_ENUM, and in the case of the <code>AppendFunction</code>, the enum type tag has to be followed by the enum ID. We should finally be able to replace that ugly <code>8</code> with something meaningful, as promised:</p>
<div class="separator" style="clear: both; text-align: center;"><img height="auto" width="550"
src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnTJxBZOb5FDQN82zq1qCC1iLI99Zo9OMZpE2SMCDeTEF723Ol-62y00pR1Sn7z4bW1kdscdHXpJoxF3JneYq_PlQdCluEwfeNH8MOf0zsiD8Gh1FcHdjO4BBe_5q2BZlWTjc2sIV8D18/s1600/level_enum.png" /></div>
<br><p>All of these changes were limited to the parameter list, without no edits to the actual function. That said, there's still a territory we haven't covered yet – other specialized function macros outside of <code>FN</code> and <code>VFN</code>. For one, there are macros that you can use to expose properties directly instead of through a getter/setter pair, those are <a href="https://help.autodesk.com/view/3DSMAX/2020/ENU/?guid=__developer_3ds_max_sdk_features_function_publishing_property_accessors_html"><code>PROP_FNS</code></a> for the aforementioned getter/setter pairing, <code>RO_PROP_FN</code> for a read-only property (getter only, note the singular <code>FN</code>), their time-dependent variants <code>PROP_TFNS</code>/<code>RO_PROP_TFN</code>, and static method versions of all the previous four with the prefix <code>SM_</code>.</p>
<p>Then there are <code>CFN</code> functions with constant return values (they do a <code>const_cast</code> behind the scenes) – which I have never seen used anywhere. And finally, <code>VFNT_</code>/<code>FNT_</code> for void/value-returning functions with time parameter, which is the same concept as the time-dependent properties mentioned earlier. In addition to the list of parameters given to the macro, they receive a time parameter – and guess where we could use it? Bingo, turns out we didn't need the Interface variable after all – but don't worry, it might come in handy for other tasks. Now let's update our <code>RippleMeshDeform</code>:</p>
<pre class="notranslate" style="font-family: Consolas; font-size: 13px; color: gray; background: #1e1e1e;"> BEGIN_FUNCTION_MAP
VFN_2(FUNC_ID(SetMeshSelLevel), SetMeshSelLevel, TYPE_MESH, TYPE_ENUM)
FN_2(FUNC_ID(GetMeshMapSeams), TYPE_BITARRAY, GetMeshMapSeams, TYPE_MESH, TYPE_INT)
<span style="color: #bd63c5;">VFNT_5</span>(FUNC_ID(RippleMeshDeform), RippleMeshDeform, TYPE_MESH, TYPE_POINT3_BR, TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT)
END_FUNCTION_MAP
void SetMeshSelLevel(Mesh* mesh, int level) const;
BitArray* GetMeshMapSeams(const Mesh * mesh, int mapChannel) const;
<span style="color: #569cd6;">void</span> <span style="color: #c8c8c8;">RippleMeshDeform</span><span style="color: #b4b4b4;">(</span><span style="color: #4ec9b0;">Mesh</span><span style="color: #b4b4b4;">*</span> <span style="color: #7f7f7f;">mesh</span><span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">const</span> <span style="color: #4ec9b0;">Point3</span><span style="color: #b4b4b4;">&</span> <span style="color: #7f7f7f;">center</span><span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">float</span> <span style="color: #7f7f7f;">speed</span><span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">float</span> <span style="color: #7f7f7f;">frequency</span><span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">float</span> <span style="color: #7f7f7f;">amplitude</span><span style="color: #b4b4b4;">,</span> <span style="color: #569cd6;">const</span> <span style="color: #4ec9b0;">TimeValue</span><span style="color: #b4b4b4;">&</span> <span style="color: #7f7f7f;">time</span><span style="color: #b4b4b4;">);</span>
</pre>
<p>The only two things that have changed in the header are the added <code>V</code> in the macro name and a new <code>const TimeValue& time</code> function parameter. On the <code>cpp-side</code>, it would be enough to replace <code>ip->GetTime()</code> with the new <code>time</code> variable...</p>
<pre class="notranslate" style="font-family:Consolas;font-size:13px;color:gainsboro;background:#1e1e1e;"><span style="color:#569cd6;">void</span> <span style="color:#4ec9b0;">IMXSExposure</span><span style="color:#b4b4b4;">::</span><span style="color:#c8c8c8;">RippleMeshDeform</span><span style="color:#b4b4b4;">(</span><span style="color:#4ec9b0;">Mesh</span><span style="color:#b4b4b4;">*</span> <span style="color:#7f7f7f;">mesh</span><span style="color:#b4b4b4;">,</span> <span style="color:#569cd6;">const</span> <span style="color:#4ec9b0;">Point3</span><span style="color:#b4b4b4;">&</span> <span style="color:#7f7f7f;">center</span><span style="color:#b4b4b4;">,</span>
<span style="color:#569cd6;">float</span> <span style="color:#7f7f7f;">speed</span><span style="color:#b4b4b4;">,</span> <span style="color:#569cd6;">float</span> <span style="color:#7f7f7f;">frequency</span><span style="color:#b4b4b4;">,</span> <span style="color:#569cd6;">float</span> <span style="color:#7f7f7f;">amplitude</span><span style="color:#b4b4b4;">,</span> <span style="color:#569cd6;">const</span> <span style="color:#4ec9b0;">TimeValue</span><span style="color:#b4b4b4;">&</span> <span style="color:#7f7f7f;">time</span><span style="color:#b4b4b4;">)</span>
<span style="color:#b4b4b4;">{</span>
<span style="color:#569cd6;">if</span> <span style="color:#b4b4b4;">(!</span><span style="color:#7f7f7f;">mesh</span> <span style="color:#b4b4b4;">||</span> <span style="color:#b4b4b4;">!</span><span style="color:#7f7f7f;">mesh</span><span style="color:#b4b4b4;">-></span><span style="color:#dadada;">numVerts</span><span style="color:#b4b4b4;">)</span> <span style="color:#569cd6;">return</span><span style="color:#b4b4b4;">;</span>
<span style="color:#569cd6;">static</span> <span style="color:#569cd6;">auto</span> <span style="color:#c8c8c8;">get2DLength</span> <span style="color:#b4b4b4;">=</span> <span style="color:#b4b4b4;">[](</span><span style="color:#569cd6;">float</span> <span style="color:#7f7f7f;">x</span><span style="color:#b4b4b4;">,</span> <span style="color:#569cd6;">float</span> <span style="color:#7f7f7f;">y</span><span style="color:#b4b4b4;">)</span> <span style="color:#b4b4b4;">{</span> <span style="color:#569cd6;">return</span> <span style="color:#c8c8c8;">sqrt</span><span style="color:#b4b4b4;">(</span><span style="color:#7f7f7f;">x</span> <span style="color:#b4b4b4;">*</span> <span style="color:#7f7f7f;">x</span> <span style="color:#b4b4b4;">+</span> <span style="color:#7f7f7f;">y</span> <span style="color:#b4b4b4;">*</span> <span style="color:#7f7f7f;">y</span><span style="color:#b4b4b4;">);</span> <span style="color:#b4b4b4;">};</span>
<span style="color:#569cd6;">const</span> <span style="color:#569cd6;">float</span> <span style="color:#c8c8c8;">shift</span> <span style="color:#b4b4b4;">=</span> <span style="color:#bd63c5;">TicksToSec</span><span style="color:#b4b4b4;">(</span><span style="color:#7f7f7f;">time</span><span style="color:#b4b4b4;">)</span> <span style="color:#b4b4b4;">*</span> <span style="color:#7f7f7f;">speed</span><span style="color:#b4b4b4;">;</span>
<span style="color:#569cd6;">for</span> <span style="color:#b4b4b4;">(</span><span style="color:#569cd6;">auto</span> <span style="color:#c8c8c8;">vert</span> <span style="color:#b4b4b4;">=</span> <span style="color:#7f7f7f;">mesh</span><span style="color:#b4b4b4;">-></span><span style="color:#dadada;">verts</span><span style="color:#b4b4b4;">,</span> <span style="color:#c8c8c8;">cutoff</span> <span style="color:#b4b4b4;">=</span> <span style="color:#c8c8c8;">vert</span> <span style="color:#b4b4b4;">+</span> <span style="color:#7f7f7f;">mesh</span><span style="color:#b4b4b4;">-></span><span style="color:#dadada;">numVerts</span><span style="color:#b4b4b4;">;</span> <span style="color:#c8c8c8;">vert</span> <span style="color:#b4b4b4;">!=</span> <span style="color:#c8c8c8;">cutoff</span><span style="color:#b4b4b4;">;</span> <span style="color:#b4b4b4;">++</span><span style="color:#c8c8c8;">vert</span><span style="color:#b4b4b4;">)</span>
<span style="color:#c8c8c8;">vert</span><span style="color:#b4b4b4;">-></span><span style="color:#dadada;">z</span> <span style="color:#b4b4b4;">+=</span> <span style="color:#7f7f7f;">amplitude</span> <span style="color:#b4b4b4;">*</span> <span style="color:#c8c8c8;">sin</span><span style="color:#b4b4b4;">(</span><span style="color:#7f7f7f;">frequency</span> <span style="color:#b4b4b4;">*</span> <span style="color:#c8c8c8;">get2DLength</span><span style="color:#b4b4b4;">(</span><span style="color:#c8c8c8;">vert</span><span style="color:#b4b4b4;">-></span><span style="color:#dadada;">x</span> <span style="color:#b4b4b4;">-</span> <span style="color:#7f7f7f;">center</span><span style="color:#b4b4b4;">.</span><span style="color:#dadada;">x</span><span style="color:#b4b4b4;">,</span> <span style="color:#c8c8c8;">vert</span><span style="color:#b4b4b4;">-></span><span style="color:#dadada;">y</span> <span style="color:#b4b4b4;">-</span> <span style="color:#7f7f7f;">center</span><span style="color:#b4b4b4;">.</span><span style="color:#dadada;">y</span><span style="color:#b4b4b4;">)</span> <span style="color:#b4b4b4;">-</span> <span style="color:#c8c8c8;">shift</span><span style="color:#b4b4b4;">);</span>
<span style="color:#b4b4b4;">}</span></pre>
<p>But since I'm a fan of the old 'train hard, fight easy' maxim, here it is with a bit more sensible loop variant – and to balance it out, a self-contained lambda that replaces the outer helper function. You should be able to make sense of this loop now that you've seen the previous one. Unlike the previous one, it doesn't have the problem that the <code>vert</code> variable would still be accessible outside the loop, pointing to a out-of-bounds garbage value should you ever come back to the function and extend it. The lambda is rather unremarkable, if it weren't for it being <code>static</code> – no problem here, but don't do this with capturing lambdas unless you want them to capture only once. Okay, that was enough confusion for today, the function works in both versions, and if you read through the whole post, you have earned a break.</p>
<p>In conclusion, Function Publishing is extremely flexible and powerful system, even if you only use it for a few critical functions and leave the rest to MAXScript and/or python. Don't be afraid to try it out and see for yourself. And most importantly, have fun!</p>
<div style="font-family: 'PT Sans',Verdana,sans-serif;font-size: 8pt">
<p>DISCLAIMER: All scripts and snippets are provided as is under <a href="http://creativecommons.org/publicdomain/zero/1.0/">Creative Commons Zero (public domain, no restrictions) license</a>. The author and this blog cannot be held liable for any loss caused as a result of inaccuracy or error within these web pages. Use at your own risk.</p></div>
Swordslayerhttp://www.blogger.com/profile/09124250713006663760noreply@blogger.com7tag:blogger.com,1999:blog-4212150079314071223.post-72284277693826078652019-05-26T19:28:00.000+02:002019-05-26T19:29:51.442+02:00Removing Controller with MAXScript<p>Since there's no built-in MAXScript function to remove controller once you add it to a parameter, here's a function to do that for you. Big thanks to Larry Minton for revealing how to handle ParamBlock2 PB2Values.</p>
<pre class="notranslate">
<code><span class="code-keywords1">fn</span> removeController subAnim <span class="code-symbol">=</span> <span class="code-keywords1">if</span> isKindOf subAnim <span class="code-symbol">::</span><span class="code-keywords2">SubAnim </span><span class="code-keywords1">and</span> <span class="code-keywords3">isController</span> subAnim<span class="code-symbol">.</span><span class="code-identifier">controller </span><span class="code-keywords1">do</span></code>
<code><span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> originalValue <span class="code-symbol">=</span> subAnim<span class="code-symbol">.</span><span class="code-identifier">value</span></code>
<code> <span class="code-keywords1">local</span> REFMSG_CONTROLREF_CHANGE <span class="code-symbol">=</span> <span class="code-number">0xFA</span></code>
<code></code>
<code> <span class="code-keywords1">if</span> <span class="code-keywords3">isKindOf</span> subAnim<span class="code-symbol">.</span><span class="code-identifier">parent</span> <span class="code-keywords2">ParamBlock2</span> <span class="code-keywords1">then</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> iGlobal <span class="code-symbol">=</span> <span class="code-symbol">(</span><span class="code-identifier">dotNetClass </span><span class="code-string">"Autodesk.Max.GlobalInterface"</span><span class="code-symbol">).</span><span class="code-identifier">Instance</span></code>
<code> <span class="code-keywords1">local</span> pBlockNET <span class="code-symbol">=</span> iGlobal<span class="code-symbol">.</span><span class="code-identifier">Animatable</span><span class="code-symbol">.</span><span class="code-identifier">GetAnimByHandle </span><span class="code-symbol">(</span><span class="code-keywords3">getHandleByAnim</span> <span class="code-identifier">subAnim</span><span class="code-symbol">.</span><span class="code-identifier">parent</span><span class="code-symbol">)</span></code>
<code> <span class="code-keywords1">local</span> pValNET <span class="code-symbol">=</span> pBlockNET<span class="code-symbol">.</span><span class="code-identifier">GetPB2Value </span><span class="code-symbol">(</span><span class="code-identifier">pBlockNET</span><span class="code-symbol">.</span><span class="code-identifier">IndexToId </span><span class="code-symbol">(</span><span class="code-identifier">subAnim</span><span class="code-symbol">.</span><span class="code-identifier">index </span><span class="code-symbol">-</span> <span class="code-number">1</span><span class="code-symbol">))</span> <span class="code-number">0</span></code>
<code></code>
<code> pValNET<span class="code-symbol">.</span><span class="code-identifier">Flags </span><span class="code-symbol">=</span> bit<span class="code-symbol">.</span><span class="code-identifier">or</span> pValNET<span class="code-symbol">.</span><span class="code-identifier">Flags </span><span class="code-number">0x40 </span><span class="code-comment">-- set the flag on the PB2Value which controls if the parameter is animated - this effectively removes the controller</span></code>
<code> <span class="code-symbol">)</span></code>
<code> <span class="code-keywords1">else</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> ctrl <span class="code-symbol">=</span> subAnim<span class="code-symbol">.</span><span class="code-identifier">controller</span></code>
<code> <span class="code-keywords1">local</span> parent <span class="code-symbol">=</span> subAnim<span class="code-symbol">.</span><span class="code-identifier">parent</span></code>
<code> <span class="code-keywords1">local</span> index <span class="code-symbol">=</span> <span class="code-keywords1">for</span> i <span class="code-symbol">=</span> <span class="code-number">1</span> <span class="code-keywords1">to</span> <span class="code-keywords3">refs</span><span class="code-symbol">.</span><span class="code-identifier">getNumRefs parent </span><span class="code-keywords1">where</span> <span class="code-keywords3">refs</span><span class="code-symbol">.</span><span class="code-identifier">getReference parent i </span><span class="code-symbol">==</span> ctrl <span class="code-keywords1">do</span> <span class="code-keywords1">exit</span> <span class="code-keywords1">with</span> i</code>
<code></code>
<code> <span class="code-keywords3">refs</span><span class="code-symbol">.</span><span class="code-identifier">replaceReference parent index </span><span class="code-keywords2">undefined</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords1">if</span> <span class="code-keywords3">classOf</span> subAnim<span class="code-symbol">.</span><span class="code-identifier">value </span><span class="code-symbol">==</span> <span class="code-keywords3">classOf</span> originalValue <span class="code-keywords1">do</span> subAnim<span class="code-symbol">.</span><span class="code-identifier">value </span><span class="code-symbol">=</span> originalValue</code>
<code> <span class="code-keywords3">notifyDependents</span> subAnim<span class="code-symbol">.</span><span class="code-identifier">parent msg</span><span class="code-symbol">:</span>REFMSG_CONTROLREF_CHANGE</code>
<code><span class="code-symbol">)</span></code>
</pre><a name='more'></a>
<p>A sample of usage shows how to remove a controller from a sphere's radius parameter:</p>
<pre class="notranslate">
<code><span class="code-keywords2">Sphere</span> <span class="code-identifier">radius</span><span class="code-symbol">:.</span><span class="code-number">5</span> isSelected<span class="code-symbol">:</span><span class="code-keywords1">on</span></code>
<code><span class="code-symbol">$.</span><span class="code-identifier">radius</span><span class="code-symbol">.</span><span class="code-identifier">controller </span><span class="code-symbol">=</span> Bezier_Float<span class="code-symbol">()</span></code>
<code><span class="code-identifier">removeController</span> <span class="code-symbol">$.</span><span class="code-identifier">baseObject</span><span class="code-symbol">[</span><span class="code-string">#radius</span><span class="code-symbol">]</span></code>
</pre>
<div style="font-family: 'PT Sans',Verdana,sans-serif;">
<p>DISCLAIMER: All scripts and snippets are provided as is under <a href="http://creativecommons.org/publicdomain/zero/1.0/">Creative Commons Zero (public domain, no restrictions) license</a>. The author and this blog cannot be held liable for any loss caused as a result of inaccuracy or error within these web pages. Use at your own risk.</p></div>Swordslayerhttp://www.blogger.com/profile/09124250713006663760noreply@blogger.com0tag:blogger.com,1999:blog-4212150079314071223.post-59715815288674639722017-10-09T20:12:00.000+02:002017-10-09T20:12:07.403+02:00KeyHydra WheelControl Customization<p>With the latest KeyHydra update comes the possibility to use scroll wheel in conjunction with modifier keys to control properties of primitives at creation time, as well as various editable/edit poly tool properties. There's a pretty straightforward UI configuration when you want to tweak the values and an .xml configuration file if you want to go beyond that and add your own presets.</p>
<a name='more'></a>
<p>You can find the <code>keyhydraWheelEvents.xml</code> config file in the <code>%USERPROFILE%\AppData\Local\Autodesk\3dsMax\%3DSMAXVER%\ENU\en-US\plugcfg</code> folder. The root element contains the <code>active</code> state which controls whether or not the events are loaded. All its contained children match the classes of objects whose properties you wish to control, with the exception of the epoly node that applies both to editable poly object and edit poly modifier. Let's have a look at the structure of the file:</p>
<img height="auto" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjO-Ls-lKZgE7_INTVZuhCCwhxMYa4a4yQt0ghq87RfPluOqgpV52E3FV1s4ez7CRaadJYLD2HHmut3BdWrwZiiEvk2i332IyO_P2lwD6buwhvjGURHFFTCODmQxKT3XFYLdhndSTUDJbk/s1600/xml.gif" width="500" />
<p>For example, the first <ngon>ngon</ngon> node binds ctrl+wheel rotation to changing the number of NGon sides:</p>
<pre class="notranslate">
<code><font color="#808080"><</font><font color="#569cd6">ngon</font> <font color="#9cdcfe">category</font><font color="#d4d4d4">=</font><font color="#ce9178">'Splines'</font><font color="#808080">></font></code>
<code> <font color="#808080"><</font><font color="#569cd6">action</font> <font color="#9cdcfe">id</font><font color="#d4d4d4">=</font><font color="#ce9178">'Create'</font> <font color="#9cdcfe">subcategory</font><font color="#d4d4d4">=</font><font color="#ce9178">'Standard'</font><font color="#808080">></font></code>
<code> <font color="#808080"><</font><font color="#569cd6">ctrl</font><font color="#808080">></font></code>
<code> <font color="#808080"><</font><font color="#569cd6">attrib</font><font color="#808080">></font><font color="#d4d4d4">nsides</font><font color="#808080"></</font><font color="#569cd6">attrib</font><font color="#808080">></font></code>
<code> <font color="#808080"><</font><font color="#569cd6">lowerLimit</font><font color="#808080">></font><font color="#d4d4d4">3</font><font color="#808080"></</font><font color="#569cd6">lowerLimit</font><font color="#808080">></font></code>
<code> <font color="#808080"><</font><font color="#569cd6">upperLimit</font><font color="#808080">></font><font color="#d4d4d4">100</font><font color="#808080"></</font><font color="#569cd6">upperLimit</font><font color="#808080">></font></code>
<code> <font color="#808080"><</font><font color="#569cd6">increment</font><font color="#808080">></font><font color="#d4d4d4">1</font><font color="#808080"></</font><font color="#569cd6">increment</font><font color="#808080">></font></code>
<code> <font color="#808080"></</font><font color="#569cd6">ctrl</font><font color="#808080">></font></code>
<code> <font color="#808080"></</font><font color="#569cd6">action</font><font color="#808080">></font></code>
<code><font color="#808080"></</font><font color="#569cd6">ngon</font><font color="#808080">></font></code>
</pre>
Here's how you would create it from scratch:<br>
<ul>
<li>To find the class name, call <code>classOf $</code> in the Listener with you primitive object selected (can be any primitive, geometry, ligh, helper, shape etc.). The category description determines what tab the action will appear under in the UI.</li>
<li>Next line, the action id <code>'Create'</code>, means the action applies on creation time (for primitives, there are no other actions, there are more for editable poly), and the subcategory is once again the name of the UI specific section for the item.</li>
<li>Inside the action node you assign the <code>ctrl</code>, <code>alt</code> or <code>shift</code> modifier keys to the desired properties.</li>
<li>To get the attrib name, list properties of you selected object by running <code>show $</code> in the listener and picking the one you want, or by activating macrorecorder, changing the value and noting the recorded property. Only numerical properties are supported. The <code>increment</code> value controls the amount by which the value will change with each wheel up/down event, <code>lowerLimit</code> and <code>upperLimit</code> set the bounds for the value.</li>
</ul>
<p>For editable poly and edit poly properties, there are predefined actions that you can configure and remove but you cannot add more of them. They are applied depending on which command is currently active or was active right before turning the mousewheel.</p>
<p>You might have noticed that in some cases, there are more property names with <code>+</code> sign inbetween. This way, you can change multiple properties at once:</p>
<img height="auto" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinF-DZznlttX8NXNOisBY0b1bvIrsWNwrB_tuAuk1UoBEbEwMNIPRsbxQcZqF0gMEOWerFr4B1iX1w3qYo6nwvP4qvEh23-pRPj3YqvfkULjoJvzOUGz9mvVECnqVCgJ4Yd6nFz-6uEJA/s1600/40_ControlMultiParamAtOnce.gif" width="500" />
<p>You can also use screen units instead of fixed increment/limits where it makes sense, using the px suffix. That way, the values will be different depending on current viewport zoom level:</p>
<img height="auto" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjA8vABFLNllJ-9vklaRCcrpcP-gFr6PBvezbe3WYNwymXT38yhQcVj_slBRJdATOQ6nmzCzX2MAKn6kmYEjnwLctl9Ao-HTctr4G_dKg8Vhey-vy_3sfc92GYXU6ILrlCUO3ucGDMWN8A/s1600/10_WorldUnit_vs_ScreenUnit.gif" width="500" />
<p>As usual, before editing the file, make a backup copy in case something goes wrong. Have fun!</p>
<div style="font-family: 'PT Sans',Verdana,sans-serif;">
<p>DISCLAIMER: All scripts and snippets are provided as is under <a href="http://creativecommons.org/publicdomain/zero/1.0/">Creative Commons Zero (public domain, no restrictions) license</a>. The author and this blog cannot be held liable for any loss caused as a result of inaccuracy or error within these web pages. Use at your own risk.</p></div>Swordslayerhttp://www.blogger.com/profile/09124250713006663760noreply@blogger.com0tag:blogger.com,1999:blog-4212150079314071223.post-38376077767022922832017-08-03T17:18:00.000+02:002018-05-14T11:26:15.906+02:00KeyHydra LazerCutI am happy to share a tool that's nearing release now: <a href="https://www.onikanabo.com/lazercut">LazerCut</a>, part of the <a href="https://www.onikanabo.com/keyhydra">KeyHydra</a> package (see also the <a href="http://polycount.com/discussion/comment/2565190/#Comment_2565190">polycount discussion</a>). It provides an interactive boolean workflow inside 3ds max using the object manipulation tools everyone is used to, without ever having to go to the boolean subobjects and settings:<br /><br />
<img height="auto" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjL13o8PAKKZLE2jURxmu2hpi5fHuz_OtCHdprfxkG0pytkiMYyCI-eblJJDME0p7QBmw3N9EsxZN6VnkuMkUL0yTmswaRG1e7_ruSG_4Y8gQJktyKYutVGBmiVB6LxodgV1nbpE8DnsHE/s1600/01_LazerCutOverview.gif" width="500" />
<br /><br />The cutters can be created in any view, perpective, orthogonal, camera etc. Depending on the current mode, they can be used to split the selected geometry, add to it, subtract from it or create independent objects. Since all the cutters (with the exception of multi-object subtractions) are created in a separate layer as children of the object operated on, you can easily select those relevant to the object with PgDn, or unhide them using <code>unhide $.children</code>.<br />
<a name='more'></a>
<br /><div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Subtract Mode</div>
Unlike Union, Subtraction can be done on multiple selected objects at the same time - in that case, the cutter is not parented to the original object and they all stay independent. You can add any modifiers to the cutter object, shown in the gif is a basic clone modifier. If you want to keep everything procedural, radial symmetry and other similar modifiers offer even more ways to extend the possibilites.<br /><br />
<img height="auto" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj633wdt36q1J6AGB3lugv3PgwC6enSnk3zpHC-Dv0C_rxT37bCiEHWqMfRR_J3OyjMRZuI31VIVrbMBbu_YLMs_jKEdUCSERY4mD69FhlLVeDUDy8bRPIucEyio6o8HcGuEdN2GypQkxY/s1600/02_Subtraction.gif" width="500" />
<br /><br /><div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Split Mode</div>
In the Split operation case, cutters are parented to the object they are subtracted from and the newly created subtracted part is independent:<br /><br />
<img height="auto" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNV643WiEEerL4dGqi8fN3mdKpDqJ26zppACPnhDNiR8DvwgS3nU6ZXeQX2zofWMxXJRTHgp7_Y-5L_lj7pkzPqPM7VB9hfFeZqYq8QrqSruCn4EZGx1DYNLKkN51b6XG_w8KuYS6x3Kw/s1600/03_Splitting.gif" width="500" />
<br /><br /><div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Multiple Cuts</div>
The default cutting mode uses current selection as the object to cut. If you want to keep cutting a single source object, change the Source Geometry mode to Scene Node instead of Selection:<br /><br />
<img height="auto" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmZX99d-MC2vwCOWE9OMur38yPeD2zaxGAr24O194WRVHgKyds6mCAQQbAavNRjRKI4qJSKGsT4qoQAU0QQjzvjAr2urOKEY-2Hy9ybV-8AW1l6L-UHGmwYaU-FljJRzmNZx-FpbyQtkI/s1600/lazercut_update.gif" width="500" />
<br /><br /><div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Manipulating Cutters</div>
To speed up the workflow, you might want to turn off the Manipulate checkbox. When inactive, the created cutters are left hidden and unselected. You can always unhide them later and change any of the properties, from segment count to projection direction and cutter height.<br /><br />
If the Revert checkbutton is pressed, manipulate mode stays only active right after the cutter is created, and is deactivated once the selection changes. If you want to change the fillets or move the cutter segments and vertices, you can activate the Select and Manipulate mode in the main max toolbar. It's the leftmost icon on the toolbar in the following gif:<br /><br />
<img height="auto" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSsjiHCY0omPksLrkDIoWpnGSeTsYFjcpxfoQW-jgDGT36T7fdUbyMROQZ6wYwwdpZsRx3oesM4ym_KxlYvOjOH7ne4ucmb6ztsR8ViSbGEaZgzuDRpJ2ne7ff7dR2v33CGZ_mKIjA8yA/s1600/04_Manipulate.gif" width="500" /><br />
<br />There are three manipulator types for all the cutter nodes. First one is the <i>vertex</i>, marked by the small cross, and you can either move it freely in the construction plane of the cutter or constrain the movement to X and Y axis in the cutter's local coordsys by pressing SHIFT while dragging it.<br /><br />
Then there is the square <i>segment</i> marker. In addition to the X/Y SHIFT constraint you can also use CTRL to move its point together/apart (in effect scaling it) and CTRL+SHIFT to slide its points along the segment.<br /><br />
The thrid one is the circular <i>fillet</i> manipulator. You can select several of them by CTRL+clicking them, dragging them apart from the node pivot increases the fillet radius, dragging them toward it makes it smaller. The fillets are further controlled by the segment count and weld threshold in the cutter object parameters.<br /><br />
<img height="auto" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDAI36jBXIrnkoiQUJPGkri6opYOk_vfDPnrN-GRVeRpOchv2QcfXxpukEQN0ozU53AbnURn1d835WE7ixN0x-6-XxWTvmnzVKoEAs5E7BtFFeoYWr2OVyCQNZggwI7_U0qOf41HH5xXo/s1600/05_Manipulators.gif" width="500" /><br />
When manipulating fillets, you can use SHIFT while dragging to force snapping to values (uses spinner snap value found in the general preferences). SHIFT-clicking a fillet brings up an input dialog where you can find the current value for the clicked fillet and input your own value (this will apply to all the selected fillets).<br /><br />
<img height="auto" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFHoSyBu0bVvObjWJOgLI3chNU9EPrEElu3QkE25qbk5PCiYjMqhQhJ-oZXFi-ejyU7wg-_zStVJVP0kxGgUconU6RkMufaBav1qy23TPusOdo9nKWb4oHuaZH1g-1GmH8ifG491Fueps/s1600/12_FilletSnap.gif" width="500" /><br />
<br />Both during the cutter creation process and while manipulating them, you can use max snap mode. For the creation process, it has to be active before entering it.<br /><br />
<img height="auto" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUZS6yvkNHMAaEIhZSi2LKGja80oMIbd0CG5pZuF4wF27kECMKyb7XvBTi9Sy-8e8QHOVgbJXzydsObIXuxHb6kXIyuEsZ3HXrNpvhku968xZb4w_vPStyc1LJeXRo-hS6vL2tAID1zpU/s1600/06_SnapCutters.gif" width="500" /><br />
<br />The cutters are automatically aligned based on the current active alignment mode. For subtraction and splitting, safe bounding box makes sure that the cutter will extend past the selection to avoid overlapping faces which can be a problem with booleans. You might want to use exact bounding box in the create mode, when matching other objects.<br /><br />
There's also construction plane, which goes through the closest point of the selected object in the active view, and another one that goes through world origin. In these two modes, you have to specify the cutter height yourself, and you can also add an offset value. All these values are saved across sessions and can be different for all the cutter modes.<br /><br />
<img height="auto" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqOgLouYz6VcEbiek3nl7s2R0oIuk3lmAjpTd7FeXKHpt2A9lgCRTIPxeSvnEdkAHI4KFd14F0phXQfViQZvSo_fgk1SkreGJwT2W5IfJqdBbCYrx0QEylT8qkWVrtAXNnj3bfw58EEqE/s1600/07_Alignment.gif" width="500" /><br />
You might have noticed that when created in the perspective view, the cutter shape is projected from the camera viewpoint. Sometimes, this might not be desirable and instead parellel edges would be preferred. For these cases, there are Directional and Ortho types of projection. Directional keeps the projection direction, ortho makes the cutter edges perpendicular to the construction plane.<br /><br />
<img height="auto" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9mPlElYuRb9M-VxVo81lFeEv6hGP8TAEf4oBHgEigBKWRM4k3oCrVGXI6YXOtXe_PqzCwJijm19GHyXRFT4QAXSrcGuPY4z37-vusYMZ78iyGsIJQZTXFzS-BDcjWPawdndfbyHAqmDE/s1600/parameters.gif" width="500" />
<br /><br /><div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Cutter Types</div>
The Rectangle cutter creates a parametric cutter box. When holding SHIFT, the base will be always square. Holding CTRL treats the first point as a center rather than a corner point. Both these modes can be combined when holding SHIFT+CTRL.<br /><br />
<img height="auto" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQsQ8TXKA2kOjzrfj1t6KU2kVSwB9ZOhDQeem14qqrstBSkhR9Wm8eL2KBzR4TRH7v5jI4b8eIU2lch9wqi9Wqh0OOxx57hU40KR9IRg19PRFJB6Hzs4NC0IZxuzODsnL6Tgsug_V9OMw/s1600/08_BoxCutter.gif" width="500" /><br />
The Circle cutter is created with fillet points along the X and Y axes by default. This is shown by the small × mark on the circle while dragging. When SHIFT is pressed, the positions are rotated 45 degrees which is handy when using it to cut slots; in that case, extending to the oblong shape is done holding SHIFT while dragging one of the segments, as shown in the following gif:<br /><br />
<img height="auto" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFq4hJyleSwDoKLxPVbrL8bwFuhMvluPAP1FNixlp1qgefxG03cia-IpCfgaqPf7JP4YlxJ1HFeyP5_eQJlHriMQp0ru9VnNJCEGvlWxFFCnJqCr8Fc-BbPU-pn2Z3g6eVb_k5HOL7rTs/s1600/09_CircleCutter.gif" width="500" /><br />
The NGon cutter is similar to Circle. Holding SHIFT locks the rotation to use increments the angle snap value (Grid and Snap Settings). CTRL-dragging along the bounding circle drives the number of segments.<br /><br />
<img height="auto" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5P459BCWbWxPIa4-A9A3V5jBGUnPHx5DK4z_Hbp3pVYXK0HiR4qmn0yJ8cuT7RXmaOeoJzAb_uLm_3OPAyvZ5N1JM8NAVBi9Onnz-UaX5Yx0MSMSTzgGfIp4aOxWjDnOaaQqYRhTkybM/s1600/10_ngonCutter.gif" width="500" /><br />
Unlike the other cutters, you don't have to keep the mouse button pressed to draw the PolyLine cutter, you can directly click the points along the path. When dragging, holding SHIFT locks the segment orientation in increments of 45 degrees. Pressing backspace removes last inserted point just like with splines. When clicking over the first point, you're presented with dialog asking if you want to close the PolyLine.<br /><br />
<img height="auto" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUBARvSVFuNb5ukSMvcqGt7T2dBrGvxpBvXu4eyhN8UWZBb97PsqxPq1p2c_aaVhffkOzMcZjehK3_fX-d7fz0KhgPdBg37DLLmSqv2e_yyYHfO31HM8xn8CfJ0poVop47ZLMRe-dyGIA/s1600/11_PolylineCutter.gif" width="500" /><br /><br />
<div style="font-family: 'PT Sans',Verdana,sans-serif;">Known issues: repeating undo multiple times might cause instability in some cases. Haven't had the issues outside of stress-testing it, but still something to bear in mind.</div>Swordslayerhttp://www.blogger.com/profile/09124250713006663760noreply@blogger.com0tag:blogger.com,1999:blog-4212150079314071223.post-23840907087952548182017-05-15T17:22:00.001+02:002019-12-07T13:44:02.839+01:00Undocumented MAXScript Features<p>Every now and then, I stumbled upon an undocumented command or optional keyword. Some of them were later added to the documentation, many of them are still undocumented. Some of those are listed in this article (I'm skipping a lot of stuff I don't find useful like the non-creatable MEditBkgnd texture map, creatable PFlow related classes etc).</p><a name='more'></a>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Box3 Values</div>
Just like the documented Box2 class, only in 3D. Pretty handy, using <code>Box3</code> returned by the <code>getNodeBBox</code> method is much more flexible than the min+max array that's usually used instead. Edit: now documented, see <a href="https://knowledge.autodesk.com/search-result/caas/CloudHelp/cloudhelp/2018/ENU/MAXScript-Help/files/GUID-2921953D-F655-4663-B243-2E8DAFEED15F-htm.html">Box3 Values</a>.<br /><br />
<div style="font-size: 9pt; font-weight: bold;">Constructor</div>
<pre class="notranslate"><code><span class="code-keywords4">Box3</span><span class="code-symbol">()</span> <span class="code-comment">-- returns new 'empty' Box3 value</span></code>
<code><span class="code-keywords4">Box3</span> <span class="code-symbol"><</span><span class="code-identifier">min_point3</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">max_point3</span><span class="code-symbol">></span></code></pre>
<div style="font-size: 9pt; font-weight: bold;">Properties</div>
<pre class="notranslate"><code><span class="code-symbol"><</span><span class="code-keywords4">Box3</span><span class="code-symbol">></span><span class="code-symbol">.</span><span class="code-identifier">min</span><span class="code-symbol">:</span> <span class="code-comment">Point3</span></code>
<code><span class="code-symbol"><</span><span class="code-keywords4">Box3</span><span class="code-symbol">></span><span class="code-symbol">.</span><span class="code-identifier">max</span><span class="code-symbol">:</span> <span class="code-comment">Point3</span></code>
<code><span class="code-symbol"><</span><span class="code-keywords4">Box3</span><span class="code-symbol">></span><span class="code-symbol">.</span><span class="code-identifier">center</span><span class="code-symbol">:</span> <span class="code-comment">Point3</span></code></pre>
<div style="font-size: 9pt; font-weight: bold;">Methods</div>
<table cellpadding="0" cellspacing="0" style="margin:16px 40px 22px 5px; padding:5px 10px 10px 5px; width:530px; table-layout:fixed;">
<tr>
<td align="left" valign="top" width="45%" style="border-right:none;">
<pre class="notranslate" style="border-right:none;"><span class="code-keywords3">contains</span> <span class="code-symbol"><</span><span class="code-keywords4">Box3</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">point3</span><span class="code-symbol">></span></br>
<span class="code-keywords3">intersects</span> <span class="code-symbol"><</span><span class="code-keywords4">Box3</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-keywords4">Box3</span><span class="code-symbol">></span></br></br>
<span class="code-keywords3">translate</span> <span class="code-symbol"><</span><span class="code-keywords4">Box3</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">point3</span><span class="code-symbol">></span></br>
<span class="code-keywords3">scale</span> <span class="code-symbol"><</span><span class="code-keywords4">Box3</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">point3</span><span class="code-symbol">></span></br>
<span class="code-keywords3">enlargeBy</span> <span class="code-symbol"><</span><span class="code-keywords4">Box3</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">float</span><span class="code-symbol">></span></br></br>
<span class="code-keywords3">rectify</span> <span class="code-symbol"><</span><span class="code-keywords4">Box3</span><span class="code-symbol">></span></br>
<span class="code-keywords3">makeCube</span> <span class="code-symbol"><</span><span class="code-keywords4">Box3</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">point3</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">float</span><span class="code-symbol">></span></br></br>
<span class="code-keywords3">empty</span> <span class="code-symbol"><</span><span class="code-keywords4">Box3</span><span class="code-symbol">></span></br>
<span class="code-keywords3">isEmpty</span> <span class="code-symbol"><</span><span class="code-keywords4">Box3</span><span class="code-symbol">></span></br></br>
<span class="code-keywords3">getNodeBBox</span> <span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span></br>
<span class="code-keywords3">getModContextBBox</span> <span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">modifier</span><span class="code-symbol">></span>
</pre></td>
<td align="left" valign="top" width="55%" style="border-left:none;">
<pre class="notranslate" style="border-left:none;">
<span class="code-comment">-- bool test for contained position</span></br>
<span class="code-comment">-- bool test for overlapping boxes</span></br></br>
<span class="code-comment">-- move box coords by offset</span></br>
<span class="code-comment">-- scale from the center of the box</span></br>
<span class="code-comment">-- expand box coords by offset</span></br></br>
<span class="code-comment">-- doesn't work</span></br>
<span class="code-comment">-- cube by center and size</span></br></br>
<span class="code-comment">-- set the box to a special 'empty' state</span></br>
<span class="code-comment">-- bool test for the special 'empty' state</span></br></br>
<span class="code-comment">-- node bounding box as a Box3 value</span></br>
<span class="code-comment">-- modContext bounding box as a Box3 value</span>
</pre></td></tr>
</table>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Missing Render Dialog Variables</div>
The following variables are missing from the <a href="http://help.autodesk.com/cloudhelp/2018/ENU/MAXScript-Help/files/GUID-30AF1E53-5A69-402D-84D6-4D6ECCDD6D20.htm">Render Scene Dialog</a> Global System Variables listing.
<pre class="notranslate"><code><span class="code-identifier">rendLockImageAspectRatio</span><span class="code-symbol">:</span> <span class="code-comment">Boolean</span></code>
<code><span class="code-identifier">rendImageAspectRatio</span><span class="code-symbol">:</span> <span class="code-comment">Float</span></code>
<code><span class="code-identifier">rendPixelAspectRatio</span><span class="code-symbol">:</span> <span class="code-comment">Float</span></code>
<code><span class="code-identifier">rendUseImgSeq</span><span class="code-symbol">:</span> <span class="code-comment">Boolean</span></code>
<code><span class="code-identifier">rendImgSeqType</span></code><span class="code-symbol">:</span> <span class="code-comment">Integer</span></code>
<code><span class="code-identifier">rendViewID</span></code><span class="code-symbol">:</span> <span class="code-comment">Integer</span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Multiplier Curve and Ease Curve Access</div>
Edit: now documented, see <a href="https://knowledge.autodesk.com/search-result/caas/CloudHelp/cloudhelp/2018/ENU/MAXScript-Help/files/GUID-2184B9B7-716F-4CFB-A7A6-E121DB24B08A-htm.html">Controller Ease and Multiplier Curves</a>.
<pre class="notranslate"><code><span class="code-keywords3">getMultiplierCurve</span> <span class="code-symbol"><</span><span class="code-identifier">controller</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">index</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">getEaseCurve</span> <span class="code-symbol"><</span><span class="code-identifier">controller</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">index</span><span class="code-symbol">></span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">High-precision Matrix Inverse</div>
Used for example by the CreateCameraFromView function.
<pre class="notranslate"><code><span class="code-keywords3">inverseHighPrecision</span> <span class="code-symbol"><</span><span class="code-identifier">matrix3</span><span class="code-symbol">></span></code></pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Xref Scene Overlay</div>
As mentioned by Eric Craft in the <a href="http://forums.cgsociety.org/showpost.php?p=8310738&postcount=4">Undocumented MAXScript Features</a> thread.
<pre class="notranslate"><code><span class="code-symbol"><</span><span class="code-keywords3">XRefScene</span><span class="code-symbol">>.</span>overlay <span class="code-identifier">Boolean</span> <span class="code-comment">default:false</span></code></pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Primitive -> BodyObject Conversion</div>
Sphere, Torus, Cylinder etc. convert nicely, Teapot doesn't.
<pre class="notranslate"><code><span class="code-keywords3">convertToBody</span> <span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">convertToJoinBodies</span> <span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">convertToBodyCutter</span> <span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Editable Poly Current CommandMode</div>
See the corresponding method in the <a href="http://help.autodesk.com/cloudhelp/2018/ENU/MAXScript-Help/files/GUID-9CA2E6DA-08C2-4279-87C9-B64351C0147E.htm">Edit Poly</a> chapter.
<pre class="notranslate"><code><span class="code-symbol"><</span><span class="code-identifier">enum</span><span class="code-symbol">></span><span class="code-symbol"><</span><span class="code-keywords4">EditablePoly</span><span class="code-symbol">></span><span class="code-symbol">.</span>getCommandMode<span class="code-symbol">()</span></code></pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Edit Poly Ready to Bridge</div>
Similar to <code><EditablePoly>.ReadyToBridgeFlagged()</code>, only for Edit Poly modifier.
<pre class="notranslate">
<code><span class="code-keywords3">editPolyModReadyToBridge</span><span class="code-symbol">()</span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Edit Poly Methods</div>
A categorized index of some of these with descriptions and sample code is available on the <a href="http://www.illusioncatalyst.com/3dsmax_files/snippets/edit_poly_undoc.php">IllusionCatalyst website</a>. For sample usage and a wrapper in the style of polyop methods, see the <a href="http://www.scriptspot.com/3ds-max/scripts/polymodop">polyModOp struct</a>.
<pre class="notranslate" style="height: 400px;">
<code><span class="code-symbol"><</span><span class="code-identifier">void</span><span class="code-symbol">></span><span class="code-keywords3">setVert</span> <span class="code-symbol"><</span><span class="code-identifier">&bitArray</span><span class="code-symbol">></span>vertSet <span class="code-symbol"><</span><span class="code-identifier">&point3</span><span class="code-symbol">></span>point node<span class="code-symbol">:</span><span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span></code>
<code></code>
<code><span class="code-symbol"><</span><span class="code-identifier">void</span><span class="code-symbol">></span><span class="code-keywords3">getVertsUsingFace</span> <span class="code-symbol"><</span><span class="code-identifier">&bitArray</span><span class="code-symbol">></span>vertSet <span class="code-symbol"><</span><span class="code-identifier">&bitArray</span><span class="code-symbol">></span>faceSet node<span class="code-symbol">:</span><span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">void</span><span class="code-symbol">></span><span class="code-keywords3">getVertsUsingEdge</span> <span class="code-symbol"><</span><span class="code-identifier">&bitArray</span><span class="code-symbol">></span>vertSet <span class="code-symbol"><</span><span class="code-identifier">&bitArray</span><span class="code-symbol">></span>edgeSet node<span class="code-symbol">:</span><span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">void</span><span class="code-symbol">></span><span class="code-keywords3">getFacesUsingEdge</span> <span class="code-symbol"><</span><span class="code-identifier">&bitArray</span><span class="code-symbol">></span>faceSet <span class="code-symbol"><</span><span class="code-identifier">&bitArray</span><span class="code-symbol">></span>edgeSet node<span class="code-symbol">:</span><span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">void</span><span class="code-symbol">></span><span class="code-keywords3">getEdgesUsingVert</span> <span class="code-symbol"><</span><span class="code-identifier">&bitArray</span><span class="code-symbol">></span>edgeSet <span class="code-symbol"><</span><span class="code-identifier">&bitArray</span><span class="code-symbol">></span>vertSet node<span class="code-symbol">:</span><span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">void</span><span class="code-symbol">></span><span class="code-keywords3">getFacesUsingVert</span> <span class="code-symbol"><</span><span class="code-identifier">&bitArray</span><span class="code-symbol">></span>faceSet <span class="code-symbol"><</span><span class="code-identifier">&bitArray</span><span class="code-symbol">></span>vertSet node<span class="code-symbol">:</span><span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">void</span><span class="code-symbol">></span><span class="code-keywords3">getElementsUsingFace</span> <span class="code-symbol"><</span><span class="code-identifier">&bitArray</span><span class="code-symbol">></span>elementSet <span class="code-symbol"><</span><span class="code-identifier">&bitArray</span><span class="code-symbol">></span>faceSet <span class="code-symbol"><</span><span class="code-identifier">&bitArray</span><span class="code-symbol">></span>fenceSet node<span class="code-symbol">:</span><span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span></code>
<code></code>
<code><span class="code-symbol"><</span><span class="code-identifier">point3 by value</span><span class="code-symbol">></span><span class="code-keywords3">GetFaceNormal</span> <span class="code-symbol"><</span><span class="code-identifier">index</span><span class="code-symbol">></span>faceID node<span class="code-symbol">:</span><span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">point3 by value</span><span class="code-symbol">></span><span class="code-keywords3">GetFaceCenter</span> <span class="code-symbol"><</span><span class="code-identifier">index</span><span class="code-symbol">></span>faceID node<span class="code-symbol">:</span><span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">float</span><span class="code-symbol">></span><span class="code-keywords3">GetFaceArea</span> <span class="code-symbol"><</span><span class="code-identifier">index</span><span class="code-symbol">></span>faceID node<span class="code-symbol">:</span><span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">bitArray</span><span class="code-symbol">></span><span class="code-keywords3">GetOpenEdges</span> node<span class="code-symbol">:</span><span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span></code>
<code></code>
<code><span class="code-symbol"><</span><span class="code-identifier">integer</span><span class="code-symbol">></span><span class="code-keywords3">getVertexFlags</span> <span class="code-symbol"><</span><span class="code-identifier">index</span><span class="code-symbol">></span>vertexID node<span class="code-symbol">:</span><span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">integer</span><span class="code-symbol">></span><span class="code-keywords3">getEdgeFlags</span> <span class="code-symbol"><</span><span class="code-identifier">index</span><span class="code-symbol">></span>edgeID node<span class="code-symbol">:</span><span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">integer</span><span class="code-symbol">></span><span class="code-keywords3">getFaceFlags</span> <span class="code-symbol"><</span><span class="code-identifier">index</span><span class="code-symbol">></span>faceID node<span class="code-symbol">:</span><span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">void</span><span class="code-symbol">></span><span class="code-keywords3">setVertexFlags</span> <span class="code-symbol"><</span><span class="code-identifier">&bitArray</span><span class="code-symbol">></span>vertexSet <span class="code-symbol"><</span><span class="code-identifier">DWORD</span><span class="code-symbol">></span>flagsToSet flagMask<span class="code-symbol">:</span><span class="code-symbol"><</span><span class="code-identifier">DWORD</span><span class="code-symbol">></span> generateUndoRecord<span class="code-symbol">:</span><span class="code-symbol"><</span><span class="code-identifier">bool</span><span class="code-symbol">></span> node<span class="code-symbol">:</span><span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">void</span><span class="code-symbol">></span><span class="code-keywords3">setEdgeFlags</span> <span class="code-symbol"><</span><span class="code-identifier">&bitArray</span><span class="code-symbol">></span>edgeSet <span class="code-symbol"><</span><span class="code-identifier">DWORD</span><span class="code-symbol">></span>flagsToSet flagMask<span class="code-symbol">:</span><span class="code-symbol"><</span><span class="code-identifier">DWORD</span><span class="code-symbol">></span> generateUndoRecord<span class="code-symbol">:</span><span class="code-symbol"><</span><span class="code-identifier">bool</span><span class="code-symbol">></span> node<span class="code-symbol">:</span><span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">void</span><span class="code-symbol">></span><span class="code-keywords3">setFaceFlags</span> <span class="code-symbol"><</span><span class="code-identifier">&bitArray</span><span class="code-symbol">></span>faceSet <span class="code-symbol"><</span><span class="code-identifier">DWORD</span><span class="code-symbol">></span>flagsToSet flagMask<span class="code-symbol">:</span><span class="code-symbol"><</span><span class="code-identifier">DWORD</span><span class="code-symbol">></span> generateUndoRecord<span class="code-symbol">:</span><span class="code-symbol"><</span><span class="code-identifier">bool</span><span class="code-symbol">></span> node<span class="code-symbol">:</span><span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">bool</span><span class="code-symbol">></span><span class="code-keywords3">getVerticesByFlag</span> <span class="code-symbol"><</span><span class="code-identifier">&bitArray</span><span class="code-symbol">></span>vertexSet <span class="code-symbol"><</span><span class="code-identifier">DWORD</span><span class="code-symbol">></span>flagsRequested flagMask<span class="code-symbol">:</span><span class="code-symbol"><</span><span class="code-identifier">DWORD</span><span class="code-symbol">></span> node<span class="code-symbol">:</span><span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">bool</span><span class="code-symbol">></span><span class="code-keywords3">getEdgesByFlag</span> <span class="code-symbol"><</span><span class="code-identifier">&bitArray</span><span class="code-symbol">></span>edgeSet <span class="code-symbol"><</span><span class="code-identifier">DWORD</span><span class="code-symbol">></span>flagsRequested flagMask<span class="code-symbol">:</span><span class="code-symbol"><</span><span class="code-identifier">DWORD</span><span class="code-symbol">></span> node<span class="code-symbol">:</span><span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">bool</span><span class="code-symbol">></span><span class="code-keywords3">getFacesByFlag</span> <span class="code-symbol"><</span><span class="code-identifier">&bitArray</span><span class="code-symbol">></span>faceSet <span class="code-symbol"><</span><span class="code-identifier">DWORD</span><span class="code-symbol">></span>flagsRequested flagMask<span class="code-symbol">:</span><span class="code-symbol"><</span><span class="code-identifier">DWORD</span><span class="code-symbol">></span> node<span class="code-symbol">:</span><span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span></code>
<code></code>
<code><span class="code-symbol"><</span><span class="code-identifier">bool</span><span class="code-symbol">></span><span class="code-keywords3">SmGrpFloaterVisible</span><span class="code-symbol">()</span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">void</span><span class="code-symbol">></span><span class="code-keywords3">SmGrpFloater</span><span class="code-symbol">()</span></code>
<code></code>
<code><span class="code-symbol"><</span><span class="code-identifier">bool</span><span class="code-symbol">></span><span class="code-keywords3">MatIDFloaterVisible</span><span class="code-symbol">()</span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">void</span><span class="code-symbol">></span><span class="code-keywords3">MatIDFloater</span><span class="code-symbol">()</span></code>
<code></code>
<code><span class="code-symbol"><</span><span class="code-identifier">void</span><span class="code-symbol">></span><span class="code-keywords3">CommitPaintDeform</span><span class="code-symbol">()</span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">void</span><span class="code-symbol">></span><span class="code-keywords3">CancelPaintDeform</span><span class="code-symbol">()</span></code>
</pre>
<p>There's also a method that's listed with no description:</p>
<pre class="notranslate">
<code><span class="code-symbol"><</span><span class="code-identifier">void</span><span class="code-symbol">></span><span class="code-keywords3">List</span> node<span class="code-symbol">:</span><span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span></code>
</pre>
<p>It outputs the complete printout of the operations stored by the Edit Poly into the Macro Recorder window. To use it, open the MAXScript Listener window, make sure Macro Recorder is active, and with the Edit Poly modifier active in the stack run:</p>
<pre class="notranslate">
<span class="code-symbol">(</span><span class="code-keywords3">modPanel</span><span class="code-symbol">.</span>getCurrentObject<span class="code-symbol">()).</span><span class="code-keywords3">List</span><span class="code-symbol">()</span>
</pre>
<p>An example printout in the MacroRecorder window might look like this:</p>
<pre class="notranslate" style="height: 250px;background:#1e1e1e;">
<i>-- Describing all Edit Poly Operations:</i>
subobjectLevel = 2
$.modifiers[#Edit_Poly].SetSelection #Edge #{1, 5, 13, 20, 25, 29, 35, 40, 44, 50, 56, 59, 64, 70, 74, 77, 83, 88, 93, 96, 99, 104, 107, 110, 141, 145, 149, 152, 159, 163, 166..167}
$.modifiers[#Edit_Poly].extrudeEdgeHeight = 1.8
$.modifiers[#Edit_Poly].extrudeEdgeWidth = 0.49
$.modifiers[#Edit_Poly].ButtonOp #ExtrudeEdge
subobjectLevel = 2
$.modifiers[#Edit_Poly].SetSelection #Edge #{1, 5, 13, 20, 25, 29, 35, 40, 44, 50, 56, 59, 64, 70, 74, 77, 83, 88, 93, 96, 99, 104, 107, 110, 141, 145, 149, 152, 159, 163, 166..167}
$.modifiers[#Edit_Poly].chamferEdgeAmount = 1
$.modifiers[#Edit_Poly].chamferEdgeOpen = off
$.modifiers[#Edit_Poly].edgeChamferSegments = 1
$.modifiers[#Edit_Poly].edgeChamferTension = 0.5
$.modifiers[#Edit_Poly].edgeChamferInvert = off
$.modifiers[#Edit_Poly].edgeChamferType = 0
$.modifiers[#Edit_Poly].edgeChamferSmooth = off
$.modifiers[#Edit_Poly].edgeChamferSmoothType = 0
$.modifiers[#Edit_Poly].edgeChamferSmoothThreshold = 30
$.modifiers[#Edit_Poly].edgeChamferQuadIntersections = off
$.modifiers[#Edit_Poly].ButtonOp #ChamferEdge
subobjectLevel = 1
$.modifiers[#Edit_Poly].SetSelection #Vertex #{1, 3, 5, 7, 15, 22, 24, 26..28, 30, 33, 36, 39, 41..42, 45..46, 49..50, 53, 56, 60, 70, 77..78, 80..81, 84..85, 91, 94, 163..194}
$.modifiers[#Edit_Poly].relaxAmount = 0.5
$.modifiers[#Edit_Poly].relaxIterations = 5
$.modifiers[#Edit_Poly].relaxHoldBoundaryPoints = off
$.modifiers[#Edit_Poly].relaxHoldOuterPoints = off
$.modifiers[#Edit_Poly].ButtonOp #Relax
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">MeshOp Methods</div>
Per-vertex velocity data and isolated texture verts removal.
<pre class="notranslate">
<code><span class="code-keywords3">meshop</span><span class="code-symbol">.</span><span class="code-identifier">getNumVelocity</span> <span class="code-symbol"><</span><span class="code-identifier">mesh</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">meshop</span><span class="code-symbol">.</span><span class="code-identifier">getVelocity</span> <span class="code-symbol"><</span><span class="code-identifier">mesh</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">vertex</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">meshop</span><span class="code-symbol">.</span><span class="code-identifier">deleteIsoMapVerts</span> <span class="code-symbol"><</span><span class="code-identifier">mesh</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">mapChannel</span><span class="code-symbol">></span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">MeshOps Methods</div>
<pre class="notranslate">
<code><span class="code-keywords3">meshOps</span><span class="code-symbol">.</span><span class="code-identifier">clearAllSG</span> <span class="code-symbol"><</span><span class="code-identifier">editable_mesh_node_or_modifier</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">meshOps</span><span class="code-symbol">.</span><span class="code-identifier">selectBySG</span> <span class="code-symbol"><</span><span class="code-identifier">editable_mesh_node_or_modifier</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">meshOps</span><span class="code-symbol">.</span><span class="code-identifier">selectByColor</span> <span class="code-symbol"><</span><span class="code-identifier">editable_mesh_node_or_modifier</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">meshOps</span><span class="code-symbol">.</span><span class="code-identifier">showNormal</span> <span class="code-symbol"><</span><span class="code-identifier">editable_mesh_node_or_modifier</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">meshOps</span><span class="code-symbol">.</span><span class="code-identifier">autoSmooth</span> <span class="code-symbol"><</span><span class="code-identifier">editable_mesh_node_or_modifier</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">meshOps</span><span class="code-symbol">.</span><span class="code-identifier">selectByID</span> <span class="code-symbol"><</span><span class="code-identifier">editable_mesh_node_or_modifier</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">meshOps</span><span class="code-symbol">.</span><span class="code-identifier">attachList</span> <span class="code-symbol"><</span><span class="code-identifier">editable_mesh_node_or_modifier</span><span class="code-symbol">></span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">PolyOp Methods</div>
<pre class="notranslate">
<code><span class="code-keywords3">polyop</span><span class="code-symbol">.</span><span class="code-identifier">checkTriangulation</span> <span class="code-symbol"><</span><span class="code-identifier">poly</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyop</span><span class="code-symbol">.</span><span class="code-identifier">makeVertsPlanar</span> <span class="code-symbol"><</span><span class="code-identifier">poly</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">vertlist</span><span class="code-symbol">></span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">PolyOps Methods</div>
Methods corresponding to pushing buttons in the Command Panel, applicable only to Editable Poly scene node.
<pre class="notranslate" style="height: 400px;">
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">startDivideFace</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">makePlanar</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">startCreateFace</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">weld</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">startCreateVertex</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">resetPlane</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">startWeldTarget</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">autoSmooth</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">break</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">delete</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">startCutEdge</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">selectByID</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">attachList</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">startSlicePlane</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">retriangulate</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">cap</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">startChamferEdge</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">tessellate</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">namedSelCopy</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">startExtrudeFace</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">removeIsolatedVerts</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">hide</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">startEditTri</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">startExtrudeVertex</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">gridAlign</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">startDivideEdge</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">createShapeFromEdges</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">startCreateEdge</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">slice</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">clearAllSG</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">collapse</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">startCutFace</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">selectBySG</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">split</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">startCutVertex</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">flipNormal</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">detach</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">startBevel</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">selectByColor</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">update</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">namedSelPaste</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">startChamferVertex</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">meshSmooth</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">unhide</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">startExtrudeEdge</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">polyOps</span><span class="code-symbol">.</span><span class="code-identifier">viewAlign</span> <span class="code-symbol"><</span><span class="code-identifier">editable_poly_node</span><span class="code-symbol">></span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">SplineOps Missing Methods</div>
<pre class="notranslate">
<code><span class="code-keywords3">splineOps</span><span class="code-symbol">.</span><span class="code-identifier">startCrossSection</span> <span class="code-symbol"><</span><span class="code-identifier">editable_spline_or_line_node_or_modifier</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">splineOps</span><span class="code-symbol">.</span><span class="code-identifier">startIntersect</span> <span class="code-symbol"><</span><span class="code-identifier">editable_spline_or_line_node_or_modifier</span><span class="code-symbol">></span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">GUID Generator</div>
Next time you need a UUID, you know what to use:<br />
<pre class="notranslate"><code><span class="code-keywords3">genGUID</span><span class="code-symbol">()</span> <span class="code-comment">--> "{F2FBBC06-1A6B-49C8-9FD6-31C597BA3265}"</span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">ToolTip Customization</div>
See <a href="http://forums.cgsociety.org/showthread.php?t=1359234">2 small cookies in 3ds Max 2017</a> for more details.
<pre class="notranslate"><code><span class="code-keywords3">viewport</span><span class="code-symbol">.</span><span class="code-identifier">appendTooltip</span> <span class="code-symbol"><</span><span class="code-identifier">tooltip_def</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">tipSystem</span><span class="code-symbol">.</span><span class="code-identifier">showTip</span> <span class="code-symbol"><</span><span class="code-identifier">integer</span><span class="code-symbol">></span>elapsedTime <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span>tipContent <span class="code-symbol"><</span><span class="code-identifier">float</span><span class="code-symbol">></span>xRatio <span class="code-symbol"><</span><span class="code-identifier">float</span><span class="code-symbol">></span>yRatio <span class="code-symbol"><</span><span class="code-identifier">HWND</span><span class="code-symbol">></span>hParent</code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Other Viewport Methods</div>
<pre class="notranslate">
<code><span class="code-keywords3">viewport</span><span class="code-symbol">.</span><span class="code-identifier">getClipScale</span><span class="code-symbol">()</span></code>
<code><span class="code-keywords3">viewport</span><span class="code-symbol">.</span><span class="code-identifier">setClipScale</span> <span class="code-symbol"><</span><span class="code-identifier">float</span><span class="code-symbol">></span>scale</code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Display Manager</div>
<pre class="notranslate">
<code><span class="code-keywords3">DisplayManager</span><span class="code-symbol">.</span><span class="code-identifier">IsEnabled</span><span class="code-symbol">()</span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">MaxOps Methods and Properties</div>
<pre class="notranslate">
<code><span class="code-symbol"><</span><span class="code-identifier">bool</span><span class="code-symbol">></span><span class="code-keywords3">maxOps</span><span class="code-symbol">.</span><span class="code-identifier">affectChildren</span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">void</span><span class="code-symbol">></span><span class="code-keywords3">maxOps</span><span class="code-symbol">.</span><span class="code-identifier">activateSetKeyMode</span> <span class="code-symbol"><</span><span class="code-identifier">void</span><span class="code-symbol">></span>onOff</code>
<code><span class="code-symbol"><</span><span class="code-identifier">matrix3</span><span class="code-symbol">></span><span class="code-keywords3">maxOps</span><span class="code-symbol">.</span><span class="code-identifier">getTransformGizmoTM</span><span class="code-symbol">()</span></code>
<code></code>
<code><span class="code-symbol"><</span><span class="code-identifier">TSTR by value</span><span class="code-symbol">></span><span class="code-keywords3">maxOps</span><span class="code-symbol">.</span><span class="code-identifier">incrementFileName</span> <span class="code-symbol"><</span><span class="code-identifier">TSTR by value</span><span class="code-symbol">></span>fileName <span class="code-identifier">versionSeparatorString</span><span class="code-symbol">:<</span><span class="code-identifier">TSTR by value</span><span class="code-symbol">=""></span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">TSTR by value</span><span class="code-symbol">></span><span class="code-keywords3">maxOps</span><span class="code-symbol">.</span><span class="code-identifier">incrementSceneFileName</span> <span class="code-symbol"><</span><span class="code-identifier">TSTR by value</span><span class="code-symbol">></span>fileName</code>
<code><span class="code-symbol"><</span><span class="code-identifier">TSTR by value</span><span class="code-symbol">></span><span class="code-keywords3">maxOps</span><span class="code-symbol">.</span><span class="code-identifier">incrementImageFileName</span> <span class="code-symbol"><</span><span class="code-identifier">TSTR by value</span><span class="code-symbol">></span>fileName</code>
<code></code>
<code><span class="code-symbol"><</span><span class="code-identifier">bool</span><span class="code-symbol">></span><span class="code-keywords3">maxOps</span><span class="code-symbol">.</span><span class="code-identifier">useCodePageSpecifiedInSceneFile</span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">bool</span><span class="code-symbol">></span><span class="code-keywords3">maxOps</span><span class="code-symbol">.</span><span class="code-identifier">legacyFilesCanBeStoredUsingUTF8</span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">enum</span><span class="code-symbol">></span><span class="code-keywords3">maxOps</span><span class="code-symbol">.</span><span class="code-identifier">languageToUseForFileIO</span> <span class="code-comment">-- enums: {#current|#English|#German|#French|#Japanese|#Korean|#Chinese}</span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">void</span><span class="code-symbol">></span><span class="code-keywords3">maxOps</span><span class="code-symbol">.</span><span class="code-identifier">persistFileLanguageSettings</span><span class="code-symbol">()</span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">The Painter Interface Spline Constraint</div>
Methods related to setting a spline used for constraining the brush.<br />
<pre class="notranslate">
<code><span class="code-symbol"><</span><span class="code-identifier">bool</span><span class="code-symbol">></span><span class="code-keywords3">thePainterInterface</span><span class="code-symbol">.</span><span class="code-identifier">useSplineConstraint</span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">bool</span><span class="code-symbol">></span><span class="code-keywords3">thePainterInterface</span><span class="code-symbol">.</span><span class="code-identifier">setSplineConstraintNode</span> <span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span>node</code>
<code><span class="code-symbol"><</span><span class="code-identifier">bool</span><span class="code-symbol">></span><span class="code-keywords3">thePainterInterface</span><span class="code-symbol">.</span><span class="code-identifier">isSplineConstraintNodeValid</span><span class="code-symbol">()</span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">SceneExplorerManager Methods</div>
Mentioned in passing inside the What's New section, missing from the <a href="http://help.autodesk.com/view/3DSMAX/2018/ENU/?guid=__files_GUID_21B47E09_1A2E_462E_AC79_2A64B4A2BB57_htm">Interface: SceneExplorerManager chapter</a>.
<pre class="notranslate"><code><span class="code-keywords3">SceneExplorerManager</span><span class="code-symbol">.</span><span class="code-identifier">GetActiveExplorer</span><span class="code-symbol">()</span></code>
<code><span class="code-keywords3">SceneExplorerManager</span><span class="code-symbol">.</span><span class="code-identifier">SetActiveExplorer</span> <span class="code-symbol"><</span><span class="code-identifier">&TSTR</span><span class="code-symbol">></span>explorerName</code>
<code><span class="code-keywords3">SceneExplorerManager</span><span class="code-symbol">.</span><span class="code-identifier">CreateLayerManager</span> <span class="code-symbol"><</span><span class="code-identifier">&TSTR</span><span class="code-symbol">></span>explorerName</code>
<code><span class="code-keywords3">SceneExplorerManager</span><span class="code-symbol">.</span><span class="code-identifier">IsDefaultLayer</span> <span class="code-symbol"><</span><span class="code-identifier">RefTarget</span><span class="code-symbol">></span>layer</code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">SimpleManipulator Flags</div>
The <code class="notranslate">addGizmoMesh</code> method accepts an additional undocumented gizmoScaleToViewport</code> flag. Mesh gizmo added with this flag will try and scale itself to have a constant size in the viewport. This size in pixels is given by the private <code class="notranslate">ManipulatorGizmo::mGizmoSize</code> variable which is not accessible from MAXScript (although there's <code class="notranslate">getGizmoSize/setGizmoSize</code> function ID pair, the property is not published).<br /><br />
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Missing and Deprecated colorMan Flags</div>
<pre class="notranslate" style="height: 400px;">
<code><span class="code-identifier">#</span>BackgroundOdd <span class="code-comment">-- background of odd layers</span></code>
<code><span class="code-identifier">#</span>BackgroundEven <span class="code-comment">-- background of even layers</span></code>
<code><span class="code-identifier">#</span>Button <span class="code-comment">-- button background</span></code>
<code><span class="code-identifier">#</span>ButtonText <span class="code-comment">-- button text</span></code>
<code><span class="code-identifier">#</span>FocusBorder</code>
<code><span class="code-identifier">#</span>UIBorder</code>
<code><span class="code-identifier">#</span>ToolTipUIBackground</code>
<code><span class="code-identifier">#</span>ToolTipUIText</code>
<code><span class="code-identifier">#</span>ToolTipViewportBackground</code>
<code><span class="code-identifier">#</span>ToolTipViewportText</code>
<code><span class="code-identifier">#</span>PreviewHighlights</code>
<code><span class="code-identifier">#</span>SelectionHighlights</code>
<code><span class="code-identifier">#</span>AnimationKeyBrackets</code>
<code><span class="code-identifier">#</span>ManipulatorsActive</code>
<code><span class="code-identifier">#</span>ManipulatorsSelected</code>
<code><span class="code-identifier">#</span>ManipulatorsInactive</code>
<code><span class="code-identifier">#</span>ViewportGradientBackgroundTop</code>
<code><span class="code-identifier">#</span>ViewportGradientBackgroundBottom</code>
<code><span class="code-identifier">#</span>PressedHierarchyButton</code>
<code><span class="code-identifier">#</span>ImageViewerBackground</code>
<code><span class="code-identifier">#</span>TrackViewBackground</code>
<code><span class="code-identifier">#</span>TrackViewInactiveBackground</code>
<code><span class="code-identifier">#</span>TrackbarCacheLine</code>
<code><span class="code-identifier">#</span>TrackbarCachedLine</code>
<code><span class="code-identifier">#</span>AssemblyOutline</code>
<code><span class="code-identifier">#</span>AdapDegActive</code>
<code><span class="code-identifier">#</span>OutOfRangeLow</code>
<code><span class="code-identifier">#</span>OutOfRangeHigh</code>
<code><span class="code-identifier">#</span>iRenderProgHoriz</code>
<code><span class="code-identifier">#</span>iRenderProgVert</code>
</pre>
<pre class="notranslate"><code><span class="code-identifier">#</span>Background <span class="code-comment">-- deprecated since 3ds Max 2017, use #BackgroundOdd instead</span></code>
<code><span class="code-identifier">#</span>Window <span class="code-comment">-- deprecated since 3ds Max 2017, use #BackgroundOdd instead</span></code>
<code><span class="code-identifier">#</span>WindowText <span class="code-comment">-- deprecated since 3ds Max 2017, use #Text instead</span></code>
<code><span class="code-identifier">#</span>Hilight <span class="code-comment">-- deprecated since 3ds Max 2017, won't be used any more</span></code>
<code><span class="code-identifier">#</span>Shadow <span class="code-comment">-- deprecated since 3ds Max 2017, won't be used any more</span></code></pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Missing Callback Event Names</div>
<pre class="notranslate">
<code><span class="code-identifier">#</span>filePostOpenProcessFinalized</code>
<code><span class="code-identifier">#</span>filePostMergeProcessFinalized</code>
<code></code>
<code><span class="code-identifier">#</span>preProjectFolderChange</code>
<code><span class="code-identifier">#</span>postProjectFolderChange</code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Profiler Methods</div>
Missing from the reference, see the <a href="https://knowledge.autodesk.com/support/3ds-max/learn-explore/caas/CloudHelp/cloudhelp/2017/ENU/3DSMax/files/GUID-FD78224F-B245-4CB6-BBDB-7D60C42C5E89-htm.html">Improving Animation Performance using Maya's Profiler</a> knowledge network article.
<pre class="notranslate"><code><span class="code-keywords3">getEnableProfiling</span><span class="code-symbol">()</span></code>
<code><span class="code-keywords3">setEnableProfiling</span><span class="code-symbol">()</span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Custom Attributes Version Handling</div>
Controls whether custom attributes that are merged/loaded should be updated in case of version conflict.
<pre class="notranslate">
<code><span class="code-keywords3">custAttributes</span><span class="code-symbol">.</span><span class="code-identifier">getSceneLoadVersionHandlingBehavior</span><span class="code-symbol">()</span></code>
<code><span class="code-keywords3">custAttributes</span><span class="code-symbol">.</span><span class="code-identifier">setSceneLoadVersionHandlingBehavior</span> <span class="code-symbol"><</span><span class="code-identifier">behavior_name</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">custAttributes</span><span class="code-symbol">.</span><span class="code-identifier">getSceneMergeVersionHandlingBehavior</span><span class="code-symbol">()</span></code>
<code><span class="code-keywords3">custAttributes</span><span class="code-symbol">.</span><span class="code-identifier">setSceneMergeVersionHandlingBehavior</span> <span class="code-symbol"><</span><span class="code-identifier">behavior_name</span><span class="code-symbol">></span></code>
</pre>
Valid <code>behavior_name</code> values are:
<pre class="notranslate">
<span class="code-identifier">#</span>neverUpdate
<span class="code-identifier">#</span>alwaysUpdate
<span class="code-identifier">#</span>updateWhenLoadVersionGreaterThanCurrentVersion
<span class="code-identifier">#</span>updateWhenLoadVersionGreaterThanOrEqualToCurrentVersion
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Schematic View Missing Methods</div>
<pre class="notranslate">
<code><span class="code-keywords3">schematicView</span><span class="code-symbol">.</span><span class="code-identifier">numSchematicViews</span><span class="code-symbol">()</span></code>
<code><span class="code-keywords3">schematicView</span><span class="code-symbol">.</span><span class="code-identifier">getSchematicViewName</span> <span class="code-symbol"><</span><span class="code-identifier">int</span><span class="code-symbol">></span>index</code>
<code><span class="code-keywords3">schematicView</span><span class="code-symbol">.</span><span class="code-identifier">open</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span>name</code>
<code><span class="code-keywords3">schematicView</span><span class="code-symbol">.</span><span class="code-identifier">zoomSelected</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span>name</code>
<code><span class="code-keywords3">schematicView</span><span class="code-symbol">.</span><span class="code-identifier">close</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span>name</code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Assert Display Getter</div>
Another of the getter/setter pairs that are not mentioned at all or just one of the pair. See <a href="http://help.autodesk.com/view/3DSMAX/2018/ENU/?guid=__files_GUID_E71723FE_39B3_4A22_AA29_1BF7D2470491_htm">3ds Max Assert Display Functions</a> for its counterpart and more information.
<pre class="notranslate"><code><span class="code-keywords3">getMaxAssertDisplay</span><span class="code-symbol">()</span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Assert Equal for Point2 & Point4</div>
See <a href="https://knowledge.autodesk.com/search-result/caas/CloudHelp/cloudhelp/2018/ENU/MAXScript-Help/files/GUID-821E791F-6D80-48C7-8A65-65BE73C551C6-htm.html">assert_point3_equal</a>.
<pre class="notranslate">
<code><span class="code-keywords3">assert_point2_equal</span> <span class="code-symbol"><</span><span class="code-identifier">point2</span><span class="code-symbol">></span>expected <span class="code-symbol"><</span><span class="code-identifier">expression</span><span class="code-symbol">></span>actual <span class="code-symbol">[</span>tolerance<span class="code-symbol">:<</span><span class="code-identifier">float</span><span class="code-symbol">>]</span> <span class="code-symbol">[</span>message<span class="code-symbol">:<</span><span class="code-identifier">string</span><span class="code-symbol">>]</span></code>
<code><span class="code-keywords3">assert_point4_equal</span> <span class="code-symbol"><</span><span class="code-identifier">point4</span><span class="code-symbol">></span>expected <span class="code-symbol"><</span><span class="code-identifier">expression</span><span class="code-symbol">></span>actual <span class="code-symbol">[</span>tolerance<span class="code-symbol">:<</span><span class="code-identifier">float</span><span class="code-symbol">>]</span> <span class="code-symbol">[</span>message<span class="code-symbol">:<</span><span class="code-identifier">string</span><span class="code-symbol">>]</span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">MxsUnitResults</div>
Probably only related to internal unit test results.
<pre class="notranslate">
<code><span class="code-symbol"><</span><span class="code-identifier">integer</span><span class="code-symbol">></span><span class="code-keywords3">MxsUnitResults</span><span class="code-symbol">.</span><span class="code-identifier">GetAssertFailCount</span><span class="code-symbol">()</span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">integer</span><span class="code-symbol">></span><span class="code-keywords3">MxsUnitResults</span><span class="code-symbol">.</span><span class="code-identifier">GetExceptionCount</span><span class="code-symbol">()</span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">integer</span><span class="code-symbol">></span><span class="code-keywords3">MxsUnitResults</span><span class="code-symbol">.</span><span class="code-identifier">GetMessageCount</span><span class="code-symbol">()</span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span><span class="code-keywords3">MxsUnitResults</span><span class="code-symbol">.</span><span class="code-identifier">GetAssertFailure</span> <span class="code-symbol"><</span><span class="code-identifier">index</span><span class="code-symbol">></span>index</code>
<code><span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span><span class="code-keywords3">MxsUnitResults</span><span class="code-symbol">.</span><span class="code-identifier">GetExceptionFailure</span> <span class="code-symbol"><</span><span class="code-identifier">index</span><span class="code-symbol">></span>index</code>
<code><span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span><span class="code-keywords3">MxsUnitResults</span><span class="code-symbol">.</span><span class="code-identifier">GetMessage</span> <span class="code-symbol"><</span><span class="code-identifier">index</span><span class="code-symbol">></span>index</code>
<code><span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span><span class="code-keywords3">MxsUnitResults</span><span class="code-symbol">.</span><span class="code-identifier">GetUserData</span><span class="code-symbol">()</span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">void</span><span class="code-symbol">></span><span class="code-keywords3">MxsUnitResults</span><span class="code-symbol">.</span><span class="code-identifier">Clear</span><span class="code-symbol">()</span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">TMCache Switch</div>
If you ever noticed your scripted rigs breaking in 2017 while they work perfectly well in 2016, be sure to check this. For more information about TMCache, see <a href="http://area.autodesk.com/blogs/max-station/k3-fixing-ik-solver-animation-editing-in-3ds-max-2017">Fixing IK solver animation editing in 3ds Max 2017</a>.
<pre class="notranslate"><code><span class="code-keywords3">preferences</span><span class="code-symbol">.</span><span class="code-identifier">enableTMCache</span> <span class="code-symbol">=</span> <span class="code-keywords1">off</span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">DontRepeatMessages Context</div>
Legacy setting, see <a href="http://help.autodesk.com/view/3DSMAX/2018/ENU/?guid=__files_GUID_141213A1_B5A8_457B_8838_E602022C8798_htm">preferences.dontRepeatRefMsg</a>.
<pre class="notranslate"><code><span class="code-keywords1">with</span> <span class="code-identifier">dontRepeatMessages</span> <span class="code-keywords1">off</span> <span class="code-symbol">...</span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Convert to Integer</div>
Unlike the <code>as integer</code> cast, thiw one will error out when a string is passed to it.
<pre class="notranslate"><code><span class="code-keywords3">int</span> <span class="code-symbol"><</span><span class="code-identifier">number</span><span class="code-symbol">></span></code></pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">IndirectRefTargContainer</div>
See <a href="http://help.autodesk.com/cloudhelp/2018/ENU/MAXScript-Help/files/GUID-794B81E9-6084-43D8-A6C5-B7AA04625013.htm">RefTargContainer</a>, same constructor and methods apply. For example usage, check the source of my <a href="http://www.scriptspot.com/3ds-max/scripts/advanced-sweep">Advanced Sweep</a> scripted modifier where the RefTargContainer is used to store CurveCtl as a maxObject parameter.
<pre class="notranslate"><code><span class="code-keywords3">IndirectRefTargContainer</span><span class="code-symbol">..</span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">NodeMonitor</div>
Similar to the NodeTransformMonitor but doesn't pass transform messages. Searching cgtalk and looking for denisT's posts and sample code will tell you more, for example <a href=http://forums.cgsociety.org/showthread.php?f=98&t=1087927&page=2&pp=15">Using controllers with scripted plugins - "this node"</a>.
<pre class="notranslate"><code><span class="code-keywords3">nodeMonitor</span> <span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span></code></pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">SnapshotAsMesh Optional RenderMesh Keyword</div>
See the <a href="http://forums.cgsociety.org/showthread.php?t=1166067">cgtalk thread</a>. Still missing from the official documentation.
<pre class="notranslate"><code><span class="code-keywords3">snapshotAsMesh</span> <span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span> <span class="code-symbol">[</span> renderMesh<span class="code-symbol">:<</span><span class="code-identifier">boolean</span><span class="code-symbol">> ]</span> </code></pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">RenderPresets Optional loadNodes Argument</div>
As mentioned in 3ds max 7 release notes, loading presets that contain node associations displays a dialog requiring user interaction. To bypass the dialog, you can use the following syntax:
<pre class="notranslate">
<code><span class="code-symbol"><</span><span class="code-identifier">boolean</span><span class="code-symbol">></span><span class="code-keywords3">renderPresets</span><span class="code-symbol">.</span><span class="code-identifier">Load</span> <span class="code-symbol"><</span><span class="code-identifier">integer</span><span class="code-symbol">></span>which <span class="code-symbol"><</span><span class="code-identifier">filename</span><span class="code-symbol">></span>file <span class="code-symbol"><</span><span class="code-identifier">bitArray</span><span class="code-symbol">></span>categories <span class="code-symbol">[</span> loadNodes<span class="code-symbol">:</span><span class="code-symbol"><</span><span class="code-identifier">enum</span><span class="code-symbol">: {#</span>Yes<span class="code-symbol">|#</span>No<span class="code-symbol">|#</span>Cancel<span class="code-symbol">|#</span>Prompt<span class="code-symbol">}</span><span class="code-symbol">></span> <span class="code-symbol">]</span></code>
</pre>
Specifying <code>loadNodes</code> with <code>#Yes</code>, <code>#No</code> or <code>#Cancel</code> will not display the Prompt window and will perform the same actions as pressing the respective buttons in the prompt. Specifying <code>#Prompt</code> will display the dialog and require user input. If you do not specify <code>loadNodes</code> and the file contains nodes associated, the prompt window will be displayed.<br /><br />
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Optional Keyword Arguments for Cloned Objects</div>
Just like with the <code>createInstance</code> function, you can pass any of the constructor arguments when creating a cloned object (say <code>copy obj transform:TM</code>).
<pre class="notranslate"><code><span class="code-keywords3">copy</span> <span class="code-symbol"><</span><span class="code-identifier">MAXWrapper_object</span><span class="code-symbol">></span> <span class="code-symbol">[</span> keyarg1<span class="code-symbol">:</span><span class="code-identifier">v</span><span class="code-symbol"> ]</span> <span class="code-symbol">[</span> keyarg2<span class="code-symbol">:</span><span class="code-identifier">v</span><span class="code-symbol"> ]</span> <span class="code-symbol">..</span></code>
<code><span class="code-keywords3">instance</span> <span class="code-symbol"><</span><span class="code-identifier">MAXWrapper_object</span><span class="code-symbol">></span> <span class="code-symbol">[</span> keyarg1<span class="code-symbol">:</span><span class="code-identifier">v</span><span class="code-symbol"> ]</span> <span class="code-symbol">[</span> keyarg2<span class="code-symbol">:</span><span class="code-identifier">v</span><span class="code-symbol"> ]</span> <span class="code-symbol">..</span></code>
<code><span class="code-keywords3">reference</span> <span class="code-symbol"><</span><span class="code-identifier">MAXWrapper_object</span><span class="code-symbol">></span> <span class="code-symbol">[</span> keyarg1<span class="code-symbol">:</span><span class="code-identifier">v</span><span class="code-symbol"> ]</span> <span class="code-symbol">[</span> keyarg2<span class="code-symbol">:</span><span class="code-identifier">v</span><span class="code-symbol"> ]</span> <span class="code-symbol">..</span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">CreateInstance Optional ForceCreate Argument</div>
Allows creation of classes that otherwise return <code>Runtime error: Not creatable</code>.
<pre class="notranslate"><code><span class="code-keywords3">createInstance</span> <span class="code-symbol"><</span><span class="code-identifier">MAXClass</span><span class="code-symbol">></span> forceCreate<span class="code-symbol">:<</span><span class="code-identifier">boolean</span><span class="code-symbol">=</span>false<span class="code-symbol">> [</span> keyarg1<span class="code-symbol">:</span><span class="code-identifier">v</span> <span class="code-symbol">] [</span> keyarg2<span class="code-symbol">:</span><span class="code-identifier">v</span> <span class="code-symbol">] ...</span></code></pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Scripted SimpleSpline Plug-in</div>
Similar to <a href="http://help.autodesk.com/view/3DSMAX/2018/ENU/?guid=__files_GUID_C0BFFE27_BB59_4265_8F70_BFE8A636F7CB_htm">Scripted SimpleObject Plug-ins</a>, instead of a predefined <code>mesh</code> variable, a <code>bezierShape</code> one is used. See for example my <a href="http://www.scriptspot.com/3ds-max/scripts/arrow">Arrow spline primitive</a> script for example usage.
<pre class="notranslate"><code><span class="code-keywords4">plugin</span> <span class="code-identifier">simpleSpline</span> <span class="code-symbol">...</span></code>
<code><span class="code-keywords1">on</span> <span class="code-identifier">buildShape</span> <span class="code-keywords1">do</span> <span class="code-symbol"><</span><span class="code-identifier">expr</span><span class="code-symbol">></span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Similar Nodes</div>
Same criteria as used by <i>Edit > Select Similar</i>.
<pre class="notranslate"><code><span class="code-keywords3">getSimilarNodes</span> <span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span></code></pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Current Selection Set Name</div>
As displayed in the main menu bar, i.e. returns <code>"Create Selection"</code> if empty.
<pre class="notranslate"><code><span class="code-keywords3">getCurNameSelSet</span><span class="code-symbol">()</span></code></pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">FromattedPrint String Type</div>
As spotted by Martin Breidt, not only you can pad numbers using formattedPrint, by using the <code>'s'</code> character to indicate the passed argument is a string you can also pad strings:
<pre class="notranslate">
<code><span class="code-keywords3">formattedPrint</span> <span class="code-string">"string"</span> format<span class="code-symbol">:</span><span class="code-string">"10s"</span></code>
<code><span class="code-comment">--> " string"</span></code>
</pre>
There are other undocumented types used by the format literal, such as <code>c/C</code> (wide/single-byte char), <code>a/A</code> (<code>[−]0xh.hhhh p/P±dd</code> hexadecimal double) or <code>p</code> (hexadecimal pointer address). For more details see the <a href = "https://msdn.microsoft.com/en-us/library/56e442dc.aspx"><code>'_snwprintf'</code> function documentation</a>.<br/><br/>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Display Filter</div>
Similar to the documented <a href="https://knowledge.autodesk.com/search-result/caas/CloudHelp/cloudhelp/2016/ENU/MAXScript-Help/files/GUID-97C887B6-CE4D-46EB-AB10-BE3A9DC2F69A-htm.html">registerSelectFilterCallback</a>.
<pre class="notranslate">
<code><span class="code-keywords3">registerDisplayFilterCallback</span> <span class="code-symbol"><</span><span class="code-identifier">filterFunction</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">name</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">unregisterDisplayFilterCallback</span> <span class="code-symbol"><</span><span class="code-identifier">filterFunction</span><span class="code-symbol">></span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">SkinOps Missing Arguments and Methods</div>
See <a href="http://www.maxforums.org/threads/workaround_dq_skinning_bug/0001.aspx">Anybody know a workaround for the DQ skinning bug?</a>.
<pre class="notranslate">
<code><span class="code-keywords3">skinOps</span><span class="code-symbol">.</span><span class="code-identifier">getVertexDQWeight</span> <span class="code-symbol"><</span><span class="code-identifier">Skin</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">vertexID</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">skinOps</span><span class="code-symbol">.</span><span class="code-identifier">setVertexDQWeight</span> <span class="code-symbol"><</span><span class="code-identifier">Skin</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">vertexID</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">weight</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">skinOps</span><span class="code-symbol">.</span><span class="code-identifier">WeightTable</span> <span class="code-symbol"><</span><span class="code-identifier">Skin</span><span class="code-symbol">></span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Unwrap Globals</div>
<pre class="notranslate">
<code><span class="code-identifier">mapPath</span> <span class="code-symbol">:</span> <span class="code-comment">path to Texture Checker map used in Unwrap UVW</span></code>
<code><span class="code-identifier">uvChecker_mtl</span> <span class="code-symbol">:</span> <span class="code-comment">standard material using the texture in mapPath</span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Network Render</div>
<pre class="notranslate"><code><span class="code-keywords3">isNetworkRenderServer</span><span class="code-symbol">()</span></code></pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Is Undo Disabled</div>
Companion function for the <code>enableUndo</code> function.
<pre class="notranslate"><code><span class="code-keywords3">isUndoDisabled</span><span class="code-symbol">()</span></code></pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">TheHold Methods</div>
Same as isUndoDisabled above, and a counter for of the nested <code>theHold.Begin()</code> calls.
<pre class="notranslate">
<code><span class="code-keywords3">theHold</span><span class="code-symbol">.</span><span class="code-identifier">isUndoDisabled</span><span class="code-symbol">()</span></code>
<code><span class="code-keywords3">theHold</span><span class="code-symbol">.</span><span class="code-identifier">getBeginDepth</span><span class="code-symbol">()</span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Other Aliases</div>
<pre class="notranslate">
<code><span class="code-identifier">productAppID</span> <span class="code-symbol">:</span> <span class="code-comment">same as maxOps.productAppID</span></code>
<code><span class="code-identifier">playbackLoop</span> <span class="code-symbol">:</span> <span class="code-comment">same as timeConfiguration.PlaybackLoop</span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Subscription</div>
<pre class="notranslate">
<code><span class="code-keywords3">systemTools</span><span class="code-symbol">.</span><span class="code-identifier">isSubscription</span><span class="code-symbol">()</span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Animatable Pointer</div>
Same as <code>refs.getAddr</code>.
<pre class="notranslate"><code><span class="code-keywords3">getAnimPointer</span> <span class="code-symbol"><</span><span class="code-identifier">MAXWrapper_object</span><span class="code-symbol">></span></code></pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">ShowDialog</div>
Hide/show existing dialog without destroying it.
<pre class="notranslate"><code><span class="code-keywords3">showDialog</span> <span class="code-symbol"><</span>rollout<span class="code-symbol">> <</span>boolean<span class="code-symbol">></span></code></pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Dialog Visibility</div>
Useful whenever you want to test if the dialog is displayed (for example in the <code>isChecked</code> macroScript event handler). Similar to <code><rollout>.inDialog</code>.
<pre class="notranslate"><code><span class="code-keywords3">isDialogVisible</span> <span class="code-symbol"><</span><span class="code-identifier">rollout</span><span class="code-symbol">></span></code></pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Windows Struct Methods</div>
<pre class="notranslate">
<code><span class="code-keywords3">windows</span><span class="code-symbol">.</span><span class="code-identifier">getParentHWND</span> <span class="code-symbol"><</span><span class="code-identifier">IntegerPtr</span><span class="code-symbol">></span>hWnd</code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Numbered String</div>
Used by Render to Texture to produce a filename with frame number, adds a 4-character zero-padded suffix (or more, if the string representation of number is longer).
<pre class="notranslate"><code><span class="code-keywords3">createNumberedFilename</span> <span class="code-symbol"><</span><span class="code-identifier">name</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">frameNr</span><span class="code-symbol">></span></code></pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Biped Methods</div>
As posted to <a href="http://tech-artists.org/t/for-those-of-you-still-stuck-using-biped-and-copy-collections/4604">For those of you still stuck using biped and copy-collections</a>.
<pre class="notranslate">
<code><span class="code-symbol"><</span><span class="code-identifier">integer</span><span class="code-symbol">></span><span class="code-keywords3">biped</span><span class="code-symbol">.</span><span class="code-identifier">numCopies</span> <span class="code-symbol"><</span><span class="code-identifier">collection_value</span><span class="code-symbol">></span> <span class="code-symbol">(#</span>pose<span class="code-symbol">|#</span>posture<span class="code-symbol">|#</span>track<span class="code-symbol">)</span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">ICP_MXBipedCopy</span><span class="code-symbol">></span><span class="code-keywords3">biped</span><span class="code-symbol">.</span><span class="code-identifier">getCopy</span> <span class="code-symbol"><</span><span class="code-identifier">collection_value</span><span class="code-symbol">></span> <span class="code-symbol">(#</span>pose<span class="code-symbol">|#</span>posture<span class="code-symbol">|#</span>track<span class="code-symbol">)</span> <span class="code-symbol"><</span><span class="code-identifier">index</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">biped</span><span class="code-symbol">.</span><span class="code-identifier">deleteCopy</span> <span class="code-symbol"><</span><span class="code-identifier">collection_value</span><span class="code-symbol">></span> <span class="code-symbol">(#</span>pose<span class="code-symbol">|#</span>posture<span class="code-symbol">|#</span>track<span class="code-symbol">)</span> <span class="code-symbol"><</span><span class="code-identifier">index</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">biped</span><span class="code-symbol">.</span><span class="code-identifier">deleteAllCopies</span> <span class="code-symbol"><</span><span class="code-identifier">collection_value</span><span class="code-symbol">></span> <span class="code-symbol">(#</span>pose<span class="code-symbol">|#</span>posture<span class="code-symbol">|#</span>track<span class="code-symbol">)</span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Is Particle System</div>
<pre class="notranslate"><code><span class="code-keywords3">isParticleSystem</span> <span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span></code></pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Direct 3D Cache Allocation</div>
For related methods, check the <a href="http://help.autodesk.com/view/3DSMAX/2018/ENU/?guid=__files_GUID_809E0228_B713_43E4_A805_6C8736A4FD6A_htm">Direct 3D Cache Allocation Query Functions</a> chapter.
<pre class="notranslate"><code><span class="code-keywords3">setD3DMeshCacheSize</span> <span class="code-symbol"><</span><span class="code-identifier">number</span><span class="code-symbol">></span></code></pre>
And related Editable Poly methods:<br />
<pre class="notranslate">
<code><span class="code-symbol"><</span><span class="code-identifier">bool</span><span class="code-symbol">><</span><span class="code-keywords4">EditablePoly</span><span class="code-symbol">>.</span><span class="code-identifier">GetCache_SystemOn</span><span class="code-symbol">()</span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">void</span><span class="code-symbol">><</span><span class="code-keywords4">EditablePoly</span><span class="code-symbol">>.</span><span class="code-identifier">SetCache_SystemOn</span> <span class="code-symbol"><</span><span class="code-identifier">bool</span><span class="code-symbol">></span>on</code>
<code><span class="code-symbol"><</span><span class="code-identifier">bool</span><span class="code-symbol">><</span><span class="code-keywords4">EditablePoly</span><span class="code-symbol">>.</span><span class="code-identifier">GetCache_SuspendDXCache</span><span class="code-symbol">()</span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">void</span><span class="code-symbol">><</span><span class="code-keywords4">EditablePoly</span><span class="code-symbol">>.</span><span class="code-identifier">SetCache_SuspendDXCache</span> <span class="code-symbol"><</span><span class="code-identifier">bool</span><span class="code-symbol">></span>suspend</code>
<code><span class="code-symbol"><</span><span class="code-identifier">integer</span><span class="code-symbol">><</span><span class="code-keywords4">EditablePoly</span><span class="code-symbol">>.</span><span class="code-identifier">GetCache_Cutoff</span><span class="code-symbol">()</span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">void</span><span class="code-symbol">><</span><span class="code-keywords4">EditablePoly</span><span class="code-symbol">>.</span><span class="code-identifier">SetCache_Cutoff</span> <span class="code-symbol"><</span><span class="code-identifier">integer</span><span class="code-symbol">></span>count</code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Link Constraint Methods</div>
These used to be erroneously filed under <code>Link_Control</code> and were later removed as a part of the cleanup. They belong to the <a href="http://help.autodesk.com/cloudhelp/2018/ENU/MAXScript-Help/files/GUID-341605ED-A152-43B2-AF96-3A6E329DA085.htm">Link_Constraint</a> chapter.
<pre class="notranslate">
<code><span class="code-keywords3">LinkCtrl</span><span class="code-symbol">.</span><span class="code-identifier">getLinkCount</span> <span class="code-symbol"><</span><span class="code-identifier">controller</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">LinkCtrl</span><span class="code-symbol">.</span><span class="code-identifier">getLinkTime</span> <span class="code-symbol"><</span><span class="code-identifier">controller</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">index</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">LinkCtrl</span><span class="code-symbol">.</span><span class="code-identifier">setLinkTime</span> <span class="code-symbol"><</span><span class="code-identifier">controller</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">index</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">time</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">LinkCtrl</span><span class="code-symbol">.</span><span class="code-identifier">getLinkNode</span> <span class="code-symbol"><</span><span class="code-identifier">controller</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">index</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">LinkCtrl</span><span class="code-symbol">.</span><span class="code-identifier">setLinkNode</span> <span class="code-symbol"><</span><span class="code-identifier">controller</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">index</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">LinkCtrl</span><span class="code-symbol">.</span><span class="code-identifier">addLink</span> <span class="code-symbol"><</span><span class="code-identifier">controller</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">node</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">time</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">LinkCtrl</span><span class="code-symbol">.</span><span class="code-identifier">deleteLink</span> <span class="code-symbol"><</span><span class="code-identifier">controller</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">index</span><span class="code-symbol">></span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Commiting/Reverting Temporary 'Set Key animation mode' Buffers</div>
<pre class="notranslate">
<code><span class="code-keywords3">SetKey</span><span class="code-symbol">.</span><span class="code-identifier">commitBuffer</span> <span class="code-symbol"><</span><span class="code-identifier">MAXWrapper_object</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">SetKey</span><span class="code-symbol">.</span><span class="code-identifier">bufferPresent</span> <span class="code-symbol"><</span><span class="code-identifier">MAXWrapper_object</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">SetKey</span><span class="code-symbol">.</span><span class="code-identifier">revertBuffer</span> <span class="code-symbol"><</span><span class="code-identifier">MAXWrapper_object</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">SetKey</span><span class="code-symbol">.</span><span class="code-identifier">subAnimRevertBuffer</span> <span class="code-symbol"><</span><span class="code-identifier">MAXWrapper_object</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">index</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">SetKey</span><span class="code-symbol">.</span><span class="code-identifier">subAnimCommitBuffer</span> <span class="code-symbol"><</span><span class="code-identifier">MAXWrapper_object</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">index</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">SetKey</span><span class="code-symbol">.</span><span class="code-identifier">subAnimBufferPresent</span> <span class="code-symbol"><</span><span class="code-identifier">MAXWrapper_object</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">index</span><span class="code-symbol">></span></code>
</pre>
<pre class="notranslate">
<code><span class="code-symbol"><</span><span class="code-identifier">bool</span><span class="code-symbol">></span><span class="code-keywords3">maxOps</span><span class="code-symbol">.</span><span class="code-identifier">allTracksCommitSetKeyBuffer</span><span class="code-symbol">()</span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">void</span><span class="code-symbol">></span><span class="code-keywords3">maxOps</span><span class="code-symbol">.</span><span class="code-identifier">allTracksRevertSetKeyBuffer</span><span class="code-symbol">()</span></code>
<code><span class="code-symbol"><</span><span class="code-identifier">void</span><span class="code-symbol">></span><span class="code-keywords3">maxOps</span><span class="code-symbol">.</span><span class="code-identifier">allTracksSetKeyBufferPresent</span><span class="code-symbol">()</span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Visual Leak Detector</div>
<pre class="notranslate"><code><span class="code-keywords3">VLD</span><span class="code-symbol">.</span><span class="code-identifier">Disable</span><span class="code-symbol">()</span></code>
<code><span class="code-keywords3">VLD</span><span class="code-symbol">.</span><span class="code-identifier">Enable</span><span class="code-symbol">()</span></code>
<code><span class="code-keywords3">VLD</span><span class="code-symbol">.</span><span class="code-identifier">Restore</span><span class="code-symbol">()</span></code>
<code><span class="code-keywords3">VLD</span><span class="code-symbol">.</span><span class="code-identifier">ReportLeaks</span><span class="code-symbol">()</span></code>
<code><span class="code-keywords3">VLD</span><span class="code-symbol">.</span><span class="code-identifier">RefreshModules</span><span class="code-symbol">()</span></code>
<code><span class="code-keywords3">VLD</span><span class="code-symbol">.</span><span class="code-identifier">ResolveCallstacks</span><span class="code-symbol">()</span></code>
<code><span class="code-keywords3">VLD</span><span class="code-symbol">.</span><span class="code-identifier">EnableModule</span> <span class="code-symbol"><</span><span class="code-identifier">unused</span><span class="code-symbol">></span> <span class="code-comment">-- just returns OK</span></code>
<code><span class="code-keywords3">VLD</span><span class="code-symbol">.</span><span class="code-identifier">DisableModule</span> <span class="code-symbol"><</span><span class="code-identifier">unused</span><span class="code-symbol">></span> <span class="code-comment">-- just returns OK</span></code>
<code><span class="code-keywords3">VLD</span><span class="code-symbol">.</span><span class="code-identifier">TestLeakMemory</span> <span class="code-symbol"><</span><span class="code-identifier">int_amount</span><span class="code-symbol">></span></code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Exchange Store Plugin Paths</div>
<pre class="notranslate">
<code><span class="code-keywords3">pathConfig</span><span class="code-symbol">.</span><span class="code-identifier">getExchangeStorePlugInInstallPath</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span>plugin</code>
</pre>
<div style="font-size: 11pt; font-weight: bold; padding-bottom: 6px;">Templates and Workspaces</div>
<pre class="notranslate" style="height: 400px;">
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">ShowUI</span><span class="code-symbol">()</span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">ShowNewSceneUI</span><span class="code-symbol">()</span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">GetAllNames</span><span class="code-symbol">()</span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">GetAvailWorkspaces</span><span class="code-symbol">()</span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">Activate</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">GetWorkspace</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">SetWorkspace</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">GetScene</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">GetName</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">GetDescription</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">GetProjectFolder</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">GetThumbnail</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">SelectProjectFolder</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">SelectThumbnail</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">SelectScene</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">SetScene</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">SetName</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">SetDescription</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">SetProjectFolder</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">GetViewSettings</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">GetViewCubeConfig</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">GetRollupConfig</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">GetUIColorSettings</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">GetUserPaths</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">SnapshotViewSettings</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">SnapshotViewCubeConfig</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">SnapshotRollupConfig</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">SnapshotUIColorSettings</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">SnapshotUserPaths</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">Delete</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">Import</span> <span class="code-symbol"><</span><span class="code-identifier">filename</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">Export</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">filename</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">Load</span> <span class="code-symbol"><</span><span class="code-identifier">filename</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">LoadAll</span> <span class="code-symbol"><</span><span class="code-identifier">???</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">Save</span> <span class="code-symbol"><</span><span class="code-identifier">string</span><span class="code-symbol">></span> <span class="code-symbol"><</span><span class="code-identifier">filename</span><span class="code-symbol">></span></code>
<code><span class="code-keywords3">StartupTemplate</span><span class="code-symbol">.</span><span class="code-identifier">SaveAll</span> <span class="code-symbol"><</span><span class="code-identifier">???</span><span class="code-symbol">></span></code>
</pre>
There are of course many more, like the numerous <code>PolyB*</code> methods, and then a whole lot of global scripted structs like uvwManipUtils, PolyBoost, PolyToolsUI, Ribbon_Modeling, Main_Ribbon and heaps of others but while not documented, those are easy to find and study in the stdscripts folder.<br /><br />
<div style="font-family: 'PT Sans',Verdana,sans-serif;">
<p>DISCLAIMER: All scripts and snippets are provided as is under <a href="http://creativecommons.org/publicdomain/zero/1.0/">Creative Commons Zero (public domain, no restrictions) license</a>. The author and this blog cannot be held liable for any loss caused as a result of inaccuracy or error within these web pages. Use at your own risk.</p></div>Swordslayerhttp://www.blogger.com/profile/09124250713006663760noreply@blogger.com3tag:blogger.com,1999:blog-4212150079314071223.post-2061844271404287112017-04-27T10:37:00.000+02:002017-04-27T10:37:58.924+02:00Vectors PrimerUnderstanding vectors is a crucial skill for any technical artist. In this article, we will look at the very basics, both as a refresher for those who already know the concepts and an introduction for the uninitiated.<br />
<a name='more'></a><br />
<a name='more'></a>
<div style="font-size: 10pt; font-weight: bold; padding-bottom: 8px;">What is a Vector?</div><br />
You might recall those arrows of a certain length from the highschool algebra, or you might have already tinkered with vectors in a 3D package where they seem to be used to denote points in space. We will only be dealing with 3D vectors, in the form <code>[x, y, z]</code> where <code>x</code>, <code>y</code> and <code>z</code> are <a href="http://creativescratchpad.blogspot.com/2013/01/maxscript-float-comparison.html">single-precision floating point numbers</a> (basically decimals with limited precision – and it's good to always keep that in mind), that describe a <i>position offset</i> in space in the context of the corresponding axes. In MAXScript, they are represented by the <a href="http://docs.autodesk.com/3DSMAX/15/ENU/MAXScript-Help/files/GUID-1564BD35-50EA-4140-9150-1AECC89F713C.htm">Point3 value</a>.<br /><br />
However, it's important not to treat vectors as a list of numbers or coordinates only – especially since they are not really point coordinates per se. And since showing beats telling every time, let's have a look at this, first of all:<br />
<br />
<div style="border: none; margin-right: 1em; text-align: center;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNgVTn7VgL0qxbeLFHc_fUXUu7NDf-2bThUTUboAROnLqRxL9wFWegXxUNQi883cUrGe9aPWu3EPljD9ibhveZKoSrfyKZHx9JDI_dSpSk3M3MM_BE0bMMZRojfuAj-vgChDeeTP3zqI4/s1600/vector_free.gif" /></div>
<br />
What can we say about it? Well, for one, it is defined by two points. And yet, it's not acutally one vector, it doesn't matter that the point labels are the same. Actually, at each frame we see a different vector. It's not the labelling that defines a it, it's the direction and its length. The vectors on the following images are all identical:<br /><br />
<div style="border: none; margin-right: 1em; text-align: center;"><svg xmlns="http://www.w3.org/2000/svg" width="400" height="167.5" viewBox="0 0 537 224"><style>.a{fill:none;stroke:#c0c0c0;}.b{fill:#c0c0c0;}.c{fill:none;stroke-linejoin:round;stroke:#404040;}.d{fill:none;stroke-linejoin:round;stroke-width:5;stroke:#e0e0e0;}.e{fill:#e0e0e0;}.f{fill:none;stroke-linejoin:round;stroke:#000;}</style><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip1)"><g fill="#202020"><path d="M0 0L537 0 537 224 0 224 0 0z"/></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip2)"><g class="a"><path d="M20.3 2L20.3 224"/></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip3)"><g class="b"><path d="M20.3 1L16.3 17 24.3 17"/></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip4)"><g class="a"><path d="M0 206.1L535 206.1"/></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip5)"><g class="b"><path d="M536 206.1L520 202.1 520 210.1"/></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip6)"><g class="c"><path d="M100.8 0L100.8 224"/></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip7)"><g class="c"><path d="M181.4 0L181.4 224"/></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip8)"><g class="c"><path d="M261.9 0L261.9 224"/></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip9)"><g class="c"><path d="M342.4 0L342.4 224"/></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip10)"><g class="c"><path d="M422.9 0L422.9 224"/></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip11)"><g class="c"><path d="M503.5 0L503.5 224"/></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip12)"><g class="c"><path d="M0 45.1L537 45.1"/></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip13)"><g class="c"><path d="M0 45.1L537 45.1"/></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip14)"><g class="c"><path d="M0 125.6L537 125.6"/></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip15)"><g class="d"><path d="M181.4 125.6L122 66.3"/><title> Vector v</title><desc> Vector v: Vector[A, B]</desc></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip16)"><g class="e"><path d="M100.8 45.1L127.3 61 116.7 71.6z"/><title> Vector v</title><desc> Vector v: Vector[A, B]</desc></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip17)"><g class="d"><path d="M261.9 206.1L202.6 146.8"/><title> Vector u</title><desc> Vector u: Vector[C, A]</desc></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip18)"><g class="e"><path d="M181.4 125.6L207.9 141.5 197.3 152.1z"/><title> Vector u</title><desc> Vector u: Vector[C, A]</desc></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip19)"><g class="d"><path d="M422.9 206.1L363.6 146.8"/><title> Vector u_1</title><desc> Vector u_1: Vector[G, D]</desc></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip20)"><g class="e"><path d="M342.4 125.6L368.9 141.5 358.3 152.1z"/><title> Vector u_1</title><desc> Vector u_1: Vector[G, D]</desc></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip21)"><g class="d"><path d="M503.5 125.6L444.2 66.3"/><title> Vector w</title><desc> Vector w: Vector[F, E]</desc></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip22)"><g class="e"><path d="M422.9 45.1L449.5 61 438.9 71.6z"/><title> Vector w</title><desc> Vector w: Vector[F, E]</desc></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip23)"><g class="e"><path d="M186.4 125.6C186.4 128.4 184.1 130.6 181.4 130.6 178.6 130.6 176.4 128.4 176.4 125.6 176.4 122.8 178.6 120.6 181.4 120.6 184.1 120.6 186.4 122.8 186.4 125.6z"/><title> Point A</title><desc> A = (2, 1)</desc></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip24)"><g class="f"><path d="M186.4 125.6C186.4 128.4 184.1 130.6 181.4 130.6 178.6 130.6 176.4 128.4 176.4 125.6 176.4 122.8 178.6 120.6 181.4 120.6 184.1 120.6 186.4 122.8 186.4 125.6z"/><title> Point A</title><desc> A = (2, 1)</desc></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip26)"><g class="e"><path d="M105.8 45.1C105.8 47.8 103.6 50.1 100.8 50.1 98.1 50.1 95.8 47.8 95.8 45.1 95.8 42.3 98.1 40.1 100.8 40.1 103.6 40.1 105.8 42.3 105.8 45.1z"/><title> Point B</title><desc> B = (1, 2)</desc></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip27)"><g class="f"><path d="M105.8 45.1C105.8 47.8 103.6 50.1 100.8 50.1 98.1 50.1 95.8 47.8 95.8 45.1 95.8 42.3 98.1 40.1 100.8 40.1 103.6 40.1 105.8 42.3 105.8 45.1z"/><title> Point B</title><desc> B = (1, 2)</desc></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip29)"><g class="e"><path d="M266.9 206.1C266.9 208.9 264.6 211.1 261.9 211.1 259.1 211.1 256.9 208.9 256.9 206.1 256.9 203.4 259.1 201.1 261.9 201.1 264.6 201.1 266.9 203.4 266.9 206.1z"/><title> Point C</title><desc> C = (3, 0)</desc></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip30)"><g class="f"><path d="M266.9 206.1C266.9 208.9 264.6 211.1 261.9 211.1 259.1 211.1 256.9 208.9 256.9 206.1 256.9 203.4 259.1 201.1 261.9 201.1 264.6 201.1 266.9 203.4 266.9 206.1z"/><title> Point C</title><desc> C = (3, 0)</desc></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip32)"><g class="e"><path d="M347.4 125.6C347.4 128.4 345.2 130.6 342.4 130.6 339.7 130.6 337.4 128.4 337.4 125.6 337.4 122.8 339.7 120.6 342.4 120.6 345.2 120.6 347.4 122.8 347.4 125.6z"/><title> Point D</title><desc> D = (4, 1)</desc></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip33)"><g class="f"><path d="M347.4 125.6C347.4 128.4 345.2 130.6 342.4 130.6 339.7 130.6 337.4 128.4 337.4 125.6 337.4 122.8 339.7 120.6 342.4 120.6 345.2 120.6 347.4 122.8 347.4 125.6z"/><title> Point D</title><desc> D = (4, 1)</desc></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip35)"><g class="e"><path d="M427.9 45.1C427.9 47.8 425.7 50.1 422.9 50.1 420.2 50.1 417.9 47.8 417.9 45.1 417.9 42.3 420.2 40.1 422.9 40.1 425.7 40.1 427.9 42.3 427.9 45.1z"/><title> Point E</title><desc> E = (5, 2)</desc></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip36)"><g class="f"><path d="M427.9 45.1C427.9 47.8 425.7 50.1 422.9 50.1 420.2 50.1 417.9 47.8 417.9 45.1 417.9 42.3 420.2 40.1 422.9 40.1 425.7 40.1 427.9 42.3 427.9 45.1z"/><title> Point E</title><desc> E = (5, 2)</desc></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip38)"><g class="e"><path d="M427.9 206.1C427.9 208.9 425.7 211.1 422.9 211.1 420.2 211.1 417.9 208.9 417.9 206.1 417.9 203.4 420.2 201.1 422.9 201.1 425.7 201.1 427.9 203.4 427.9 206.1z"/><title> Point G</title><desc> G = (5, 0)</desc></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip39)"><g class="f"><path d="M427.9 206.1C427.9 208.9 425.7 211.1 422.9 211.1 420.2 211.1 417.9 208.9 417.9 206.1 417.9 203.4 420.2 201.1 422.9 201.1 425.7 201.1 427.9 203.4 427.9 206.1z"/><title> Point G</title><desc> G = (5, 0)</desc></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip41)"><g class="e"><path d="M508.5 125.6C508.5 128.4 506.2 130.6 503.5 130.6 500.7 130.6 498.5 128.4 498.5 125.6 498.5 122.8 500.7 120.6 503.5 120.6 506.2 120.6 508.5 122.8 508.5 125.6z"/><title> Point F</title><desc> F = (6, 1)</desc></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><g clip-path="url(#clip42)"><g class="f"><path d="M508.5 125.6C508.5 128.4 506.2 130.6 503.5 130.6 500.7 130.6 498.5 128.4 498.5 125.6 498.5 122.8 500.7 120.6 503.5 120.6 506.2 120.6 508.5 122.8 508.5 125.6z"/><title> Point F</title><desc> F = (6, 1)</desc></g></g><clipPath><path d="M0 0L0 224 537 224 537 0z"/></clipPath><defs><font horiz-adv-x="0"><font-face font-family="Helvetica" font-size="100.00" units-per-em="100.00" ascent="96.67969" descent="21.09375"/><glyph unicode="G" horiz-adv-x="72.266" d="M 63.623 1.9531 Q 50.488 -1.8066 40.723 -1.8066 Q 23.486 -1.8066 14.282 8.0078 Q 5.0781 17.822 5.0781 36.133 Q 5.0781 54.102 14.404 64.087 Q 23.730 74.072 40.576 74.072 Q 51.611 74.072 63.525 70.801 L 63.525 61.328 Q 48.584 66.406 40.625 66.406 Q 28.906 66.406 22.437 58.447 Q 15.967 50.488 15.967 36.035 Q 15.967 21.729 22.900 13.794 Q 29.834 5.8594 42.334 5.8594 Q 47.461 5.8594 53.418 7.6660 L 53.418 31.201 L 63.623 31.201 z"/><glyph unicode="F" horiz-adv-x="53.613" d="M 9.3262 -0.0000 L 9.3262 72.266 L 49.707 72.266 L 49.707 64.600 L 19.580 64.600 L 19.580 40.381 L 44.873 40.381 L 44.873 32.812 L 19.580 32.812 L 19.580 -0.0000 z"/><glyph unicode="E" horiz-adv-x="54.199" d="M 9.3262 -0.0000 L 9.3262 72.266 L 49.707 72.266 L 49.707 64.600 L 19.580 64.600 L 19.580 41.406 L 44.824 41.406 L 44.824 33.838 L 19.580 33.838 L 19.580 7.6660 L 51.807 7.6660 L 51.807 -0.0000 z"/><glyph unicode="D" horiz-adv-x="74.902" d="M 9.3262 -0.0000 L 9.3262 72.266 L 33.350 72.266 Q 44.092 72.266 50.708 69.873 Q 57.324 67.480 62.158 61.768 Q 69.824 52.686 69.824 37.842 Q 69.824 19.824 60.303 9.9121 Q 50.781 -0.0000 33.496 -0.0000 z M 19.580 7.6660 L 32.715 7.6660 Q 46.777 7.6660 52.637 15.234 Q 58.936 23.291 58.936 36.865 Q 58.936 49.609 52.734 56.885 Q 48.975 61.328 43.750 62.964 Q 38.525 64.600 28.027 64.600 L 19.580 64.600 z"/><glyph unicode="C" horiz-adv-x="69.189" d="M 40.283 -1.8066 Q 23.438 -1.8066 14.258 8.0811 Q 5.0781 17.969 5.0781 36.084 Q 5.0781 54.150 14.429 64.111 Q 23.779 74.072 40.771 74.072 Q 50.488 74.072 63.525 70.898 L 63.525 61.279 Q 48.682 66.406 40.625 66.406 Q 28.857 66.406 22.412 58.447 Q 15.967 50.488 15.967 35.986 Q 15.967 22.168 22.852 14.185 Q 29.736 6.2012 41.650 6.2012 Q 51.904 6.2012 63.623 12.500 L 63.623 3.7109 Q 52.930 -1.8066 40.283 -1.8066 z"/><glyph unicode="B" horiz-adv-x="57.520" d="M 9.3262 -0.0000 L 9.3262 72.266 L 28.076 72.266 Q 38.916 72.266 44.702 68.164 Q 50.488 64.062 50.488 56.348 Q 50.488 43.213 35.645 37.646 Q 53.369 32.227 53.369 18.066 Q 53.369 9.2773 47.510 4.6387 Q 41.650 -0.0000 30.615 -0.0000 z M 19.482 7.6660 L 21.582 7.6660 Q 32.861 7.6660 36.182 9.0820 Q 42.529 11.768 42.529 19.043 Q 42.529 25.488 36.768 29.761 Q 31.006 34.033 22.363 34.033 L 19.482 34.033 z M 19.482 40.527 L 22.754 40.527 Q 30.957 40.527 35.474 44.043 Q 39.990 47.559 39.990 53.955 Q 39.990 64.600 23.486 64.600 L 19.482 64.600 z"/><glyph unicode="A" horiz-adv-x="68.994" d="M 45.947 27.637 L 33.643 58.789 L 21.289 27.637 z M 56.787 -0.0000 L 48.926 20.020 L 18.311 20.020 L 10.352 -0.0000 L .83008 -0.0000 L 29.492 72.266 L 39.648 72.266 L 67.871 -0.0000 z"/></font></defs></svg></div>
<br />You might have seen the concept described as a directed magnitude and while that's definitely more exact, I want you to think about the 3D vectors we will be using primarily as <i>position offsets</i>.<br />
<br />What does it mean? Different things in different contexts:<ul>
<li>when used for point positions in world space, a vector describes the position offset from the scene origin,</li>
<li>in local space it's a position offset from the center of the object's coordinate system,</li>
<li>for a pair of points it's a direction and distance to get from one to the other,</li>
<li>and sometimes, like for example with normal vectors, we care mostly only about the direction part.</li></ul>
<br />And as vectors are position-less, i.e. you can move a vector all around and it's still the same vector, let's respect the convention of placing the starting point at the origin:<br />
<br />
<div style=border:none;margin-right:1em;text-align:center><svg height=175 viewBox="0 0 536 238"width=400 xmlns=http://www.w3.org/2000/svg><g stroke-linecap=square stroke-linejoin=miter stroke-width=1.0000 stroke-dasharray=none stroke-dashoffset=0.0000 stroke-miterlimit=10.000><clipPath id=clip1><path d="M 0.0000 0.0000 L 0.0000 238.00 L 536.00 238.00 L 536.00 0.0000 z"/></clipPath><g clip-path=url(#clip1)><g fill=#202020 stroke=none fill-opacity=1.0000 fill-rule=nonzero><path d="M 0.0000 0.0000 L 536.00 0.0000 L 536.00 238.00 L 0.0000 238.00 L 0.0000 0.0000 z"/></g></g><clipPath id=clip2><path d="M 0.0000 0.0000 L 0.0000 238.00 L 536.00 238.00 L 536.00 0.0000 z"/></clipPath><g clip-path=url(#clip2)><g fill=none stroke=#c0c0c0 stroke-linecap=butt stroke-opacity=1.0000><path d="M 54.299 2.0000 L 54.299 238.00"/></g></g><clipPath id=clip3><path d="M 0.0000 0.0000 L 0.0000 238.00 L 536.00 238.00 L 536.00 0.0000 z"/></clipPath><g clip-path=url(#clip3)><g fill=#c0c0c0 stroke=none fill-opacity=1.0000 fill-rule=evenodd><path d="M 54.299 1.0000 L 50.299 17.000 L 58.299 17.000"/></g></g><clipPath id=clip4><path d="M 0.0000 0.0000 L 0.0000 238.00 L 536.00 238.00 L 536.00 0.0000 z"/></clipPath><g clip-path=url(#clip4)><g fill=none stroke=#c0c0c0 stroke-linecap=butt stroke-opacity=1.0000><path d="M 0.0000 200.12 L 534.00 200.12"/></g></g><clipPath id=clip5><path d="M 0.0000 0.0000 L 0.0000 238.00 L 536.00 238.00 L 536.00 0.0000 z"/></clipPath><g clip-path=url(#clip5)><g fill=#c0c0c0 stroke=none fill-opacity=1.0000 fill-rule=evenodd><path d="M 535.00 200.12 L 519.00 196.12 L 519.00 204.12"/></g></g><clipPath id=clip6><path d="M 0.0000 0.0000 L 0.0000 238.00 L 536.00 238.00 L 536.00 0.0000 z"/></clipPath><g clip-path=url(#clip6)><g fill=none stroke=#404040 stroke-linecap=round stroke-opacity=1.0000 stroke-linejoin=round><path d="M 134.83 0.0000 L 134.83 238.00"/></g></g><clipPath id=clip7><path d="M 0.0000 0.0000 L 0.0000 238.00 L 536.00 238.00 L 536.00 0.0000 z"/></clipPath><g clip-path=url(#clip7)><g fill=none stroke=#404040 stroke-linecap=round stroke-opacity=1.0000 stroke-linejoin=round><path d="M 215.35 0.0000 L 215.35 238.00"/></g></g><clipPath id=clip8><path d="M 0.0000 0.0000 L 0.0000 238.00 L 536.00 238.00 L 536.00 0.0000 z"/></clipPath><g clip-path=url(#clip8)><g fill=none stroke=#404040 stroke-linecap=round stroke-opacity=1.0000 stroke-linejoin=round><path d="M 295.88 0.0000 L 295.88 238.00"/></g></g><clipPath id=clip9><path d="M 0.0000 0.0000 L 0.0000 238.00 L 536.00 238.00 L 536.00 0.0000 z"/></clipPath><g clip-path=url(#clip9)><g fill=none stroke=#404040 stroke-linecap=round stroke-opacity=1.0000 stroke-linejoin=round><path d="M 376.41 0.0000 L 376.41 238.00"/></g></g><clipPath id=clip10><path d="M 0.0000 0.0000 L 0.0000 238.00 L 536.00 238.00 L 536.00 0.0000 z"/></clipPath><g clip-path=url(#clip10)><g fill=none stroke=#404040 stroke-linecap=round stroke-opacity=1.0000 stroke-linejoin=round><path d="M 456.94 0.0000 L 456.94 238.00"/></g></g><clipPath id=clip11><path d="M 0.0000 0.0000 L 0.0000 238.00 L 536.00 238.00 L 536.00 0.0000 z"/></clipPath><g clip-path=url(#clip11)><g fill=none stroke=#404040 stroke-linecap=round stroke-opacity=1.0000 stroke-linejoin=round><path d="M 0.0000 39.064 L 536.00 39.064"/></g></g><clipPath id=clip12><path d="M 0.0000 0.0000 L 0.0000 238.00 L 536.00 238.00 L 536.00 0.0000 z"/></clipPath><g clip-path=url(#clip12)><g fill=none stroke=#404040 stroke-linecap=round stroke-opacity=1.0000 stroke-linejoin=round><path d="M 0.0000 39.064 L 536.00 39.064"/></g></g><clipPath id=clip13><path d="M 0.0000 0.0000 L 0.0000 238.00 L 536.00 238.00 L 536.00 0.0000 z"/></clipPath><g clip-path=url(#clip13)><g fill=none stroke=#404040 stroke-linecap=round stroke-opacity=1.0000 stroke-linejoin=round><path d="M 0.0000 119.59 L 536.00 119.59"/></g></g><g id=misc></g><g id=layer0><clipPath id=clip14><path d="M 0.0000 0.0000 L 0.0000 238.00 L 536.00 238.00 L 536.00 0.0000 z"/></clipPath><g clip-path=url(#clip14)><g fill=none stroke=#c0c0c0 stroke-linecap=butt stroke-opacity=1.0000 stroke-linejoin=round stroke-width=2.0000 stroke-dasharray=10.000,8.0000><path d="M 456.94 119.59 L 456.94 200.12"/><title>Segment g</title><desc>Segment g: Segment [B, C]</desc></g></g><clipPath id=clip15><path d="M 0.0000 0.0000 L 0.0000 238.00 L 536.00 238.00 L 536.00 0.0000 z"/></clipPath><g clip-path=url(#clip15)><g fill=none stroke=#c0c0c0 stroke-linecap=butt stroke-opacity=1.0000 stroke-linejoin=round stroke-width=2.0000 stroke-dasharray=10.000,8.0000><path d="M 54.299 119.59 L 456.94 119.59"/><title>Segment i</title><desc>Segment i: Segment [D, B]</desc></g></g><clipPath id=clip16><path d="M 0.0000 0.0000 L 0.0000 238.00 L 536.00 238.00 L 536.00 0.0000 z"/></clipPath><g clip-path=url(#clip16)><g fill=none stroke=#c0c0c0 stroke-linecap=butt stroke-opacity=1.0000 stroke-linejoin=round stroke-width=2.0000 stroke-dasharray=10.000,8.0000><path d="M 134.83 39.064 L 54.299 39.064"/><title>Segment j</title><desc>Segment j: Segment [A, E]</desc></g></g><clipPath id=clip17><path d="M 0.0000 0.0000 L 0.0000 238.00 L 536.00 238.00 L 536.00 0.0000 z"/></clipPath><g clip-path=url(#clip17)><g fill=none stroke=#c0c0c0 stroke-linecap=butt stroke-opacity=1.0000 stroke-linejoin=round stroke-width=2.0000 stroke-dasharray=10.000,8.0000><path d="M 134.83 39.064 L 134.83 200.92"/><title>Segment k</title><desc>Segment k: Segment [A, F]</desc></g></g><clipPath id=clip18><path d="M 0.0000 0.0000 L 0.0000 238.00 L 536.00 238.00 L 536.00 0.0000 z"/></clipPath><g clip-path=url(#clip18)><g fill=none stroke=#e0e0e0 stroke-linecap=round stroke-opacity=1.0000 stroke-linejoin=round stroke-width=5.0000><path d="M 54.299 200.12 L 427.52 125.47"/><title>Vector u</title><desc>Vector u: Vector[O, B]</desc></g></g><clipPath id=clip19><path d="M 0.0000 0.0000 L 0.0000 238.00 L 536.00 238.00 L 536.00 0.0000 z"/></clipPath><g clip-path=url(#clip19)><g fill=#e0e0e0 stroke=none fill-opacity=1.0000 fill-rule=evenodd><path d="M 456.94 119.59 L 428.99 132.83 L 426.05 118.12 z"/><title>Vector u</title><desc>Vector u: Vector[O, B]</desc></g></g><clipPath id=clip20><path d="M 0.0000 0.0000 L 0.0000 238.00 L 536.00 238.00 L 536.00 0.0000 z"/></clipPath><g clip-path=url(#clip20)><g fill=none stroke=#e0e0e0 stroke-linecap=round stroke-opacity=1.0000 stroke-linejoin=round stroke-width=5.0000><path d="M 54.299 200.12 L 121.41 65.897"/><title>Vector v</title><desc>Vector v: Vector[O, A]</desc></g></g><clipPath id=clip21><path d="M 0.0000 0.0000 L 0.0000 238.00 L 536.00 238.00 L 536.00 0.0000 z"/></clipPath><g clip-path=url(#clip21)><g fill=#e0e0e0 stroke=none fill-opacity=1.0000 fill-rule=evenodd><path d="M 134.83 39.064 L 128.12 69.251 L 114.70 62.542 z"/><title>Vector v</title><desc>Vector v: Vector[O, A]</desc></g></g><clipPath id=clip22><path d="M 0.0000 0.0000 L 0.0000 238.00 L 536.00 238.00 L 536.00 0.0000 z"/></clipPath><g clip-path=url(#clip22)><g fill=#e0e0e0 stroke=none fill-opacity=1.0000 fill-rule=nonzero><path d="M 461.94 119.59 C 461.94 122.35 459.70 124.59 456.94 124.59 C 454.18 124.59 451.94 122.35 451.94 119.59 C 451.94 116.83 454.18 114.59 456.94 114.59 C 459.70 114.59 461.94 116.83 461.94 119.59 z"/><title>Point B</title><desc>B = (5, 1)</desc></g></g><clipPath id=clip23><path d="M 0.0000 0.0000 L 0.0000 238.00 L 536.00 238.00 L 536.00 0.0000 z"/></clipPath><g clip-path=url(#clip23)><g fill=none stroke=#000000 stroke-linecap=round stroke-opacity=1.0000 stroke-linejoin=round><path d="M 461.94 119.59 C 461.94 122.35 459.70 124.59 456.94 124.59 C 454.18 124.59 451.94 122.35 451.94 119.59 C 451.94 116.83 454.18 114.59 456.94 114.59 C 459.70 114.59 461.94 116.83 461.94 119.59 z"/><title>Point B</title><desc>B = (5, 1)</desc></g></g><clipPath id=clip24><path d="M 0.0000 0.0000 L 0.0000 238.00 L 536.00 238.00 L 536.00 0.0000 z"/></clipPath><g clip-path=url(#clip24)><g transform="matrix(1.0000, 0.0000, 0.0000, 1.0000, 441.00, 110.00)"><text fill=#e0e0e0 fill-opacity=1.0000 font-family=Helvetica font-size=16.000 font-style=normal font-weight=normal stroke=none x=0 y=0>B = [5, 1, 0]</text></g></g><clipPath id=clip25><path d="M 0.0000 0.0000 L 0.0000 238.00 L 536.00 238.00 L 536.00 0.0000 z"/></clipPath><g clip-path=url(#clip25)><g fill=#e0e0e0 stroke=none fill-opacity=1.0000 fill-rule=nonzero><path d="M 59.299 200.12 C 59.299 202.88 57.060 205.12 54.299 205.12 C 51.537 205.12 49.299 202.88 49.299 200.12 C 49.299 197.36 51.537 195.12 54.299 195.12 C 57.060 195.12 59.299 197.36 59.299 200.12 z"/><title>Point O</title><desc>O = (0, 0)</desc></g></g><clipPath id=clip26><path d="M 0.0000 0.0000 L 0.0000 238.00 L 536.00 238.00 L 536.00 0.0000 z"/></clipPath><g clip-path=url(#clip26)><g fill=none stroke=#000000 stroke-linecap=round stroke-opacity=1.0000 stroke-linejoin=round><path d="M 59.299 200.12 C 59.299 202.88 57.060 205.12 54.299 205.12 C 51.537 205.12 49.299 202.88 49.299 200.12 C 49.299 197.36 51.537 195.12 54.299 195.12 C 57.060 195.12 59.299 197.36 59.299 200.12 z"/><title>Point O</title><desc>O = (0, 0)</desc></g></g><clipPath id=clip27><path d="M 0.0000 0.0000 L 0.0000 238.00 L 536.00 238.00 L 536.00 0.0000 z"/></clipPath><g clip-path=url(#clip27)><g fill=#e0e0e0 stroke=none fill-opacity=1.0000 fill-rule=nonzero><path d="M 139.83 39.064 C 139.83 41.825 137.59 44.064 134.83 44.064 C 132.06 44.064 129.83 41.825 129.83 39.064 C 129.83 36.302 132.06 34.064 134.83 34.064 C 137.59 34.064 139.83 36.302 139.83 39.064 z"/><title>Point A</title><desc>A = (1, 2)</desc></g></g><clipPath id=clip28><path d="M 0.0000 0.0000 L 0.0000 238.00 L 536.00 238.00 L 536.00 0.0000 z"/></clipPath><g clip-path=url(#clip28)><g fill=none stroke=#000000 stroke-linecap=round stroke-opacity=1.0000 stroke-linejoin=round><path d="M 139.83 39.064 C 139.83 41.825 137.59 44.064 134.83 44.064 C 132.06 44.064 129.83 41.825 129.83 39.064 C 129.83 36.302 132.06 34.064 134.83 34.064 C 137.59 34.064 139.83 36.302 139.83 39.064 z"/><title>Point A</title><desc>A = (1, 2)</desc></g></g><clipPath id=clip29><path d="M 0.0000 0.0000 L 0.0000 238.00 L 536.00 238.00 L 536.00 0.0000 z"/></clipPath><g clip-path=url(#clip29)><g transform="matrix(1.0000, 0.0000, 0.0000, 1.0000, 139.00, 29.000)"><text fill=#e0e0e0 fill-opacity=1.0000 font-family=Helvetica font-size=16.000 font-style=normal font-weight=normal stroke=none x=0 y=0>A = [1, 2, 0]</text></g></g><clipPath id=clip30><path d="M 0.0000 0.0000 L 0.0000 238.00 L 536.00 238.00 L 536.00 0.0000 z"/></clipPath><g clip-path=url(#clip30)><g transform="matrix(1.0000, 0.0000, 0.0000, 1.0000, 219.00, 148.00)"><text fill=#e0e0e0 fill-opacity=1.0000 font-family=Helvetica font-size=16.000 font-style=normal font-weight=normal stroke=none x=0 y=0>5.1</text></g></g><clipPath id=clip31><path d="M 0.0000 0.0000 L 0.0000 238.00 L 536.00 238.00 L 536.00 0.0000 z"/></clipPath><g clip-path=url(#clip31)><g transform="matrix(1.0000, 0.0000, 0.0000, 1.0000, 65.000, 83.000)"><text fill=#e0e0e0 fill-opacity=1.0000 font-family=Helvetica font-size=16.000 font-style=normal font-weight=normal stroke=none x=0 y=0>2.24</text></g></g></g><defs><font horiz-adv-x=0 id=Helvetica><font-face ascent=96.67969 descent=21.09375 font-family=Helvetica font-size=100.00 font-style=normal font-weight=normal units-per-em=100.00 /><missing-glyph d=""/><glyph d="M 9.6191 -14.453 L 9.6191 77.100 L 28.906 77.100 L 28.906 69.873 L 18.066 69.873 L 18.066 -7.2266 L 28.906 -7.2266 L 28.906 -14.453 z"horiz-adv-x=32.520 unicode=[ /><glyph d=""horiz-adv-x=31.641 unicode=" "/><glyph d="M 10.840 16.260 L 10.840 23.486 L 68.652 23.486 L 68.652 16.260 z M 10.840 34.326 L 10.840 41.553 L 68.652 41.553 L 68.652 34.326 z"horiz-adv-x=79.492 unicode="="/><glyph d="M 12.158 -.29297 L 12.158 8.3008 Q 19.336 5.4199 25.830 5.4199 Q 32.959 5.4199 37.036 9.6191 Q 41.113 13.818 41.113 21.191 Q 41.113 37.451 18.701 37.451 Q 16.162 37.451 13.379 37.109 L 13.379 72.266 L 49.951 72.266 L 49.951 63.867 L 21.826 63.867 L 21.826 44.824 Q 35.742 44.824 43.555 38.428 Q 51.367 32.031 51.367 20.703 Q 51.367 10.156 44.263 4.1748 Q 37.158 -1.8066 24.561 -1.8066 Q 19.092 -1.8066 12.158 -.29297 z"horiz-adv-x=63.232 unicode=5 /><glyph d="M 37.646 -0.0000 L 37.646 20.459 L 5.1270 20.459 L 5.1270 27.734 L 37.646 72.266 L 46.680 72.266 L 46.680 28.320 L 56.348 28.320 L 56.348 20.459 L 46.680 20.459 L 46.680 -0.0000 z M 14.551 28.320 L 38.281 28.320 L 38.281 60.449 z"horiz-adv-x=63.232 unicode=4 /><glyph d="M 15.039 -0.0000 L 15.039 7.2266 L 29.492 7.2266 L 29.492 64.258 L 15.039 60.645 L 15.039 68.066 L 39.160 74.072 L 39.160 7.2266 L 53.613 7.2266 L 53.613 -0.0000 z"horiz-adv-x=63.232 unicode=1 /><glyph d="M 31.348 -1.8066 Q 20.166 -1.8066 13.257 8.7158 Q 6.3477 19.238 6.3477 36.182 Q 6.3477 53.271 13.306 63.672 Q 20.264 74.072 31.641 74.072 Q 43.018 74.072 49.976 63.672 Q 56.934 53.271 56.934 36.328 Q 56.934 18.945 49.976 8.5693 Q 43.018 -1.8066 31.348 -1.8066 z M 31.445 5.4199 Q 46.729 5.4199 46.729 36.475 Q 46.729 66.846 31.641 66.846 Q 16.602 66.846 16.602 36.182 Q 16.602 5.4199 31.445 5.4199 z"horiz-adv-x=63.232 unicode=0 /><glyph d="M 8.3008 -0.0000 L 8.3008 8.4473 Q 12.500 18.262 25.293 29.834 L 30.811 34.766 Q 41.455 44.385 41.455 53.857 Q 41.455 59.912 37.817 63.379 Q 34.180 66.846 27.832 66.846 Q 20.312 66.846 10.107 61.035 L 10.107 69.531 Q 19.727 74.072 29.199 74.072 Q 39.355 74.072 45.508 68.604 Q 51.660 63.135 51.660 54.102 Q 51.660 47.607 48.560 42.578 Q 45.459 37.549 37.012 30.371 L 33.301 27.197 Q 21.729 17.383 19.922 8.4473 L 51.318 8.4473 L 51.318 -0.0000 z"horiz-adv-x=63.232 unicode=2 /><glyph d="M 9.7656 -0.0000 L 9.7656 12.061 L 21.826 12.061 L 21.826 -0.0000 z"horiz-adv-x=31.641 unicode=. /><glyph d="M 9.7656 -15.674 L 9.7656 -12.061 Q 14.453 -10.742 14.453 -.97656 L 14.453 -0.0000 L 9.7656 -0.0000 L 9.7656 12.061 L 21.826 12.061 L 21.826 1.6113 Q 21.826 -14.453 9.7656 -15.674 z"horiz-adv-x=31.641 unicode=, /><glyph d="M 9.3262 -0.0000 L 9.3262 72.266 L 28.076 72.266 Q 38.916 72.266 44.702 68.164 Q 50.488 64.062 50.488 56.348 Q 50.488 43.213 35.645 37.646 Q 53.369 32.227 53.369 18.066 Q 53.369 9.2773 47.510 4.6387 Q 41.650 -0.0000 30.615 -0.0000 z M 19.482 7.6660 L 21.582 7.6660 Q 32.861 7.6660 36.182 9.0820 Q 42.529 11.768 42.529 19.043 Q 42.529 25.488 36.768 29.761 Q 31.006 34.033 22.363 34.033 L 19.482 34.033 z M 19.482 40.527 L 22.754 40.527 Q 30.957 40.527 35.474 44.043 Q 39.990 47.559 39.990 53.955 Q 39.990 64.600 23.486 64.600 L 19.482 64.600 z"horiz-adv-x=57.520 unicode=B /><glyph d="M 45.947 27.637 L 33.643 58.789 L 21.289 27.637 z M 56.787 -0.0000 L 48.926 20.020 L 18.311 20.020 L 10.352 -0.0000 L .83008 -0.0000 L 29.492 72.266 L 39.648 72.266 L 67.871 -0.0000 z"horiz-adv-x=68.994 unicode=A /><glyph d="M 22.900 -14.453 L 22.900 77.100 L 3.6133 77.100 L 3.6133 69.873 L 14.453 69.873 L 14.453 -7.2266 L 3.6133 -7.2266 L 3.6133 -14.453 z"horiz-adv-x=32.520 unicode=] /></font></defs></g></svg></div><br />
<div style="font-size: 10pt; font-weight: bold; padding-bottom: 8px;">Vector Addition</div><br />
You might remember that adding vectors graphically amounts to sticking a starting point of one vector to the end point of the other one, optionally adding other vectors iteratively, and in the end connecting the starting point of the first one with the end point of the last one. The order is arbitrary and <a href="http://www.physicsclassroom.com/mmedia/vectors/ao.gif/">doesn't matter</a>.<br /><br />
<div style="border: none; margin-right: 1em; text-align: center;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh23oL1TvHi9V_aF5ppj7P30aM8qUVG4BWJz_tS0KZ7BtF5XOcMm6gjeqssvXV8yHFcxC2j08w5yBNi7V_ml0wQXtmR3EDhtcEbwDcozO_bvcEsaMufz9ptVDFwQzIfXao-GiczsJyc024/s320/vector_addition.gif" width="400" height="184" /></div><br />
That's true and lends itself nicely to the notion of vectors as position offsets in space, but let's have a look at another way to look at it. As I've said before, I will stick to the convention of placing vector starting points at the origin, and I do that for a reason:<br /><br />
<div style="border: 0; margin-right: 1em; text-align: center;"><iframe scrolling="no" src="https://www.geogebra.org/material/iframe/id/sRerk3fu/width/400/height/312/border/212121" width="400px" height="312px" title="Vector Addition" style="border:1px solid #222;"> </iframe></div><br />
The difference from the previous image is that here all the vectors are placed so that they start at the <code>[0,0]</code> point. Instead of putting the other vector in the addition to the end of the first one, let's draw a thin dashed line. As you can see, for both vectors, the end point of the dashed line ends up in the same place, at the end of the diagonal of the parallelogram created by the vectors. This diagonal is the resulting vector.<br /><br />
Try and move the vertex handles around, and you will see that when both the vectors are of the same magnitude (length), their sum is a vector that halves their angle. If one of them is bigger, it drags the resulting vector more towards itself.<br /><br />
When expressed numerically, matching pairs of coordinates are added together:<br />
<pre class="notranslate"><span class="code-symbol">[</span><span class="code-number">1</span><span class="code-symbol">, </span><span class="code-number">0</span><span class="code-symbol">, </span><span class="code-number">5</span><span class="code-symbol">] + [-</span><span class="code-number">10</span><span class="code-symbol">, </span><span class="code-number">2</span><span class="code-symbol">, </span><span class="code-number">0</span><span class="code-symbol">] = [-</span><span class="code-number">9</span><span class="code-symbol">, </span><span class="code-number">2</span><span class="code-symbol">, </span><span class="code-number">5</span><span class="code-symbol">]</span></pre>
What can you use that for?<br/>
<ul><li>With more vectors of the same length, the resulting vector will point in their average direction (unless they cancel out each other).</li>
<li>When their lengths are different, the result is a weighted average (used in weighted normals where small faces contribute a smaller amount).</li></ul>
You can visualize any 3D vector by creating axis vectors from its components. It is also a nice demonstration of vector addition in 3D space, note that in this case, the resulting vector is also a diagonal of the imaginary bounding box of the three vectors:<br /><br />
<div style="border: none; margin-right: 1em; text-align: center;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhN6cKgbceeCBe7MJuAr8oqylVf5UOuLtDfv6JE8UFa_eRjDWXzJB6jTzGEFq5LJp9-OEMs4Ix9DX9vXRtdpBIALOpckqfHCr4OBu35iaDOQmzwFkm9KerEPhNFoeKn0ujTnTR0UPzFXEo/s1600/vectors.gif" width="400" height="345" /></div><br />
Since the axis vectors come handy pretty often, there are predefined MAXScript globals <code>x_axis</code>, <code>y_axis</code> and <code>z_axis</code> that contain the values <code>[1,0,0]</code>, <code>[0,1,0]</code> and <code>[0,0,1]</code> respectively.<br /><br />
<div style="font-size: 10pt; font-weight: bold; padding-bottom: 8px;">Vector Subtraction</div><br />
Vector subtraction follows exactly the same rules, only flipping the vector that's negated. For a pair of vectors, it helps to think about it as the other diagonal of the parallelogram, the one that connects the end points of the two vectors when they share the same starting point (which is true for example for all positions in space measured from the origin point). The direction of the resulting vector depends on whether we are subtracting <i>A</i> from <i>B</i> or <i>B</i> from <i>A</i>.<br /><br />
In the next example, <i>A</i> is the vector that is subtracted from <i>B</i>, and as such becomes the new 'origin' point for the resulting vector. Whenever you find yourself deciding what to subtract from what, ask yourself what you want to treat as the <i>origin</i> – the subtracted position effectively becomes one. Grab the vector handles and see how the result changes:<br /><br />
<div style="border: 0; margin-right: 1em; text-align: center;"><iframe scrolling="no" src="https://www.geogebra.org/material/iframe/id/Djb5Ej8Q/width/400/height/345/border/212121" width="400px" height="345px" title="Vector Subtraction" style="border:1px solid #222; "> </iframe></div><br />
You can also think of it this way: subtracting <code>[0,0,0]</code> from any position gives you the position difference that needs to be added to the origin <code>[0,0,0]</code> to get to that given position. The line <i>AB</i> is described by points <i>A</i> and <i>B</i>, and if you subtract <i>A</i> from both of them, the first one is suddenly <code>[0,0,0]</code> – and the other one is <i>(B - A)</i> – our new vector.<br /><br />
<div style="font-family: 'PT Sans',Verdana,sans-serif;">
DISCLAIMER: All scripts and snippets are provided as is under <a href="http://creativecommons.org/publicdomain/zero/1.0/">Creative Commons Zero (public domain, no restrictions) license</a>. All the diagrams and presentations on the page are made using <a href="http://www.geogebra.org">GeoGebra</a> and are made available under the terms of the <a href="http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode">Creative Commons Attribution-NonCommercial-ShareAlike license</a>. The author and this blog cannot be held liable for any loss caused as a result of inaccuracy or error within these web pages.<br />
<br />
</div>Swordslayerhttp://www.blogger.com/profile/09124250713006663760noreply@blogger.com0tag:blogger.com,1999:blog-4212150079314071223.post-56313202848446115842013-01-31T21:32:00.000+01:002013-01-31T21:32:57.449+01:00Comparing float values<p>Dealing with floating point values in MAXScript is almost inevitable, as are the accuracy problems connected to that.</p><a name='more'></a>
<div style="font-weight:bold; font-size: 10pt; padding-bottom:8px">Floating point numbers</div>
<p>Most of the floats you will deal with in MAXScript are single precision floats, be it controller values, point3 values of normals and positions etc. When you are free to do the calculations the way you want, it more sense to use for example doubles instead, but not in the cases mentioned above. Meet <a href="http://en.wikipedia.org/wiki/Single-precision_floating-point_format#IEEE_754_single-precision_binary_floating-point_format:_binary32" title="Wikipedia :: Single precision floating point format">IEEE-754</a>, by its definition, this format has 6 to 9 significant decimal digits precision, and addition is not necessarily associative which can lead to all sorts of interesting errors (but arguably that would be outside the scope of this topic – if you are interested in learning more, refer to <a href="http://floating-point-gui.de/">What Every Programmer Should Know About Floating-Point Arithmetic</a>). Suffice it to say that one should always be careful when mixing small and large numbers:</p>
<pre class="notranslate">
<code><span class="code-number">12345</span><span class="code-symbol">.</span><span class="code-number">0</span> <span class="code-symbol">+</span> <span class="code-number">0</span><span class="code-symbol">.</span><span class="code-number">54321</span> <span class="code-symbol">==</span> <span class="code-number">12345</span><span class="code-symbol">.</span><span class="code-number">0</span> <span class="code-symbol">+</span> <span class="code-number">0</span><span class="code-symbol">.</span><span class="code-number">543</span> <span class="code-comment">--> true</span></code>
</pre>
<p>Nearly every MAXScript coder (or rather any coder using single precision floats) has been bitten by something like that before, and there are many ways how to cimcurvent it if all you need is testing the values for equality. The easiest way is getting the difference of the two terms, if that is smaller than some deliberately chosen epsilon value, we treat them as equal values:</p>
<pre class="notranslate">
<code><span class="code-keywords1">fn</span> <span class="code-identifier">areFloatsEquivalent</span> <span class="code-identifier">f1</span> <span class="code-identifier">f2</span> <span class="code-identifier">eps</span><span class="code-symbol">:</span><span class="code-number">1e</span><span class="code-symbol">-</span><span class="code-number">6</span> <span class="code-symbol">=</span></code>
<code> <span class="code-identifier">f1</span> <span class="code-symbol">==</span> <span class="code-identifier">f2</span> <span class="code-keywords2">OR</span> <span class="code-keywords3">abs</span> <span class="code-symbol">(</span><span class="code-identifier">f1</span> <span class="code-symbol">-</span> <span class="code-identifier">f2</span><span class="code-symbol">)</span> <span class="code-symbol"><=</span> <span class="code-identifier">eps</span></code>
</pre>
<p>The advantage of this method is that you can manually set the epsilon to whatever value suits you at the moment and it tends to be good enough when you roughly know what order of magnitude are the values you are comparing. With large numbers, however, the epsilon could actually be smaller than the rounding error, and the comparison would always returns <code>false</code>. As this is quite a common issue, there is a built-in function that solves this, namely <code>close_enough</code> – use it whenever it makes sense. If you are curious about the implementation, written in maxscript it would be:</p>
<pre class="notranslate">
<code><span class="code-keywords1">fn</span> <span class="code-identifier">close_enough_mxs</span> <span class="code-identifier">f1</span> <span class="code-identifier">f2</span> <span class="code-identifier">rounds</span> <span class="code-identifier">eps</span><span class="code-symbol">:</span><span class="code-number">1</span><span class="code-symbol">.</span><span class="code-number">19209e</span><span class="code-symbol">-</span><span class="code-number">7</span> <span class="code-symbol">=</span></code>
<code> <span class="code-identifier">f1</span> <span class="code-symbol">==</span> <span class="code-identifier">f2</span> <span class="code-keywords2">OR</span> <span class="code-number">2</span><span class="code-symbol">.</span><span class="code-number">0</span> <span class="code-symbol">*</span> <span class="code-keywords3">abs</span><span class="code-symbol">(</span><span class="code-identifier">f1</span> <span class="code-symbol">-</span> <span class="code-identifier">f2</span><span class="code-symbol">)/(</span><span class="code-keywords3">abs</span> <span class="code-identifier">f1</span> <span class="code-symbol">+</span> <span class="code-keywords3">abs</span> <span class="code-identifier">f2</span><span class="code-symbol">)</span> <span class="code-symbol"><</span> <span class="code-identifier">rounds</span> <span class="code-symbol">*</span> <span class="code-identifier">eps</span></code>
</pre>
<p>The value 1.19209e-7 used here is the delta of 1.0 and the next distinguishable float value. If you want to know the value for floats in a different range than around the 1.0, there is an easy way to find out. Under Customize menu item, System Unit Setup pop-up of the Unit Setup dialog shows an interactive slider where you can see the value in a given range:</p>
<div style="margin-right: 1em; text-align: center; border:none;"><a name="Float Precision" imageanchor="1"><img alt="System Unit Setup :: Float Precision" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxSiGSne_ppHrkVkkFf2QOomcn0lkDBC843vqkQPnLwuFwV1loIZIWEjPx3ce8jwXwW-tjHAu1KnE9ZcwV40O5duQ-ede1CtNCuzaAOQPPYIzId4F0ivy-GYURd4AEa0-kISyLYQOLX7Q/s1600/system_unit_setup.png" title="System Unit Setup :: Float Precision" /></a></div><br />
<p>If you are curious as to how to get these values in a script, here is a function for that:</p>
<pre class="notranslate">
<code><span class="code-keywords1">fn</span> <span class="code-identifier">floatAccuracy</span> <span class="code-identifier">nr</span> <span class="code-symbol">=</span></code>
<code> <span class="code-number">2</span><span class="code-symbol">.^(</span><span class="code-keywords3">int</span><span class="code-symbol">(</span><span class="code-keywords3">log</span> <span class="code-identifier">nr</span> <span class="code-symbol">/</span> <span class="code-keywords3">log</span> <span class="code-number">2</span><span class="code-symbol">)</span> <span class="code-symbol">-</span> <span class="code-number">23</span><span class="code-symbol">)</span></code>
</pre>
<p>So if all you really wanted to know was if two values are interchangeable (which is certainly not helpful in cases where the errors add up), a function testing it could make use of it:</p>
<pre class="notranslate">
<code><span class="code-keywords1">fn</span> <span class="code-identifier">areFloatsEquivalent</span> <span class="code-identifier">f1</span> <span class="code-identifier">f2</span> <span class="code-symbol">=</span></code>
<code><span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">if</span> <span class="code-identifier">f1</span> <span class="code-symbol"><</span> <span class="code-identifier">f2</span> <span class="code-keywords1">do</span> <span class="code-keywords3">swap</span> <span class="code-identifier">f1</span> <span class="code-identifier">f2</span></code>
<code> <span class="code-symbol">(</span><span class="code-identifier">f1</span> <span class="code-symbol">-</span> <span class="code-identifier">f2</span><span class="code-symbol">)</span> <span class="code-symbol"><=</span> <span class="code-identifier">floatAccuracy</span> <span class="code-identifier">f1</span></code>
<code><span class="code-symbol">)</span></code>
</pre>
<div style="font-weight:bold; font-size: 10pt; padding-bottom:8px">Other types based on 32-bit floats</div>
<p><strong>Point2, Point3, Point4</strong></p>
<p>The most straightforward way here is using the <code>distance</code> function:</p>
<pre class="notranslate">
<code><span class="code-keywords1">fn</span> <span class="code-identifier">arePtsEquivalent</span> <span class="code-identifier">v1</span> <span class="code-identifier">v2</span> <span class="code-identifier">eps</span><span class="code-symbol">:</span><span class="code-number">1e</span><span class="code-symbol">-</span><span class="code-number">6</span> <span class="code-symbol">=</span></code>
<code> <span class="code-keywords3">distance</span> <span class="code-identifier">p1</span> <span class="code-identifier">p2</span> <span class="code-symbol"><</span> <span class="code-identifier">eps</span></code>
</pre>
<p>Of course, you can also use <code>getHashValue</code>, which can be used this way in many other circumstances (not for comparing floats directly, though, the error margin is too large for that to work on small values):</p>
<pre class="notranslate">
<code><span class="code-keywords1">fn</span> <span class="code-identifier">arePtsEquivalent</span> <span class="code-identifier">v1</span> <span class="code-identifier">v2</span> <span class="code-identifier">eps</span><span class="code-symbol">:</span><span class="code-number">1e</span><span class="code-symbol">-</span><span class="code-number">6</span> <span class="code-symbol">=</span></code>
<code> <span class="code-keywords3">getHashValue</span> <span class="code-identifier">p1</span> <span class="code-number">0</span> <span class="code-symbol">==</span> <span class="code-keywords3">getHashValue</span> <span class="code-identifier">p2</span> <span class="code-number">0</span></code>
</pre>
<p>This works well with values describing e.g. position, and if the aim is to compare non-unit vectors based on their direction, it would work the same if you normalized both of them prior to passing them to the function. Another possibility is to compare the angle between them with a custom threshold angle:</p>
<pre class="notranslate">
<code><span class="code-keywords1">fn</span> <span class="code-identifier">areVectorsEquivalent</span> <span class="code-identifier">v1</span> <span class="code-identifier">v2</span> <span class="code-identifier">eps</span><span class="code-symbol">:</span><span class="code-number">0</span><span class="code-symbol">.</span><span class="code-number">999999</span> <span class="code-symbol">=</code>
<code> <span class="code-keywords3">dot</span> <span class="code-symbol">(</span><span class="code-keywords3">normalize</span> <span class="code-identifier">v1</span><span class="code-symbol">)</span> <span class="code-symbol">(</span><span class="code-keywords3">normalize</span> <span class="code-identifier">v2</span><span class="code-symbol">)</span> <span class="code-symbol">></span> <span class="code-identifier">eps</span></code>
</pre>
<p>To directly compare the angles, <code>acos</code> would be needed, however as we treat the threshold angle as a constant, it makes more sense to instead use <code>cos(thresholdAngle)</code> as our epsilon value to save some computation cycles (and also avoid indeterminate result due to inaccuracies). Note that this also switches the greater-than/less-than operators in the comparison.</p>
<p><strong>Colors</strong></p>
<p>The easiest way is to cast the colors to <code>Point3</code> format and compare those values, which can be simplified to:</p>
<pre class="notranslate">
<code><span class="code-keywords1">fn</span> <span class="code-identifier">areColorsEquivalent</span> <span class="code-identifier">c1</span> <span class="code-identifier">c2</span> <span class="code-identifier">eps</span><span class="code-symbol">:</span><span class="code-number">1e</span><span class="code-symbol">-</span><span class="code-number">6</span> <span class="code-symbol">=</span></code>
<code> <span class="code-keywords3">length</span> <span class="code-symbol">((</span><span class="code-identifier">c1</span> <span class="code-symbol">-</span> <span class="code-identifier">c2</span><span class="code-symbol">)</span> <span class="code-keywords1">as</span> <span class="code-keywords4">point3</span><span class="code-symbol">)</span> <span class="code-symbol"><</span> <span class="code-identifier">eps</span></code>
</pre>
<p><strong>Matrices</strong></p>
<p>Similar to other values, casting to string works quite good for matrix comparison, the only thing to bear in mind is that MAXScript prints the value of a float to the 6th significant digit, which effectivelly truncates decimals beyond that point.</p>
<pre class="notranslate">
<code><span class="code-keywords1">fn</span> <span class="code-identifier">areMatricesEquivalent</span> <span class="code-identifier">m1</span> <span class="code-identifier">m2</span> <span class="code-symbol">=</span></code>
<code> <span class="code-identifier">m1</span> <span class="code-keywords1">as</span> <span class="code-keywords4">string</span> <span class="code-symbol">==</span> <span class="code-identifier">m2</span> <span class="code-keywords1">as</span> <span class="code-keywords4">string</span></code>
</pre>
<p>For increased precison, comparing each row as <code>Point3</code> values, together with the use of short-circuiting <code>and</code> operator is a better idea:</p>
<pre class="notranslate">
<code><span class="code-keywords1">fn</span> <span class="code-identifier">areMatricesEquivalent</span> <span class="code-identifier">m1</span> <span class="code-identifier">m2</span> <span class="code-symbol">=</span></code>
<code> <span class="code-identifier">areVectorsEquivalent</span> <span class="code-identifier">m1</span><span class="code-symbol">.</span><span class="code-identifier">row1</span> <span class="code-identifier">m2</span><span class="code-symbol">.</span><span class="code-identifier">row1</span> <span class="code-keywords2">AND</span></code>
<code> <span class="code-identifier">areVectorsEquivalent</span> <span class="code-identifier">m1</span><span class="code-symbol">.</span><span class="code-identifier">row2</span> <span class="code-identifier">m2</span><span class="code-symbol">.</span><span class="code-identifier">row2</span> <span class="code-keywords2">AND</span></code>
<code> <span class="code-identifier">areVectorsEquivalent</span> <span class="code-identifier">m1</span><span class="code-symbol">.</span><span class="code-identifier">row3</span> <span class="code-identifier">m2</span><span class="code-symbol">.</span><span class="code-identifier">row3</span> <span class="code-keywords2">AND</span></code>
<code> <span class="code-identifier">areVectorsEquivalent</span> <span class="code-identifier">m1</span><span class="code-symbol">.</span><span class="code-identifier">row4</span> <span class="code-identifier">m2</span><span class="code-symbol">.</span><span class="code-identifier">row4</span></code>
</pre>
<p>Another method, mentioned in MAXScript reference, makes use of the fact that matrix multiplied by its inverse returns the identity matrix:</p>
<pre class="notranslate">
<code><span class="code-keywords1">fn</span> <span class="code-identifier">areMatricesEquivalent</span> <span class="code-identifier">m1</span> <span class="code-identifier">m2</span> <span class="code-symbol">=</span></code>
<code> <span class="code-keywords3">isIdentity</span> <span class="code-symbol">(</span><span class="code-identifier">m1</span> <span class="code-symbol">*</span> <span class="code-keywords3">inverse</span> <span class="code-identifier">m2</span><span class="code-symbol">)</span></code>
</pre>
<div style="font-family: 'PT Sans',Verdana,sans-serif;">
<p>DISCLAIMER: All scripts and snippets are provided as is under <a href="http://creativecommons.org/publicdomain/zero/1.0/">Creative Commons Zero (public domain, no restrictions) license</a>. The author and this blog cannot be held liable for any loss caused as a result of inaccuracy or error within these web pages. Use at your own risk.</p></div>Swordslayerhttp://www.blogger.com/profile/09124250713006663760noreply@blogger.com3tag:blogger.com,1999:blog-4212150079314071223.post-13935456884919501492012-12-23T00:31:00.000+01:002012-12-23T00:31:26.356+01:00Progress Info<p>The built-in progress bar in max status bar is not suited for every task, and as I have found myself writing quite similar lines of code to print debug info to the prompt and trying to prevent max window from 'not responding' over and over again, I whipped up a little struct to make it easier.</p><a name='more'></a>
<pre class="notranslate">
<code><span class="code-keywords1">global</span> <span class="code-identifier">progressInfoDef</span></code>
<code><span class="code-symbol">(</span></code>
<code> <span class="code-identifier">_timeSpan</span> <span class="code-symbol">=</span> <span class="code-symbol">(</span><span class="code-keywords3">dotNetClass</span> <span class="code-string">"TimeSpan"</span><span class="code-symbol">).</span><span class="code-identifier">FromSeconds</span></code>
<code></code>
<code> <span class="code-keywords1">struct</span> <span class="code-identifier">progressInfoDef</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-identifier">infoFormat</span><span class="code-symbol">,</span></code>
<code> <span class="code-identifier">_info</span> <span class="code-symbol">=</span> <span class="code-keywords4">stringStream</span> <span class="code-string">""</span><span class="code-symbol">,</span></code>
<code> <span class="code-identifier">_start</span> <span class="code-symbol">=</span> <span class="code-keywords3">timeStamp</span><span class="code-symbol">(),</span></code>
<code></code>
<code> <span class="code-keywords1">fn</span> <span class="code-keywords3">update</span> <span class="code-identifier">counter</span> <span class="code-symbol">=</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords3">seek</span> <span class="code-identifier">_info</span> <span class="code-number">0</span></code>
<code> <span class="code-keywords3">format</span> <span class="code-identifier">infoFormat</span> <span class="code-identifier">counter</span> <span class="code-keywords1">to</span><span class="code-symbol">:</span><span class="code-identifier">_info</span></code>
<code> <span class="code-keywords3">pushPrompt</span> <span class="code-identifier">_info</span></code>
<code></code>
<code> <span class="code-keywords1">if</span> <span class="code-keywords3">mod</span> <span class="code-identifier">counter</span> <span class="code-number">10</span> <span class="code-symbol">==</span> <span class="code-number">0</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-keywords3">windows</span><span class="code-symbol">.</span><span class="code-identifier">processPostedMessages</span><span class="code-symbol">()</span></code>
<code> <span class="code-keywords1">OK</span></code>
<code> <span class="code-symbol">),</span></code>
<code></code>
<code> <span class="code-keywords1">fn</span> <span class="code-keywords1">end</span> <span class="code-symbol">=</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords3">free</span> <span class="code-identifier">_info</span></code>
<code> <span class="code-keywords3">pushPrompt</span> <span class="code-symbol">(</span><span class="code-string">"DONE, time elapsed: "</span> <span class="code-symbol">+</span> <span class="code-symbol">(</span><span class="code-identifier">_timeSpan</span> <span class="code-symbol">((</span><span class="code-keywords3">timeStamp</span><span class="code-symbol">()</span> <span class="code-symbol">-</span> <span class="code-identifier">_start</span><span class="code-symbol">)/</span><span class="code-number">1000</span><span class="code-symbol">)).</span><span class="code-identifier">ToString</span><span class="code-symbol">())</span></code>
<code> <span class="code-keywords1">OK</span></code>
<code> <span class="code-symbol">)</span></code>
<code> <span class="code-symbol">)</span></code>
<code><span class="code-symbol">)</span></code>
</pre>
<p>The custom "infoFormat" string contains anything you want to be kept informed of, like <code>"Intersections found: %"</code> or <code>"Filtering: % of 1000"</code>. Calling the end function is purely optional, nothing serious happens if you don't do it, only the total amount of time will not overwrite the last value the update function was passed.</p>
<p>For 3ds max versions earlier than 2011, the <code>windows.processPostedMessages()</code> obviously won't work, you can use <code>(dotnetClass "Application").doEvents()</code> instead, as discussed for example <a href="http://forums.cgsociety.org/showpost.php?p=6944009&postcount=19" title="CGTalk :: Interface updates while busy">here</a>. Calling it on every value which is divisible by ten is arbitrary and based on where it is called from might not happen at all or might happen all the time so make sure to keep that in mind and feel free to modify it (as well as the whole struct) to suit your needs.</p>
<p>An artificial use case scenario looks basically like this:</p>
<pre class="notranslate">
<code><span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">totalCount</span> <span class="code-symbol">=</span> <span class="code-number">100</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">progressInfo</span> <span class="code-symbol">=</span> <span class="code-identifier">progressInfoDef</span> <span class="code-identifier">infoFormat</span><span class="code-symbol">:(</span><span class="code-string">"Processing: % of "</span> <span class="code-symbol">+</span> <span class="code-identifier">totalCount</span> <span class="code-keywords1">as</span> <span class="code-keywords4">string</span><span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">i</span> <span class="code-symbol">=</span> <span class="code-number">1</span> <span class="code-keywords1">to</span> <span class="code-number">100</span> <span class="code-keywords1">while</span> <span class="code-keywords2">NOT</span> <span class="code-keywords3">keyboard</span><span class="code-symbol">.</span><span class="code-identifier">ESCpressed</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-identifier">progressInfo</span><span class="code-symbol">.</span><span class="code-keywords3">update</span> <span class="code-identifier">i</span></code>
<code> <span class="code-keywords3">sleep</span> <span class="code-symbol">.</span><span class="code-number">1337</span></code>
<code> <span class="code-symbol">)</span></code>
<code> <span class="code-identifier">progressInfo</span><span class="code-symbol">.</span><span class="code-keywords1">end</span><span class="code-symbol">()</span></code>
<code><span class="code-symbol">)</span></code>
</pre>
<div style="font-family: 'PT Sans',Verdana,sans-serif;">
<p>DISCLAIMER: All scripts and snippets are provided as is under <a href="http://creativecommons.org/publicdomain/zero/1.0/">Creative Commons Zero (public domain, no restrictions) license</a>. The author and this blog cannot be held liable for any loss caused as a result of inaccuracy or error within these web pages. Use at your own risk.</p></div>Swordslayerhttp://www.blogger.com/profile/09124250713006663760noreply@blogger.com0tag:blogger.com,1999:blog-4212150079314071223.post-31762946162434308002012-12-20T20:26:00.000+01:002012-12-20T20:26:00.262+01:00Persistent values in rollout (across one session)<p>Sometimes it is desirable for rollout controls to keep their values when you close the dialog and open it again. There are many ways to achieve that, one of the easiest is using locals declared in a macroscript body and using its <code>on execute</code> handler to initialize the rollout. When a regular script is used instead, a global struct or a global set of values can be used, but there is also another method which might be more suitable in many cases.</p><a name='more'></a>
<p>A simple example would be keeping a text that was previously entered in an <code>editText</code> control:</p>
<pre class="notranslate">
<code><span class="mygeneral1-keywords1">try</span> <span class="code-keywords3">destroyDialog</span> <span class="code-symbol">::</span><span class="code-identifier">persistentRollout</span> <span class="code-keywords1">catch</span><span class="code-symbol">()</span></code>
<code></code>
<code><span class="code-keywords1">if</span> <span class="code-keywords2">NOT</span> <span class="code-keywords3">isKindOf</span> <span class="code-identifier">persistentRollout</span> <span class="code-keywords4">RolloutClass</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-keywords5">rollout</span> <span class="code-identifier">persistentRollout</span> <span class="code-string">"Persistent Rollout"</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">savedText</span> <span class="code-symbol">=</span> <span class="code-keywords1">if</span> <span class="code-identifier">savedText</span> <span class="code-symbol">==</span> <span class="code-keywords1">undefined</span> <span class="code-keywords1">then</span> <span class="code-string">""</span> <span class="code-keywords1">else</span> <span class="code-identifier">savedText</span></code>
<code></code>
<code> <span class="code-keywords5">editText</span> <span class="code-identifier">etTest</span> <span class="code-string">"Type a Value"</span> <span class="code-keywords4">text</span><span class="code-symbol">:</span><span class="code-identifier">savedText</span></code>
<code></code>
<code> <span class="code-keywords1">on</span> <span class="code-identifier">etTest</span> <span class="code-keywords1">changed</span> <span class="code-keywords4">text</span> <span class="code-keywords1">do</span> <span class="code-identifier">savedText</span> <span class="code-symbol">=</span> <span class="code-keywords4">text</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code><span class="code-keywords3">createDialog</span> <span class="code-identifier">persistentRollout</span></code>
</pre>
<p>The first line declares a global variable to hold the rollout definition if it haven't been declared yet, and tries to destroy the dialog at the same time. If the global variable contains a rollout class already, we create the dialog with the existing rollout definiton. Otherwise, a rollout is created, and in its scope a local variable to hold the text is declared. When the <code>createDialog</code> function is called for the first time, the local in the rollout haven't been assigned a value yet and so it is assigned an empty string value. When the script is evaluated next time, it already contains a value that can be used.</p>
<p>Of course, for some complex scripts it makes sense to use a struct instead but for small projects it is easy enough to make use of this method.</p>Swordslayerhttp://www.blogger.com/profile/09124250713006663760noreply@blogger.com0tag:blogger.com,1999:blog-4212150079314071223.post-81691653269242205632012-11-24T17:53:00.000+01:002012-11-24T17:53:35.735+01:00Unique random wirecolor<p>As I've indicated in my previous retrospective that there's a skeleton in my closet, a bulk of code waiting to be commented. Let's now have a look at a piece of code from almost a year ago (original question at Stack Overflow: <a href="http://stackoverflow.com/questions/8910878/give-each-object-in-scene-a-unique-wirecolor">Give each object in scene a unique wirecolor?</a>).</p><a name='more'></a>
<p>The common solution used to the automate wirecolor randomization is assigning a random color to each object in scene by calling random function for every node. While this might seem to work in many cases it actually generates repeating colors and might lead to unexpected result.</p>
<p>What we can do instead is prepare a unique set of elements to build the colors of and iterate over them as we traverse the node collection:</p>
<pre class="notranslate">
<code><span class="code-keywords1">fn</span> <span class="code-identifier">shuffle</span> <span class="code-identifier">arr</span> <span class="code-symbol">=</span></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">counter</span> <span class="code-symbol">=</span> <span class="code-identifier">arr</span><span class="code-symbol">.</span><span class="code-keywords1">count to</span> <span class="code-number">2</span> <span class="code-keywords1">by</span> <span class="code-number">-1</span> <span class="code-keywords1">collect</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">swapIndex</span> <span class="code-symbol">=</span> <span class="code-keywords3">random</span> <span class="code-number">1</span> <span class="code-identifier">counter</span></code>
<code> <span class="code-keywords3">swap</span> <span class="code-identifier">arr</span><span class="code-symbol">[</span><span class="code-keywords3">random</span> <span class="code-number">1</span> <span class="code-identifier">counter</span><span class="code-symbol">]</span> <span class="code-identifier">arr</span><span class="code-symbol">[</span><span class="code-identifier">counter</span><span class="code-symbol">]</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code><span class="code-keywords1">fn</span> <span class="code-identifier">incrementCounters</span> <span class="code-symbol">&</span><span class="code-identifier">r</span> <span class="code-symbol">&</span><span class="code-identifier">g</span> <span class="code-symbol">&</span><span class="code-identifier">b</span> <span class="code-identifier">step</span> <span class="code-symbol">=</span></code>
<code> <span class="code-keywords1">if</span> <span class="code-symbol">(</span><span class="code-identifier">b</span> <span class="code-symbol">+=</span> <span class="code-identifier">step</span><span class="code-symbol">)</span> <span class="code-symbol">></span> <span class="code-number">256</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-identifier">b</span> <span class="code-symbol">=</span> <span class="code-number">1</span></code>
<code> <span class="code-keywords1">if</span> <span class="code-symbol">(</span><span class="code-identifier">g</span> <span class="code-symbol">+=</span> <span class="code-identifier">step</span><span class="code-symbol">)</span> <span class="code-symbol">></span> <span class="code-number">256</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-identifier">g</span> <span class="code-symbol">=</span> <span class="code-number">1</span></code>
<code> <span class="code-keywords1">if</span> <span class="code-symbol">(</span><span class="code-identifier">r</span> <span class="code-symbol">+=</span> <span class="code-identifier">step</span><span class="code-symbol">)</span> <span class="code-symbol">></span> <span class="code-number">256</span> <span class="code-keywords1">do</span> <span class="code-identifier">r</span> <span class="code-symbol">=</span> <span class="code-number">1</span></code>
<code> <span class="code-symbol">)</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code><span class="code-keywords1">fn</span> <span class="code-identifier">assignRandomWirecolor</span> <span class="code-identifier">objs</span> <span class="code-identifier">shuffleObjs</span><span class="code-symbol">:</span><span class="code-keywords1">false</span> <span class="code-symbol">=(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">stepCount</span> <span class="code-symbol">=</span> <span class="code-identifier">objs</span><span class="code-symbol">.</span><span class="code-keywords1">count</span><span class="code-symbol">^(</span><span class="code-keywords3">double</span> <span class="code-number">1</span><span class="code-symbol">/</span><span class="code-number">3</span><span class="code-symbol">)</span> <span class="code-symbol">+</span> <span class="code-number">1</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">step</span> <span class="code-symbol">=</span> <span class="code-number">255</span><span class="code-symbol">./</span><span class="code-identifier">stepCount</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">redArr</span> <span class="code-symbol">=</span> <span class="code-identifier">shuffle</span> <span class="code-symbol">(#(</span><span class="code-number">0</span><span class="code-symbol">)</span> <span class="code-symbol">+</span> <span class="code-symbol">#{</span><span class="code-number">1</span><span class="code-symbol">..</span><span class="code-number">255</span><span class="code-symbol">})</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">greenArr</span> <span class="code-symbol">=</span> <span class="code-identifier">shuffle</span> <span class="code-symbol">(#(</span><span class="code-number">0</span><span class="code-symbol">)</span> <span class="code-symbol">+</span> <span class="code-symbol">#{</span><span class="code-number">1</span><span class="code-symbol">..</span><span class="code-number">255</span><span class="code-symbol">})</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">blueArr</span> <span class="code-symbol">=</span> <span class="code-identifier">shuffle</span> <span class="code-symbol">(#(</span><span class="code-number">0</span><span class="code-symbol">)</span> <span class="code-symbol">+</span> <span class="code-symbol">#{</span><span class="code-number">1</span><span class="code-symbol">..</span><span class="code-number">255</span><span class="code-symbol">})</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">r</span> <span class="code-symbol">=</span> <span class="code-number">1</span><span class="code-symbol">,</span> <span class="code-identifier">g</span> <span class="code-symbol">=</span> <span class="code-number">1</span><span class="code-symbol">,</span> <span class="code-identifier">b</span> <span class="code-symbol">=</span> <span class="code-number">1</span></code>
<code></code>
<code> <span class="code-keywords1">if</span> <span class="code-identifier">shuffleObjs</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-identifier">objs</span> <span class="code-symbol">=</span> <span class="code-identifier">shuffle</span> <span class="code-identifier">objs</span></code>
<code></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">obj</span> <span class="code-keywords1">in</span> <span class="code-identifier">objs</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-identifier">obj</span><span class="code-symbol">.</span><span class="code-identifier">wirecolor</span> <span class="code-symbol">=</span> <span class="code-symbol">[</span><span class="code-identifier">redArr</span><span class="code-symbol">[</span><span class="code-keywords3">int</span><span class="code-symbol">(</span><span class="code-identifier">r</span><span class="code-symbol">)],</span> <span class="code-identifier">greenArr</span><span class="code-symbol">[</span><span class="code-keywords3">int</span><span class="code-symbol">(</span><span class="code-identifier">g</span><span class="code-symbol">)],</span> <span class="code-identifier">blueArr</span><span class="code-symbol">[</span><span class="code-keywords3">int</span><span class="code-symbol">(</span><span class="code-identifier">b</span><span class="code-symbol">)]]</span></code>
<code> <span class="code-identifier">incrementCounters</span> <span class="code-symbol">&</span><span class="code-identifier">r</span> <span class="code-symbol">&</span><span class="code-identifier">g</span> <span class="code-symbol">&</span><span class="code-identifier">b</span> <span class="code-identifier">step</span></code>
<code> <span class="code-symbol">)</span></code>
<code><span class="code-symbol">)</span></code>
</pre>
<p>The process involved in getting unique random colors does not add much complexity and is faster than many naive implementations, especially with large number of objects. As we are working in the RGB color space with red, green and blue values in the range 0 to 255, there are 255 × 255 × 255, i.e. 16 777 216 different colors to make use of.</p>
<p>This means that for the most complex case we could make three lists of numbers from 0 to 255 and assign color 0 0 0 to the first object, then color 0 0 1 to the second one and so on all the way up to 0 0 255. After this step we would zero out the last counter and increase the middle one so we get 0 1 0, and continue up to 0 255 255, increasing the middle counter each time the last counter is zeroed out as it gets bigger than 255. Finally the first counter would increase every time the other two reach 255.</p>
<p>Instead of directly assigning the counter values we can use them to get an item at that index on a list of values from 0 to 255, so redHues[1] gives us 0 and redHues[256] gives us 255. When we shuffle the three lists those values are no longer predictable and we get the randomness we wanted while still keeping the uniqueness.</p>
<p>In a general case we rarely need 255 × 255 × 255 colors, e.g. for 1 000 objects 10 × 10 × 10 colors is enough – 10 being the cube root of the number of objects here. The easiest solution to get only that many values from the complete 256 item long lists is to increase the counter not by one as in the previous case but by a bigger number, 25.6 in this case. As we only want to access indexed members of the list, the resulting counter values have to rounded off and 25.6 becomes 26, 51.2 becomes 51 and so on.</p>
<p>DISCLAIMER: All scripts and snippets are provided as is under <a href="http://creativecommons.org/publicdomain/zero/1.0/">Creative Commons Zero (public domain, no restrictions) license</a>. The author and this blog cannot be held liable for any loss caused as a result of inaccuracy or error within these web pages. Use at your own risk.</p>Swordslayerhttp://www.blogger.com/profile/09124250713006663760noreply@blogger.com1tag:blogger.com,1999:blog-4212150079314071223.post-60884279606579680042012-11-24T16:54:00.000+01:002012-12-24T23:20:13.057+01:00Array shuffling gotchas<p>Shuffling an array is a fairly common task in the world of maxscript, and even if you don't do it quite right it's still okay for most of the tasks it's used for. However when unique array elements get dropped in the process and other are repeated, it's definitely not the expected outcome.</p><a name='more'></a>
<p>I tend not to overuse local variables when they are only used once and it doesn't hinder readability (why, yes, I do fancy me some functional programming from time to time). In this context, though, it fails miserably:</p>
<pre class="notranslate">
<code><span class="code-keywords1">fn</span> <span class="code-identifier">shuffle</span> <span class="code-identifier">arr</span> <span class="code-symbol">=</span></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">counter</span> <span class="code-symbol">=</span> <span class="code-identifier">arr</span><span class="code-symbol">.</span><span class="code-keywords1">count to</span> <span class="code-number">1</span> <span class="code-keywords1">by</span> <span class="code-number">-1</span> <span class="code-keywords1">collect</span></code>
<code> <span class="code-keywords3">swap</span> <span class="code-identifier">arr</span><span class="code-symbol">[</span><span class="code-keywords3">random</span> <span class="code-number">1</span> <span class="code-identifier">counter</span><span class="code-symbol">]</span> <span class="code-identifier">arr</span><span class="code-symbol">[</span><span class="code-identifier">counter</span><span class="code-symbol">]</span></code>
</pre>
<p>Supposedly, this would shuffle the passed array and return a reversed copy of the shuffled array (because swap returns the first value that was passed to it – which is the value we use for replacing the original one here – and we traverse the array in reverse order). The actual output of this function is quite different:</p>
<pre class="notranslate">
<span class="code-identifier">shuffle</span> <span class="code-symbol">(#{</span><span class="code-number">1</span><span class="code-symbol">..</span><span class="code-number">20</span><span class="code-symbol">}</span> <span class="code-keywords1">as</span> <span class="code-keywords4">array</span><span class="code-symbol">)</span>
<samp class="code-comment">-- #(9, 5, 6, 12, 16, 3, 13, 19, 14, 6, 5, 5, 19, 6, 5, 3, 5, 19, 5, 5)</samp>
</pre>
<p>Note that this is not a proper variant of Fisher–Yates shuffle as the item can be swapped with itself, yet it's usually good enough and this implementation detail has nothing to do with all those repeated and dropped values it outputs.</p>
<p>Now let's see what happens when we introduce a variable to hold the result of random call instead:</p>
<pre class="notranslate">
<code><span class="code-keywords1">fn</span> <span class="code-identifier">shuffle</span> <span class="code-identifier">arr</span> <span class="code-symbol">=</span></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">counter</span> <span class="code-symbol">=</span> <span class="code-identifier">arr</span><span class="code-symbol">.</span><span class="code-keywords1">count to</span> <span class="code-number">1</span> <span class="code-keywords1">by</span> <span class="code-number">-1</span> <span class="code-keywords1">collect</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">swapIndex</span> <span class="code-symbol">=</span> <span class="code-keywords3">random</span> <span class="code-number">1</span> <span class="code-identifier">counter</span></code>
<code> <span class="code-keywords3">swap</span> <span class="code-identifier">arr</span><span class="code-symbol">[</span><span class="code-identifier">swapIndex</span><span class="code-symbol">]</span> <span class="code-identifier">arr</span><span class="code-symbol">[</span><span class="code-identifier">counter</span><span class="code-symbol">]</span></code>
<code> <span class="code-symbol">)</span></code>
</pre>
<pre class="notranslate">
<span class="code-identifier">shuffle</span> <span class="code-symbol">(#{</span><span class="code-number">1</span><span class="code-symbol">..</span><span class="code-number">20</span><span class="code-symbol">}</span> <span class="code-keywords1">as</span> <span class="code-keywords4">array</span><span class="code-symbol">)</span>
<samp class="code-comment">-- #(14, 7, 4, 16, 8, 6, 20, 15, 2, 3, 9, 13, 19, 5, 17, 12, 10, 1, 11, 18)</samp>
</pre>
<p>I got bitten by it more than once and although I've tackled it before (<a href="http://creativescratchpad.blogspot.cz/2011/06/select-random-elements-by-percentage.html">randomizeArray</a> being one of the examples), I tend to forget that and go WTF when I meet the swap enigma again, the best evidence being
<a href="http://stackoverflow.com/questions/8910878/give-each-object-in-scene-a-unique-wirecolor/8939056#8939056">this</a> shuffle function with manual swap using temporary variable.</p>
<p>Looking at that unexplained, uncommented piece of code again, I should probably explain what I did there as well, this blog has been quiet for a long time and I guess it's about time to change that.</p>
<p>DISCLAIMER: All scripts and snippets are provided as is under <a href="http://creativecommons.org/publicdomain/zero/1.0/">Creative Commons Zero (public domain, no restrictions) license</a>. The author and this blog cannot be held liable for any loss caused as a result of inaccuracy or error within these web pages. Use at your own risk.</p>
Swordslayerhttp://www.blogger.com/profile/09124250713006663760noreply@blogger.com0tag:blogger.com,1999:blog-4212150079314071223.post-15448494410438498092011-07-13T22:43:00.004+02:002013-01-13T16:20:08.117+01:00Render Info-strip Customization<p>I have recently published an <a href="http://www.scriptspot.com/3ds-max/scripts/render-info-strip" title="ScriptSpot :: Render Info-strip">info-strip script</a> that allows custom information to be displayed in the rendered image, just like the v-ray frame stamp, but this one supports all renderers using the VFB (most notably mental ray and scanline). Together with user defined font size, style, colors and opacity of the strip background the user can define expressions to include things like photon count, diffuse bounces number etc. in the displayed information. There are five custom fields for simple expression and one field for custom script if you need some more elaborate way to get the desired result. In this tutorial I will show how these fields can be used to their full potential.</p><a name='more'></a><div style="margin-right: 1em; text-align: center; border:none;"><a href="http://www.scriptspot.com/3ds-max/scripts/render-info-strip" imageanchor="1"><img alt="Render Info-strip UI" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrijbtgIRK-CoymtG0ZHnjtYkZUu-9JHiCK-LqMW0jxF9D7XqMGDzXjgO3lvrkpKB3D4-cewfJkJzVBDUjqZ_KMYOkM_rP3fcTNf_xPvflAjAy6s_cXNTrDonVKZxE9eaTfmK4jdlPuMQ/s400/infostrip_ui.png" title="ScriptSpot :: Render Info-strip" /></a></div></ br><br />
<p>Among the default values you will notice <code><span class="code-keywords3">renderers</span>.current.FinalGatherAccuracy</code> and similar parameters of the current renderer. There are many more that can be useful to record, like <code>.GlobalIllumAccuracy</code>, <code>.GlobalIllumRadius</code> or <code>.GIPhotonMergeDistance</code>. To get the complete list of render settings for mental ray, have a look at <a href="http://docs.autodesk.com/3DSMAX/14/ENU/MAXScript%20Help%202012/files/GUID-EE96053B-6E67-4578-B1C7-2738CF47C5B-1529.htm" title="MAXScript 2012 Help :: mental_ray_renderer">mental_ray_renderer : RendererClass</a> section of maxscript help – wherever it says <code><mental_ray_renderer></code> you'd replace it with <code><span class="code-keywords3">renderers</span>.current</code>. To get a list of properties for a different renderer run <code><span class="code-keywords3">showProperties renderers</span>.current</code> in the maxscript listener (press F11 to open it).</p><p>The same procedure applies for exposure control and virtually any single property that you can access via maxscript or .NET. In the case of mental ray Photographic Exposure Control the example usage is <code><span class="code-keywords3">sceneExposureControl</span>.exposureControl.exposure_value</code> and the exposure_value can be likewise replaced with <code>.shutter_speed</code>, <code>.saturation</code>, <code>.gamma</code> etc. The list of all the properties for this exposure control can be found in chapter <a href="http://docs.autodesk.com/3DSMAX/14/ENU/MAXScript%20Help%202012/index.html?url=files/GUID-A338EFEC-FDDD-4BD2-9F17-BD54505ACDF-1608.htm,topicNumber=d28e578721" title="MAXScript 2012 Help :: mr_Photographic_Exposure_Control">mr_Photographic_Exposure_Control : ToneOperator</a>.</p><p>Other simple expressions that might be noteworthy are listed here:</p><pre class="notranslate"><code> <span class="code-keywords3">objects</span><span class="code-symbol">.</span><span class="code-keywords1">count</span> <span class="code-comment">-- number of objects</span></code>
<code></code>
<code> <span class="code-keywords3">sceneMaterials</span><span class="code-symbol">.</span><span class="code-keywords1">count</span> <span class="code-comment">-- number of scene materials</span></code>
<code></code>
<code> <span class="code-keywords3">displayGamma</span> <span class="code-comment">-- main gamma correction value</span></code>
<code></code>
<code> <span class="code-keywords3">fileInGamma</span> <span class="code-comment">-- input gamma</span></code>
<code></code>
<code> <span class="code-keywords3">fileOutGamma</span> <span class="code-comment">-- output gamma</span></code>
<code></code>
<code> <span class="code-keywords3">numEffects</span> <span class="code-comment">-- number of current render effects</span></code>
<code></code>
<code> <span class="code-keywords3">rendOutputFilename</span> <span class="code-comment">-- preset rendered image file name</span></code>
<code></code>
<code> <span class="code-keywords3">sliderTime</span> <span class="code-comment">-- current slider time position</span></code>
<code></code>
<code> <span class="code-keywords3">units</span><span class="code-symbol">.</span><span class="code-keywords1">systemType</span> <span class="code-comment">-- current system unit type</span></code>
</pre><p>The custom script entry offers the possibility to get more information at once, the only requirement for the script is it has to return a value – either a string or a value that can be converted to one. Also, the resulting string cannot contain any line-breaks and should be short enough to fit in the strip lenght. To combine multiple values into one result, there are a few options. The first one is string concatenation:</p><pre class="notranslate"> <span class="code-string">"Ten: "</span> <span class="code-symbol">+</span> <span class="code-number">10</span> <span class="code-keywords1">as</span> <span class="code-keywords4">string</span> <span class="code-symbol">+</span> <span class="code-string">" that's all, folks!"</span>
</pre><p>The second one is formatting the values to a stringStream. Each percent character works as a placeholder for the argument following the string. For each percent metacharacter you have to add one argument:</p><pre class="notranslate"> <span class="code-identifier">sstream</span> <span class="code-symbol">=</span> <span class="code-string">""</span> <span class="code-keywords1">as</span> <span class="code-keywords4">stringStream</span>
<span class="code-keywords3">format</span> <span class="code-string">"Ten: % %"</span> <span class="code-number">10</span> <span class="code-string">"that's all, folks!"</span> <span class="code-keywords1">to</span><span class="code-symbol">:</span><span class="code-identifier">sstream</span>
<span class="code-identifier">sstream</span>
</pre><p>To show some possible uses, here are some ready-made snippets. If you use temporary variables, it's always better to enclose the code in braces and declare the variables as locals. To test the output of the script you can copy it to maxscript editor in 3ds max (located under New Script.. menu entry) and evaluate it (CTRL+E). If you'd need a piece of code or would like to share one that you find useful and is not listed here, use the comments section under the article.</p><p>Anti-aliasing (default value of the script field):</p><pre class="notranslate"><code><span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">s</span> <span class="code-symbol">=</span> <span class="code-string">""</span> <span class="code-keywords1">as</span> <span class="code-keywords4">stringStream</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">r</span> <span class="code-symbol">=</span> <span class="code-keywords3">renderers</span><span class="code-symbol">.</span><span class="code-identifier">current</span></code>
<code></code>
<code> <span class="code-keywords3">format</span> <span class="code-string">"AA Min: % | AA Max: % | AA Spatial Contrast: % % % %"</span> <span class="code-symbol">\</span></code>
<code> <span class="code-identifier">r</span><span class="code-symbol">.</span><span class="code-identifier">MinimumSamples</span> <span class="code-symbol">\</span></code>
<code> <span class="code-identifier">r</span><span class="code-symbol">.</span><span class="code-identifier">MaximumSamples</span> <span class="code-symbol">\</span></code>
<code> <span class="code-identifier">r</span><span class="code-symbol">.</span><span class="code-identifier">RedSpatialContrast</span> <span class="code-symbol">\</span></code>
<code> <span class="code-identifier">r</span><span class="code-symbol">.</span><span class="code-identifier">GreenSpatialContrast</span> <span class="code-symbol">\</span></code>
<code> <span class="code-identifier">r</span><span class="code-symbol">.</span><span class="code-identifier">BlueSpatialContrast</span> <span class="code-symbol">\</span></code>
<code> <span class="code-identifier">r</span><span class="code-symbol">.</span><span class="code-identifier">AlphaSpatialContrast</span> <span class="code-keywords1">to</span><span class="code-symbol">:</span><span class="code-identifier">s</span></code>
<code></code>
<code> <span class="code-identifier">s</span> <span class="code-keywords1">as</span> <span class="code-keywords4">string</span> <span class="code-comment">-- returned value </span></code>
<code><span class="code-symbol">)</span></code>
</pre><p>The highest number of glossy subdivisions of Arch&Design material in scene:</p><pre class="notranslate"><code><span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">highestGlossy</span> <span class="code-symbol">=</span> <span class="code-number">0</span></code>
<code></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">mat</span> <span class="code-keywords1">in</span> <span class="code-keywords3">sceneMaterials</span></code>
<code> <span class="code-keywords1">where</span> <span class="code-keywords3">isProperty</span> <span class="code-identifier">mat</span> <span class="code-symbol">#</span><span class="code-identifier">refl_samples</span> <span class="code-keywords2">AND</span></code>
<code> <span class="code-symbol">(</span><span class="code-keywords1">local</span> <span class="code-identifier">newGlossy</span> <span class="code-symbol">=</span> <span class="code-keywords3">getProperty</span> <span class="code-identifier">mat</span> <span class="code-symbol">#</span><span class="code-identifier">refl_samples</span><span class="code-symbol">)</span> <span class="code-symbol">></span> <span class="code-identifier">highestGlossy</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-identifier">highestGlossy</span> <span class="code-symbol">=</span> <span class="code-identifier">newGlossy</span></code>
<code></code>
<code> <span class="code-string">"Highest Glossy Subdivs: "</span> <span class="code-symbol">+</span> <span class="code-identifier">highestGlossy</span> <span class="code-keywords1">as</span> <span class="code-keywords4">string</span></code>
<code><span class="code-symbol">)</span></code>
</pre><p>Snippet to get the heaviest mesh in scene:</p><pre class="notranslate"><code><span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">heaviestMesh</span> <span class="code-symbol">=</span> <span class="code-symbol">#(</span><span class="code-number">0</span><span class="code-symbol">,</span><span class="code-string">"none"</span><span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">obj</span> <span class="code-keywords1">in</span> <span class="code-keywords3">geometry</span></code>
<code> <span class="code-keywords1">where</span> <span class="code-symbol">(</span><span class="code-keywords3">getPolygonCount</span> <span class="code-identifier">obj</span><span class="code-symbol">)[</span><span class="code-number">1</span><span class="code-symbol">]</span> <span class="code-symbol">></span> <span class="code-identifier">heaviestMesh</span><span class="code-symbol">[</span><span class="code-number">1</span><span class="code-symbol">]</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-identifier">heaviestMesh</span> <span class="code-symbol">=</span> <span class="code-symbol">#((</span><span class="code-keywords3">getPolygonCount</span> <span class="code-identifier">obj</span><span class="code-symbol">)[</span><span class="code-number">1</span><span class="code-symbol">],</span> <span class="code-identifier">obj</span><span class="code-symbol">.</span><span class="code-keywords4">name</span><span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-string">"Heaviest mesh: "</span> <span class="code-symbol">+</span> <span class="code-identifier">heaviestMesh</span><span class="code-symbol">[</span><span class="code-number">2</span><span class="code-symbol">]</span> <span class="code-symbol">+</span> <span class="code-string">", poly count: "</span> <span class="code-symbol">+</span> <span class="code-identifier">heaviestMesh</span><span class="code-symbol">[</span><span class="code-number">1</span><span class="code-symbol">]</span> <span class="code-keywords1">as</span> <span class="code-keywords4">string</span></code>
<code><span class="code-symbol">)</span></code>
</pre><p>Scene poly count and vertex count – this one depends on another factor which is whether or not the file had been saved since the last change in scene that would influence the poly and vertex count (even <code>saveNodes</code> command or scene hold updates scene information). If it has already been saved, we can use <code>(<span class="code-keywords3">fileProperties</span>.getItems <span class="code-string">"Mesh Totals"</span>)<span class="code-symbol">[</span><span class="code-number">1</span><span class="code-symbol">]</span></code> to get the vertex count and <code>(<span class="code-keywords3">fileProperties</span>.getItems <span class="code-string">"Mesh Totals"</span>)<span class="code-symbol">[</span><span class="code-number">2</span><span class="code-symbol">]</span></code> to get the face count. If not, something like this would work:</p><pre class="notranslate"><code>(</code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">faceTotal</span> <span class="code-symbol">=</span> <span class="code-number">0</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">vertTotal</span> <span class="code-symbol">=</span> <span class="code-number">0</span></code>
<code></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">obj</span> <span class="code-keywords1">in</span> <span class="code-keywords3">objects</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">meshTotal</span> <span class="code-symbol">=</span> <span class="code-keywords3">getPolygonCount</span> <span class="code-identifier">obj</span></code>
<code> <span class="code-identifier">vertTotal</span> <span class="code-symbol">+=</span> <span class="code-identifier">meshTotal</span><span class="code-symbol">[</span><span class="code-number">1</span><span class="code-symbol">]</span></code>
<code> <span class="code-identifier">faceTotal</span> <span class="code-symbol">+=</span> <span class="code-identifier">meshTotal</span><span class="code-symbol">[</span><span class="code-number">2</span><span class="code-symbol">]</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-string">"Vertices: "</span> <span class="code-symbol">+</span> <span class="code-identifier">vertTotal</span> <span class="code-keywords1">as</span> <span class="code-keywords4">string</span> <span class="code-symbol">+</span> <span class="code-string">" | Faces: "</span> <span class="code-symbol">+</span> <span class="code-identifier">faceTotal</span> <span class="code-keywords1">as</span> <span class="code-keywords4">string</span></code>
<code><span class="code-symbol">)</span></code>
</pre><p>Number of materials and their types:</p><pre class="notranslate"><code><span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">classes</span> <span class="code-symbol">=</span> <span class="code-symbol">#()</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">counts</span> <span class="code-symbol">=</span> <span class="code-symbol">#()</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">result</span> <span class="code-symbol">=</span> <span class="code-string">""</span></code>
<code></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">mat</span> <span class="code-keywords1">in</span> <span class="code-keywords3">sceneMaterials</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">if</span> <span class="code-symbol">(</span><span class="code-keywords1">local</span> <span class="code-identifier">index</span> <span class="code-symbol">=</span> <span class="code-keywords3">findItem</span> <span class="code-identifier">classes</span> <span class="code-symbol">(</span><span class="code-keywords3">classOf</span> <span class="code-identifier">mat</span><span class="code-symbol">))</span> <span class="code-symbol">></span> <span class="code-number">0</span> <span class="code-keywords1">then</span></code>
<code> <span class="code-identifier">counts</span><span class="code-symbol">[</span><span class="code-identifier">index</span><span class="code-symbol">]</span> <span class="code-symbol">+=</span> <span class="code-number">1</span></code>
<code> <span class="code-keywords1">else</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords3">append</span> <span class="code-identifier">classes</span> <span class="code-symbol">(</span><span class="code-keywords3">classOf</span> <span class="code-identifier">mat</span><span class="code-symbol">)</span></code>
<code> <span class="code-keywords3">append</span> <span class="code-identifier">counts</span> <span class="code-number">1</span></code>
<code> <span class="code-symbol">)</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">i</span> <span class="code-symbol">=</span> <span class="code-number">1</span> <span class="code-keywords1">to</span> <span class="code-identifier">classes</span><span class="code-symbol">.</span><span class="code-keywords1">count</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-keywords3">append</span> <span class="code-identifier">result</span> <span class="code-symbol">(</span><span class="code-identifier">classes</span><span class="code-symbol">[</span><span class="code-identifier">i</span><span class="code-symbol">]</span> <span class="code-keywords1">as</span> <span class="code-keywords4">string</span> <span class="code-symbol">+</span> <span class="code-string">":"</span> <span class="code-symbol">+</span> <span class="code-identifier">counts</span><span class="code-symbol">[</span><span class="code-identifier">i</span><span class="code-symbol">]</span> <span class="code-keywords1">as</span> <span class="code-keywords4">string</span> <span class="code-symbol">+</span> <span class="code-string">" "</span><span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-identifier">result</span></code>
<code><span class="code-symbol">)</span></code>
</pre><p>Scene dimensions (bounding box dimensions, bounding box center position):</p><pre class="notranslate"><code><span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">fn</span> <span class="code-identifier">formatPoint3</span> <span class="code-identifier">p3</span> <span class="code-symbol">=</span> <span class="code-string">"x:"</span> <span class="code-symbol">+</span> <span class="code-identifier">p3</span><span class="code-symbol">.</span><span class="code-identifier">x</span> <span class="code-keywords1">as</span> <span class="code-keywords4">string</span> <span class="code-symbol">+</span> <span class="code-string">", y:"</span> <span class="code-symbol">+</span> <span class="code-identifier">p3</span><span class="code-symbol">.</span><span class="code-identifier">y</span> <span class="code-keywords1">as</span> <span class="code-keywords4">string</span> <span class="code-symbol">+</span> <span class="code-string">", z:"</span> <span class="code-symbol">+</span> <span class="code-identifier">p3</span><span class="code-symbol">.</span><span class="code-identifier">z</span> <span class="code-keywords1">as</span> <span class="code-keywords4">string</span></code>
<code></code>
<code> <span class="code-string">"Dimensions: "</span> <span class="code-symbol">+</span> <span class="code-identifier">formatPoint3</span> <span class="code-symbol">(</span><span class="code-keywords3">objects</span><span class="code-symbol">.</span><span class="code-keywords1">max</span> <span class="code-symbol">-</span> <span class="code-keywords3">objects</span><span class="code-symbol">.</span><span class="code-identifier">min</span><span class="code-symbol">)</span> <span class="code-symbol">+</span> <span class="code-string">"; Center:"</span> <span class="code-symbol">+</span> <span class="code-identifier">formatPoint3</span> <span class="code-symbol">(</span><span class="code-keywords3">objects</span><span class="code-symbol">.</span><span class="code-identifier">center</span><span class="code-symbol">)</span></code>
<code><span class="code-symbol">)</span></code>
</pre>
<p>For yet more ideas be sure to have a look at the <a href="http://creativescratchpad.blogspot.com/2011/06/maxscript-one-liners-for-artists.html" title="Creative Scratchpad :: Maxscript One-Liners for Artists">Maxscript Oneliners for Artists</a> article.</p>
<p>All the custom expressions together with the script part are evaluated after the rendering is done. If you'd need to take into consideration some information you could only get before the rendering starts, you can register your own preRender callback that would save the desired value(s) to a global variable, and then access it from the script.</p><p>DISCLAIMER: All scripts and snippets are provided as is under <a href="http://creativecommons.org/publicdomain/zero/1.0/">Creative Commons Zero (public domain, no restrictions) license</a>. The author and this blog cannot be held liable for any loss caused as a result of inaccuracy or error within these web pages. Use at your own risk.</p>Swordslayerhttp://www.blogger.com/profile/09124250713006663760noreply@blogger.com0tag:blogger.com,1999:blog-4212150079314071223.post-29763213907147029672011-06-16T23:52:00.000+02:002016-12-24T16:44:56.585+01:00Maxscript one-liners for artistsThere are many cases when doing something by hand is too tiresome and you can get it done really fast with some simple maxscript knowledge.<br />
<a name='more'></a><div style="font-size: 10pt; font-weight: bold; padding-bottom: 8px;">
<br />Collections</div>
The first thing worth looking into are object sets, i.e. object (or rather node) collections. The predefined objects sets in max include <code>objects</code>, <code>geometry</code>, <code>lights</code>, <code>cameras</code>, <code>helpers</code>, <code>shapes</code>, <code>systems</code>, <code>spacewarps</code> and <code>selection</code>.<br />
<pre class="notranslate"><code> <span class="code-keywords3">select</span> <span class="code-keywords3">helpers</span> <span class="code-comment">-- selects all helper objects</span></code>
<code> <span class="code-keywords3">freeze</span> <span class="code-keywords1">selection</span> <span class="code-comment">-- freezes currently selected objects</span></code>
</pre>
Object sets are mappable which simply means that we can set their shared properties en masse.<br />
<pre class="notranslate"><code> <span class="code-keywords3">lights</span><span class="code-symbol">.</span><span class="code-keywords3">value</span> <span class="code-symbol">*=</span> <span class="code-number">0</span><span class="code-symbol">.</span><span class="code-number">5</span> <span class="code-comment">-- halve the intensity of all lights</span></code>
<code> <span class="code-keywords1">selection</span><span class="code-symbol">.</span><span class="code-keywords3">pos</span><span class="code-symbol">.</span><span class="code-identifier">z</span> <span class="code-symbol">=</span> <span class="code-number">0</span> <span class="code-comment">-- move all objects in selection to zero Z elevation</span></code>
<code> <span class="code-keywords3">objects</span><span class="code-symbol">.</span><span class="code-keywords4">mat</span> <span class="code-symbol">=</span> <span class="code-keywords1">undefined</span> <span class="code-comment">-- remove materials from all objects</span></code>
</pre>
This is all nice but what if we want just a specific subset of this group, for example just the key lights (note as well that when there is for example a skylight in the scene, the snippet above won't work as it doesn't have the <code>value</code> property)? Well, there's a <a href="http://docs.autodesk.com/3DSMAX/14/ENU/MAXScript%20Help%202012/index.html?url=files/GUID-8395020C-E3B6-4282-AF1C-5B58BDB97A2-391.htm,topicNumber=d28e140459" title="MAXScript Reference :: Pathname Literals">pathname access</a> which allows exactly for that. Pathnames identify individual objects in the scene and support not only hierarchic access but also wildcards. You have to prefix the object sets or object names by <code>$</code> to tell max you don't try to access a variable but names.<br />
<pre class="notranslate"><code> <span class="code-symbol">$</span><span class="code-keywords3">lights</span><span class="code-symbol">/</span><span class="code-identifier">Key</span><span class="code-symbol">*.</span><span class="code-keywords1">enabled</span> <span class="code-symbol">=</span> <span class="code-keywords1">on</span> <span class="code-comment">-- turn on all lights whose names start with "Key"</span></code>
<code> <span class="code-symbol">$*</span><span class="code-identifier">_left</span><span class="code-symbol">*.</span><span class="code-keywords3">position</span> <span class="code-symbol">+=</span> <span class="code-symbol">[</span><span class="code-number">50</span><span class="code-symbol">,</span><span class="code-number">20</span><span class="code-symbol">,</span><span class="code-number">10</span><span class="code-symbol">]</span> <span class="code-comment">-- adds 50,20,10 units (x,y,z order) to the positions</span></code>
<code> <span class="code-comment">-- of all objects whose names contain "_left"</span></code>
<code> <span class="code-keywords3">select</span> <span class="code-symbol">$</span><span class="code-symbol">/</span><span class="code-keywords1">selection</span><span class="code-symbol">/*</span> <span class="code-comment">-- get only top-level nodes from selection</span></code>
<code> <span class="code-keywords3">deselect</span> <span class="code-symbol">$</span><span class="code-identifier">Dummy</span><span class="code-symbol">??</span> <span class="code-comment">-- substracts from selection objects named Dummy__</span></code>
<code> <span class="code-comment">-- each ? substituting one character</span></code>
<code> <span class="code-keywords3">delete</span> <span class="code-symbol">$</span><span class="code-symbol">'</span><span class="code-identifier">car</span><span class="code-symbol">.</span><span class="code-identifier">wheel</span><span class="code-symbol">.*'</span> <span class="code-comment">-- delete object with specified name from scene</span></code>
<code> <span class="code-comment">-- handling special characters in objects' names using single quotes</span></code>
<code> <span class="code-symbol">$</span><span class="code-identifier">Box001</span><span class="code-symbol">*...*</span> <span class="code-keywords1">as</span> <span class="code-keywords4">array</span> <span class="code-comment">-- list containing Box001 and all its children (complete hierarchy)</span></code>
<code> <span class="code-keywords3">hide</span> <span class="code-symbol">$*/*</span><span class="code-comment"> -- hide all children in scene (i.e. leave only top-level nodes)</span></code>
<code> <span class="code-keywords3">selectionSets</span><span class="code-symbol">[</span><span class="code-string">"Boxes"</span><span class="code-symbol">]</span><span class="code-space"> </span><span class="code-symbol">=</span><span class="code-space"> </span><span class="code-symbol">$</span><span class="code-identifier">Box</span><span class="code-symbol">*</span> <span class="code-comment">-- make a selection set from objects starting with 'Box'</span></code>
</pre>
There are also collections that are only accessible as a property of the node, like the object's modifiers, and then special collection types such as <code>sceneMaterials</code> and <code>meditMaterials</code>. For the complete list of collections in maxscript refer to the <a href="http://docs.autodesk.com/3DSMAX/14/ENU/MAXScript%20Help%202012/index.html?url=files/GUID-92688D8B-A838-4519-9798-5DAB1107B0C-507.htm,topicNumber=d28e170402" title="MAXScript Language Reference :: Collections">collection types</a> (MXS Online Reference). In the next example, the <code>$</code> followed by a dot refers to the current selection. You can see it mostly in code based on the output of Macro Recorder. However, <code>selection</code> keyword is preferred and should be used instead, as it avoids ambiguity – <code>selection[1]</code> refers to a single object, first one in the selection set (if there is such an object), <code>selection</code> refers to the selection set itself.<br />
<pre class="notranslate"><code> <span class="code-symbol">$.</span><span class="code-identifier">modifiers</span><span class="code-symbol">.</span><span class="code-identifier">enabledInViews</span> <span class="code-symbol">=</span> <span class="code-keywords1">off</span> <span class="code-comment">-- sets the state of all modifiers of selected object</span></code>
<code> <span class="code-comment">-- to "Off in Viewport"</span></code>
<code> <span class="code-symbol">$.</span><span class="code-identifier">children</span><span class="code-symbol">.</span><span class="code-identifier">wirecolor</span> <span class="code-symbol">=</span> <span class="code-keywords1">red</span> <span class="code-comment">-- modify wirecolor of direct children of a node</span></code>
<code> <span class="code-symbol">$.</span><span class="code-identifier">selectedVerts</span><span class="code-symbol">.</span><span class="code-keywords1">count</span> <span class="code-comment">-- get number of selected vertices</span></code>
</pre>
As we are accessing properties here and property access is not mapped (it makes sense to set one common propety in one go, not so much to get probably different properties with no sense of their ordering), the execution would error out if you'd have more than one object selected (which would not happen if <code>selection[1]</code> was used instead) or if the selection was empty (which would happen anyway). But there are many cases where we want to manipulate many objects and where the previous method would not work.<br />
<br /><div style="font-size: 10pt; font-weight: bold; padding-bottom: 8px;">Traversing collections</div>
That's where <a href='http://docs.autodesk.com/3DSMAX/16/ENU/MAXScript-Help/files/GUID-378F3155-6001-43A7-9E0D-6D98E0823F6F.htm'><code>for</code>-loop</a> comes into play. There are basically two possibilities as to how to use a <code>for</code>-loop, first one is indexed access and the second one is iterating over a collection. The second one executes a certain operation on each member of a collection and will be extremely useful for us. The syntax is simple and it works without glitches even if the collection is empty or has just one member.<br />
<pre class="notranslate"><code> <span class="code-keywords1">for</span> <span class="code-identifier">obj</span> <span class="code-keywords1">in</span> <span class="code-keywords1">selection</span> <span class="code-keywords1">do</span> <span class="code-identifier">obj</span><span class="code-symbol">.</span><span class="code-keywords4">name</span> <span class="code-symbol">=</span> <span class="code-keywords3">uniqueName</span> <span class="code-string">"Prefix"</span></code>
<code> <span class="code-comment">-- for every object in selection do : set object name to unique name with a given prefix</span></code>
<code> <span class="code-comment">-- obj here is a variable (you can use any other variable name instead, i, item etc.)</span></code>
</pre>
All the built-in collections are live, which means that if you want to take a snapshot of them at any given time, you have to cast them to array when assigning to a variable. However, it is also easy to make use of this property, for example when you call <code>selectMore</code> function, the object it is called on gets appended to the selection set. While the <code>node.children</code> collection contains only direct children of the node, this allows you to get the whole hierarchy:<br />
<pre class="notranslate"><code> <span class="code-keywords1">for</span> <span class="code-identifier">obj</span> <span class="code-keywords1">in</span> <span class="code-keywords1">selection</span> <span class="code-keywords1">do</span> <span class="code-keywords3">selectMore</span> <span class="code-identifier">obj</span><span class="code-symbol">.</span><span class="code-identifier">children</span></code>
<code> <span class="code-comment">-- add all children of currently selected nodes to the selection</span></code></pre>
There's also the <a href='http://docs.autodesk.com/3DSMAX/16/ENU/MAXScript-Help/files/GUID-EAD55DDE-6C7C-44CB-8BC8-34905BC05BE5.htm'><code>while</code> loop</a> which keeps repeating the task until the condition is met:<br />
<pre class="notranslate"><code> <span class="code-keywords1">while</span> <span class="code-keywords1">selection</span><span class="code-symbol">.</span><span class="code-keywords1">count</span> <span class="code-symbol">></span> <span class="code-number">50</span> <span class="code-keywords1">do</span> <span class="code-keywords3">deselect</span> <span class="code-keywords1">selection</span><span class="code-symbol">[</span><span class="code-keywords3">random</span> <span class="code-number">1</span> <span class="code-keywords1">selection</span><span class="code-symbol">.</span><span class="code-keywords1">count</span><span class="code-symbol">]</span></code>
<code> <span class="code-comment">-- deselect random objects until only 50 are left selected</span></code></pre>
Additionaly, there are two optional expressions for the <code>for</code> loop itself that we can use to narrow down the items we are interested in accessing, <code>where</code> and <code>while</code>. Let's have a look at an example using <code>where</code>:<br />
<pre class="notranslate"><code> <span class="code-keywords1">for</span> <span class="code-identifier">obj</span> <span class="code-keywords1">in</span> <span class="code-keywords3">objects</span> <span class="code-keywords1">where</span> <span class="code-keywords3">isGroupHead</span> <span class="code-identifier">obj</span> <span class="code-keywords1">do</span> <span class="code-keywords3">setGroupOpen</span> <span class="code-identifier">obj</span> <span class="code-keywords1">on</span></code>
<code> <span class="code-comment">-- for each object, where the object is a Head of a group, set the group open</span></code>
</pre>
Multiple such tests can be combined together. To check if all conditions hold, use <code>and</code>, for one or more <code>or</code> and <code>not</code> to flip the resulting value of the expression. They are called boolean operators and to learn more about using them, be sure to look at the <a href="http://docs.autodesk.com/3DSMAX/15/ENU/MAXScript-Help/index.html?url=files/GUID-7C65C77D-3C74-482B-ACC2-3D5D879DD99C.htm,topicNumber=d30e144235">Logical Expressions</a> chapter of the MAXScript reference. Note that even though I consistently use uppercase for them, it does not make any difference if you write them all lowercase (or even mixed case) as MAXScript is not case sensitive language and it is a matter of personal preference and/or which coding style you choose to follow.<br />
<pre class="notranslate"><code> <span class="code-keywords1">for</span> <span class="code-identifier">obj</span> <span class="code-keywords1">in</span> <span class="code-keywords1">selection</span> <span class="code-keywords1">where</span> <span class="code-keywords3">isKindOf</span> <span class="code-identifier">obj</span> <span class="code-keywords4">Helper</span> <span class="code-keywords2">AND</span> <span class="code-identifier">obj</span><span class="code-symbol">.</span><span class="code-keywords4">parent</span> <span class="code-symbol">==</span> <span class="code-keywords1">undefined</span> <span class="code-keywords1">do</span> <span class="code-keywords3">print</span> <span class="code-identifier">obj</span><span class="code-symbol">.</span><span class="code-keywords4">name</span></code>
<code> <span class="code-comment">-- for each selected helper which is not parented to anything print out its name</span></code>
</pre>
One good example of using conditions in loops is avoiding errors such as invalid property assignments, the classic example would be assigning some fixed <code>value</code> or <code>intensity</code> to all lights that have the property (remember how the <code>lights.value *= 0.5</code> example wouldn't work with skylight?):<br />
<pre class="notranslate"><code> <span class="code-keywords1">for</span> eachLight <span class="code-keywords1">in</span> <span class="code-keywords3">lights</span> <span class="code-keywords1">where</span> <span class="code-keywords3">isProperty</span> eachLight <span class="code-string">#intensity</span> <span class="code-keywords1">do</span> eachLight.<span class="code-keywords3">intensity</span> <span class="code-symbol">=</span> <span class="code-number">1000</span></code>
<code> <span class="code-comment">-- for each light that has the property intensity, make that property value 1000</span></code>
</pre>
And rather than doing something with each node separately in every single iteration we can collect the nodes to an array, and work with the resulting array instead. For-loop with <code>collect</code> keyword instead of the usual <code>do</code> returns the array and if you don't need to store it, you can access it directly (the command in brackets evaluates first):<br />
<pre class="notranslate"><code> <span class="code-keywords3">select</span> <span class="code-symbol">(</span><span class="code-keywords1">for</span> <span class="code-identifier">obj</span> <span class="code-keywords1">in</span> <span class="code-keywords3">geometry</span> <span class="code-keywords1">where</span> <span class="code-keywords3">getNumTVerts</span> <span class="code-identifier">obj</span> <span class="code-symbol">==</span> <span class="code-number">0</span> <span class="code-keywords1">collect</span> <span class="code-identifier">obj</span><span class="code-symbol">)</span></code>
<code> <span class="code-comment">-- select (for each geometry object, where the object doesn't have any texture vertices collect that object)</span></code>
<code> <span class="code-comment">-- i.e., this selects all objects without proper mapping coordinates</span></code>
<code></code>
<code> <span class="code-keywords3">select</span> <span class="code-symbol">(</span><span class="code-keywords1">for</span> <span class="code-identifier">obj</span> <span class="code-keywords1">in</span> <span class="code-symbol">$</span><span class="code-keywords4">box</span><span class="code-symbol">*</span> <span class="code-keywords1">where</span> <span class="code-identifier">obj</span><span class="code-symbol">.</span><span class="code-keywords3">height</span> <span class="code-symbol">></span> <span class="code-number">100</span> <span class="code-keywords1">collect</span> <span class="code-identifier">obj</span><span class="code-symbol">)</span></code>
<code> <span class="code-comment">-- select all objects starting with "Box" with height (in system units) bigger than 100</span></code>
<code></code>
<code> <span class="code-keywords3">select</span> <span class="code-symbol">(</span><span class="code-symbol">$*</span>_right<span class="code-symbol">*</span> <span class="code-keywords1">as</span> <span class="code-keywords4">array</span> <span class="code-symbol">+</span> <span class="code-symbol">$*</span>_left<span class="code-symbol">*</span> <span class="code-keywords1">as</span> <span class="code-keywords4">array</span><span class="code-symbol">)</span></code>
<code> <span class="code-comment">-- select objects whose names contain either _right or _left</span></code>
</pre>
Sometimes, you want to change or distribute a number of objects at once. There are several commands in MAXScript to make your life easier, here I've picked a few common tasks:<br />
<pre class="code-notranslate">
<code> <span class="code-keywords1">for</span><span class="code-space"> </span><span class="code-identifier">obj</span><span class="code-space"> </span><span class="code-keywords1">in</span><span class="code-space"> </span><span class="code-keywords1">selection</span><span class="code-space"> </span><span class="code-keywords1">do</span><span class="code-space"> </span><span class="code-keywords3">instance</span><span class="code-space"> </span><span class="code-symbol">$</span><span class="code-identifier">Downlight001</span><span class="code-space"> </span><span class="code-keywords3">pos</span><span class="code-symbol">:</span><span class="code-identifier">obj</span><span class="code-symbol">.</span><span class="code-keywords3">pos</span></code>
<code> <span class="code-comment">-- place instances of object at pivots of selected objects</span></code>
<code></code>
<code> <span class="code-keywords3">instanceReplace</span><span class="code-space"> </span><span class="code-keywords1">selection</span><span class="code-space"> </span><span class="code-symbol">$</span><span class="code-identifier">LampPost01</span></code>
<code> <span class="code-comment">-- replace objects in selection with specified object (respecting the transforms)</span></code>
<code></code>
<code> <span class="code-symbol">(</span><span class="code-keywords3">getClassInstances</span><span class="code-space"> </span><span class="code-keywords4">TurboSmooth</span><span class="code-symbol">).</span><span class="code-identifier">enabledInViews</span><span class="code-space"> </span><span class="code-symbol">=</span><span class="code-space"> </span><span class="code-keywords1">off</span></code>
<code> <span class="code-comment">-- turn all the TurboSmooth modifiers off in viewport (stays on in render)</span></code>
<code></code>
<code> <span class="code-keywords3">select</span><span class="code-space"> </span><span class="code-symbol">(</span><span class="code-keywords3">refs</span><span class="code-symbol">.</span><span class="code-identifier">dependentNodes</span><span class="code-space"> </span><span class="code-symbol">$.</span><span class="code-keywords4">baseObject</span><span class="code-symbol">)</span></code>
<code> <span class="code-comment">-- select instances and references of the selected node</span></code>
</pre>
<div style="font-size: 10pt; font-weight: bold; padding-bottom: 8px;">
Closing thoughts</div>
While some of these scripts are suboptimal, in most cases they are good enough and can be easily altered to fit the purpose. There is also an added benefit to oneliners, after executing the script you can easily reevaluate it just by right-clicking the mini listener and picking the corresponding line from the list of recent commands.<br />
<div style="border: none; margin-right: 1em; text-align: center;">
<a href="https://www.blogger.com/null" imageanchor="1" name="Mini Listener"><img alt="Reevaluating a oneliner" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCo4watKcI6s4MGXiCVXlIZGCoIMLPvHhLlvfaefpTl4dyNHb5MPpvQUeqoYj2Fos41pVymzsCeMgpxcSXl3zY_ABsO3gb-vMJ87IQh5zMzoDmaysvnN09dvuhf3pIUbtdrvsMpd-IG1o/s1600/mini-listener.png" title="Reevaluating a oneliner" /></a></div>
<br />
DISCLAIMER: All scripts and snippets are provided as is under <a href="http://creativecommons.org/publicdomain/zero/1.0/">Creative Commons Zero (public domain, no restrictions) license</a>. The author and this blog cannot be held liable for any loss caused as a result of inaccuracy or error within these web pages. Use at your own risk.Swordslayerhttp://www.blogger.com/profile/09124250713006663760noreply@blogger.com3tag:blogger.com,1999:blog-4212150079314071223.post-30101270762468094152011-06-15T18:34:00.000+02:002012-11-24T11:49:48.014+01:00Select Random Elements by PercentageThis little script allows you to randomly select a number (given by percent) of elements in a mesh. Works both on editable poly and editable mesh objects. Note that for certain usage scenarios, applying MaterialByElement modifier and using the ID percentages generated by that might be faster.<br />
<br />
<a name='more'></a><pre class="notranslate" style="height: 400px;"><code><span class="code-keywords1">try</span> <span class="code-keywords3">destroyDialog</span> <span class="code-identifier">selectRandElements</span> <span class="code-keywords1">catch</span><span class="code-symbol">()</span></code>
<code><span class="code-keywords5">rollout</span> <span class="code-identifier">selectRandElements</span> <span class="code-string">"Select Random Elements"</span> <span class="code-keywords3">width</span><span class="code-symbol">:</span><span class="code-number">205</span></code>
<code><span class="code-symbol">(</span></code>
<code> <span class="code-keywords5">label</span> <span class="code-identifier">lblPercentage</span> <span class="code-string">"Percent of total:"</span> <span class="code-keywords3">across</span><span class="code-symbol">:</span><span class="code-number">3</span> <span class="code-keywords3">offset</span><span class="code-symbol">:[</span><span class="code-number">0</span><span class="code-symbol">,</span><span class="code-number">3</span><span class="code-symbol">]</span></code>
<code> <span class="code-keywords5">spinner</span> <span class="code-identifier">spnPercentage</span> <span class="code-keywords3">width</span><span class="code-symbol">:</span><span class="code-number">50</span> <span class="code-keywords3">scale</span><span class="code-symbol">:</span><span class="code-number">1</span> <span class="code-keywords3">range</span><span class="code-symbol">:[</span><span class="code-number">0</span><span class="code-symbol">,</span><span class="code-number">100</span><span class="code-symbol">,</span><span class="code-number">10</span><span class="code-symbol">.]</span> <span class="code-keywords3">offset</span><span class="code-symbol">:[</span><span class="code-number">0</span><span class="code-symbol">,</span><span class="code-number">2</span><span class="code-symbol">]</span></code>
<code> <span class="code-keywords5">button</span> <span class="code-identifier">btnSelect</span> <span class="code-string">"SELECT"</span> <span class="code-keywords3">height</span><span class="code-symbol">:</span><span class="code-number">22</span> <span class="code-keywords3">offset</span><span class="code-symbol">:[</span><span class="code-number">12</span><span class="code-symbol">,</span><span class="code-number">0</span><span class="code-symbol">]</span></code>
<code></code>
<code> <span class="code-keywords1">fn</span> <span class="code-identifier">randomizeArray arr</span> <span class="code-symbol">=</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">arrayLength</span> <span class="code-symbol">=</span> <span class="code-identifier">arr</span><span class="code-symbol">.</span><span class="code-keywords1">count</span></code>
<code></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">i</span> <span class="code-symbol">=</span> <span class="code-number">1</span> <span class="code-keywords1">to</span> <span class="code-identifier">arrayLength</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">index</span> <span class="code-symbol">=</span> <span class="code-keywords3">random</span> <span class="code-identifier">i arrayLength</span></code>
<code> <span class="code-keywords3">swap</span> <span class="code-identifier">arr</span><span class="code-symbol">[</span><span class="code-identifier">i</span><span class="code-symbol">]</span> <span class="code-identifier">arr</span><span class="code-symbol">[</span><span class="code-identifier">index</span><span class="code-symbol">]</span></code>
<code> <span class="code-symbol">)</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords1">on</span> <span class="code-identifier">btnSelect</span> <span class="code-keywords1">pressed</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-keywords1">if</span> <span class="code-keywords1">selection</span><span class="code-symbol">.</span><span class="code-keywords1">count</span> <span class="code-symbol">></span> <span class="code-number">0</span> <span class="code-keywords2">AND</span> <span class="code-symbol">(</span><span class="code-keywords3">isKindOf</span> <span class="code-symbol">(</span><span class="code-identifier">obj</span> <span class="code-symbol">=</span> <span class="code-keywords1">selection</span><span class="code-symbol">[</span><span class="code-number">1</span><span class="code-symbol">])</span> <span class="code-keywords4">Editable_Poly</span> <span class="code-keywords2">OR</span> <span class="code-keywords3">isKindOf</span> <span class="code-identifier">obj</span> <span class="code-keywords4">Editable_Mesh</span><span class="code-symbol">)</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">if</span> <span class="code-keywords3">heapSize</span> <span class="code-symbol"><</span> <span class="code-number">102400000</span> <span class="code-keywords1">do</span> <span class="code-keywords3">heapSize</span> <span class="code-symbol">=</span> <span class="code-number">102400000</span></code>
<code></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">faces</span> <span class="code-symbol">=</span> <span class="code-symbol">#{}</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">obj_faces</span> <span class="code-symbol">=</span> <span class="code-identifier">obj</span><span class="code-symbol">.</span><span class="code-identifier">faces</span> <span class="code-keywords1">as</span> <span class="code-keywords4">bitArray</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">obj_faces_arr</span> <span class="code-symbol">=</span> <span class="code-identifier">obj_faces</span> <span class="code-keywords1">as</span> <span class="code-keywords4">array</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">obj_faces_count</span> <span class="code-symbol">=</span> <span class="code-identifier">obj_faces_arr</span><span class="code-symbol">.</span><span class="code-keywords1">count</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">op</span> <span class="code-symbol">=</span> <span class="code-keywords1">if</span> <span class="code-keywords3">isKindOf</span> <span class="code-identifier">obj</span> <span class="code-keywords4">Editable_Poly</span> <span class="code-keywords1">then</span> <span class="code-keywords3">polyOp</span> <span class="code-keywords1">else</span> <span class="code-keywords3">meshOp</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">getElement</span> <span class="code-symbol">=</span> <span class="code-identifier">op</span><span class="code-symbol">.</span><span class="code-keywords3">getElementsUsingFace</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">step</span> <span class="code-symbol">=</span> <span class="code-number">100</span><span class="code-symbol">./</span><span class="code-identifier">spnPercentage</span><span class="code-symbol">.</span><span class="code-keywords3">value</span></code>
<code></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">elements</span> <span class="code-symbol">=</span> <span class="code-keywords1">for</span> <span class="code-identifier">i</span> <span class="code-keywords1">in</span> <span class="code-identifier">obj_faces</span> <span class="code-keywords1">where</span> <span class="code-identifier">obj_faces</span><span class="code-symbol">[</span><span class="code-identifier">i</span><span class="code-symbol">]</span> <span class="code-symbol">==</span> <span class="code-keywords1">true</span> <span class="code-keywords1">collect</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">element</span> <span class="code-symbol">=</span> <span class="code-identifier">getElement</span> <span class="code-identifier">obj</span> <span class="code-identifier">i</span></code>
<code> <span class="code-identifier">obj_faces</span> <span class="code-symbol">-=</span> <span class="code-identifier">element</span></code>
<code> <span class="code-identifier">element</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-identifier">randomizeArray elements</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">elements_count</span> <span class="code-symbol">=</span> <span class="code-identifier">elements</span><span class="code-symbol">.</span><span class="code-keywords1">count</span></code>
<code></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">i</span> <span class="code-symbol">=</span> <span class="code-number">1</span> <span class="code-keywords1">to</span> <span class="code-identifier">elements_count</span> <span class="code-keywords1">by</span> <span class="code-identifier">step</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-identifier">faces</span> <span class="code-symbol">+=</span> <span class="code-identifier">elements</span><span class="code-symbol">[</span><span class="code-identifier">i</span><span class="code-symbol">]</span></code>
<code></code>
<code> <span class="code-identifier">obj</span><span class="code-symbol">.</span><span class="code-keywords3">selectedFaces</span> <span class="code-symbol">=</span> <span class="code-identifier">faces</span></code>
<code> <span class="code-keywords1">max</span> <span class="code-identifier">modify mode</span></code>
<code> <span class="code-identifier">subObjectLevel</span> <span class="code-symbol">=</span> <span class="code-number">4</span></code>
<code> <span class="code-keywords3">completeRedraw</span><span class="code-symbol">()</span></code>
<code> <span class="code-symbol">)</span></code>
<code><span class="code-symbol">)</span></code>
<code><span class="code-keywords3">createDialog</span> <span class="code-identifier">selectRandElements</span></code>
</pre><p>USAGE: Run the script, enter desired value (in percent), select a mesh and press the SELECT button.</p><div style="margin-right: 1em; text-align: center; border:none;"><a name="Randomize UVW" imageanchor="1"><img alt="Randomize UVW UI" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiARP5Be6MarHwjbMgP3Gymg1yTDFqIxdPjkTu9BDBxkPFj9cSgX1gMmL6fUmRcDbbdsWdFHxhttMHQI0oHBUz-GtLErJObFKyfz7fccGT-shZS8dCTgenIDWyzHA2dx2gbL2zxKerlav0/s1600/select-elements.png" title="Randomize UVW UI" /></a></div></ br><br />
<p>DISCLAIMER: All scripts and snippets are provided as is under <a href="http://creativecommons.org/publicdomain/zero/1.0/">Creative Commons Zero (public domain, no restrictions) license</a>. The author and this blog cannot be held liable for any loss caused as a result of inaccuracy or error within these web pages. Use at your own risk.</p>Swordslayerhttp://www.blogger.com/profile/09124250713006663760noreply@blogger.com3tag:blogger.com,1999:blog-4212150079314071223.post-12903905348305076552011-06-14T19:20:00.001+02:002012-11-19T11:38:22.726+01:00Using Mousewheel with SlidersThere exists an underused feature of the sliders in max that allows you to increase/decrease their value just by rolling the mousewheel. In a default state, there's a catch, once you roll your wheel and the value changes, the spinner loses focus and you have to click it again to be able to repeat the success. However, this is easy to fix:<a name='more'></a><pre class="notranslate"><code><span class="code-keywords5">rollout</span> <span class="code-identifier">rollIt</span> <span class="code-string">""</span></code>
<code><span class="code-symbol">(</span></code>
<code> <span class="code-keywords5">spinner</span> <span class="code-identifier">spn</span> <span class="code-string">"Click'n'roll: "</span> <span class="code-keywords3">range</span><span class="code-symbol">:[-</span><span class="code-number">1e9</span><span class="code-symbol">,</span><span class="code-number">1e9</span><span class="code-symbol">,</span><span class="code-number">1</span><span class="code-symbol">]</span> <span class="code-keywords3">scale</span><span class="code-symbol">:.</span><span class="code-number">5</span></code>
<code></code>
<code> <span class="code-keywords1">on</span> <span class="code-identifier">rollIt</span> <span class="code-keywords3">open</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-keywords3">setFocus</span> <span class="code-identifier">spn</span></code>
<code></code>
<code> <span class="code-keywords1">on</span> <span class="code-identifier">spn</span> <span class="code-keywords1">changed</span> <span class="code-identifier">val</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-keywords3">setFocus</span> <span class="code-identifier">spn</span></code>
<code><span class="code-symbol">)</span></code>
<code><span class="code-keywords3">createDialog</span> <span class="code-identifier">rollIt</span></code>
</pre><p>USAGE: Run the script and roll your mousewheel. If you click elsewhere and the control loses focus, click inside it again to be able to use the mousewheel as before.</p><p>NOTE: It seems that in newer versions of max (2012, to be exact) this can cause the spinner to become unresponsive.</p><p>DISCLAIMER: All scripts and snippets are provided as is under <a href="http://creativecommons.org/publicdomain/zero/1.0/">Creative Commons Zero (public domain, no restrictions) license</a>. The author and this blog cannot be held liable for any loss caused as a result of inaccuracy or error within these web pages. Use at your own risk.</p>Swordslayerhttp://www.blogger.com/profile/09124250713006663760noreply@blogger.com2tag:blogger.com,1999:blog-4212150079314071223.post-91344089493452987702011-06-11T00:39:00.000+02:002012-11-19T11:38:39.079+01:00Incremental Grid Slice<p>If you ever needed a lot of individual chunks instead of a large mesh, you know that it's not so easy to spilt the mesh (in a grid) and detach all the resulting elements into individual meshes. If you only need to separate it in let's say 10,000 individual pieces, this script may be for you:</p><a name='more'></a><pre class="notranslate" style="height: 400px;"><code><span class="code-keywords1">try</span> <span class="code-keywords3">destroyDialog</span> <span class="code-identifier">sliceInChunks</span> <span class="code-keywords1">catch</span><span class="code-symbol">()</span></code>
<code><span class="code-keywords5">rollout</span> <span class="code-identifier">sliceInChunks</span> <span class="code-string">"Slice in Chunks"</span> <span class="code-keywords3">width</span><span class="code-symbol">:</span><span class="code-number">187</span></code>
<code><span class="code-symbol">(</span></code>
<code> <span class="code-keywords5">spinner</span> <span class="code-identifier">spnStep1</span> <span class="code-string">""</span> <span class="code-keywords3">range</span><span class="code-symbol">:[</span><span class="code-number">1</span><span class="code-symbol">,</span><span class="code-number">10</span><span class="code-symbol">,</span><span class="code-number">4</span><span class="code-symbol">]</span> <span class="code-identifier">type</span><span class="code-symbol">:#</span><span class="code-keywords4">integer</span> <span class="code-keywords3">width</span><span class="code-symbol">:</span><span class="code-number">40</span> <span class="code-keywords3">across</span><span class="code-symbol">:</span><span class="code-number">3</span> <span class="code-keywords3">align</span><span class="code-symbol">:#</span><span class="code-identifier">left</span></code>
<code> <span class="code-keywords5">spinner</span> <span class="code-identifier">spnStep2</span> <span class="code-string">"\xd7 "</span> <span class="code-keywords3">range</span><span class="code-symbol">:[</span><span class="code-number">1</span><span class="code-symbol">,</span><span class="code-number">10</span><span class="code-symbol">,</span><span class="code-number">3</span><span class="code-symbol">]</span> <span class="code-identifier">type</span><span class="code-symbol">:#</span><span class="code-keywords4">integer</span> <span class="code-keywords3">width</span><span class="code-symbol">:</span><span class="code-number">55</span> <span class="code-keywords3">offset</span><span class="code-symbol">:[-</span><span class="code-number">14</span><span class="code-symbol">,</span><span class="code-number">0</span><span class="code-symbol">]</span></code>
<code> <span class="code-keywords5">spinner</span> <span class="code-identifier">spnStep3</span> <span class="code-string">"\xd7 "</span> <span class="code-keywords3">range</span><span class="code-symbol">:[</span><span class="code-number">1</span><span class="code-symbol">,</span><span class="code-number">10</span><span class="code-symbol">,</span><span class="code-number">3</span><span class="code-symbol">]</span> <span class="code-identifier">type</span><span class="code-symbol">:#</span><span class="code-keywords4">integer</span> <span class="code-keywords3">width</span><span class="code-symbol">:</span><span class="code-number">55</span> <span class="code-keywords3">align</span><span class="code-symbol">:#</span><span class="code-identifier">right</span></code>
<code> <span class="code-keywords5">checkBox</span> <span class="code-identifier">chxHidden</span> <span class="code-string">"Make the sliced chunks hidden"</span> <span class="code-keywords1">checked</span><span class="code-symbol">:</span><span class="code-keywords1">true</span> <span class="code-keywords3">align</span><span class="code-symbol">:#</span><span class="code-identifier">center</span> <span class="code-keywords3">offset</span><span class="code-symbol">:[</span><span class="code-number">0</span><span class="code-symbol">,</span><span class="code-number">3</span><span class="code-symbol">]</span></code>
<code> <span class="code-keywords5">button</span> <span class="code-identifier">btnSlice</span> <span class="code-string">""</span> <span class="code-keywords3">height</span><span class="code-symbol">:</span><span class="code-number">27</span> <span class="code-keywords3">align</span><span class="code-symbol">:#</span><span class="code-identifier">center</span> <span class="code-keywords3">offset</span><span class="code-symbol">:[</span><span class="code-number">0</span><span class="code-symbol">,</span><span class="code-number">5</span><span class="code-symbol">]</span></code>
<code> <span class="code-keywords5">progressBar</span> <span class="code-identifier">pbStep1</span> <span class="code-string">""</span> <span class="code-keywords3">width</span><span class="code-symbol">:</span><span class="code-number">170</span> <span class="code-keywords3">height</span><span class="code-symbol">:</span><span class="code-number">10</span> <span class="code-keywords4">color</span><span class="code-symbol">:</span><span class="code-keywords1">orange</span> <span class="code-keywords3">offset</span><span class="code-symbol">:[-</span><span class="code-number">5</span><span class="code-symbol">,</span><span class="code-number">5</span><span class="code-symbol">]</span></code>
<code> <span class="code-keywords5">progressBar</span> <span class="code-identifier">pbStep2</span> <span class="code-string">""</span> <span class="code-keywords3">width</span><span class="code-symbol">:</span><span class="code-number">170</span> <span class="code-keywords3">height</span><span class="code-symbol">:</span><span class="code-number">10</span> <span class="code-keywords4">color</span><span class="code-symbol">:[</span><span class="code-number">0</span><span class="code-symbol">,</span><span class="code-number">100</span><span class="code-symbol">,</span><span class="code-number">180</span><span class="code-symbol">]</span> <span class="code-keywords3">offset</span><span class="code-symbol">:[-</span><span class="code-number">5</span><span class="code-symbol">,</span><span class="code-number">0</span><span class="code-symbol">]</span></code>
<code></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">detachFaces</span> <span class="code-symbol">=</span> <span class="code-keywords3">meshOp</span><span class="code-symbol">.</span><span class="code-identifier">detachFaces</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">getElement</span> <span class="code-symbol">=</span> <span class="code-keywords3">meshOp</span><span class="code-symbol">.</span><span class="code-identifier">getElementsUsingFace</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">meshSlice</span> <span class="code-symbol">=</span> <span class="code-keywords3">meshOp</span><span class="code-symbol">.</span><span class="code-identifier">slice</span></code>
<code></code>
<code> <span class="code-keywords1">fn</span> <span class="code-identifier">updateCount</span> <span class="code-symbol">=</span></code>
<code> <span class="code-identifier">btnSlice</span><span class="code-symbol">.</span><span class="code-keywords4">text</span> <span class="code-symbol">=</span> <span class="code-string">" Slice into "</span> <span class="code-symbol">+</span> <span class="code-symbol">(</span><span class="code-identifier">spnStep1</span><span class="code-symbol">.</span><span class="code-keywords3">value</span><span class="code-symbol">^</span><span class="code-number">2</span> <span class="code-symbol">*</span> <span class="code-identifier">spnStep2</span><span class="code-symbol">.</span><span class="code-keywords3">value</span><span class="code-symbol">^</span><span class="code-number">2</span> <span class="code-symbol">*</span> <span class="code-identifier">spnStep3</span><span class="code-symbol">.</span><span class="code-keywords3">value</span><span class="code-symbol">^</span><span class="code-number">2</span><span class="code-symbol">)</span> <span class="code-keywords1">as</span> <span class="code-keywords4">string</span> <span class="code-symbol">+</span> <span class="code-string">" pieces "</span></code>
<code></code>
<code> <span class="code-keywords1">mapped</span> <span class="code-keywords1">fn</span> <span class="code-identifier">renameDetached</span> <span class="code-identifier">obj</span> <span class="code-identifier">formatStr</span> <span class="code-symbol">&</span><span class="code-identifier">objCount</span> <span class="code-symbol">=</span></code>
<code> <span class="code-identifier">obj</span><span class="code-symbol">.</span><span class="code-keywords4">name</span> <span class="code-symbol">+=</span> <span class="code-keywords3">formattedPrint</span> <span class="code-symbol">(</span><span class="code-identifier">objCount</span> <span class="code-symbol">+=</span> <span class="code-number">1</span><span class="code-symbol">)</span> <span class="code-keywords3">format</span><span class="code-symbol">:</span><span class="code-identifier">formatStr</span></code>
<code></code>
<code> <span class="code-keywords1">fn</span> <span class="code-identifier">explodeMesh</span> <span class="code-identifier">obj</span> <span class="code-identifier">intCount</span> <span class="code-symbol">&</span><span class="code-identifier">detachedObjs</span> <span class="code-symbol">=</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-identifier">detachedObjs</span><span class="code-symbol">[</span><span class="code-number">1</span><span class="code-symbol">]</span> <span class="code-symbol">=</span> <span class="code-identifier">obj</span></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">element</span> <span class="code-symbol">=</span> <span class="code-number">2</span> <span class="code-keywords1">to</span> <span class="code-identifier">intCount</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">newMesh</span> <span class="code-symbol">=</span> <span class="code-keywords3">detachFaces</span> <span class="code-identifier">obj</span> <span class="code-symbol">(</span><span class="code-identifier">getElement</span> <span class="code-identifier">obj</span> <span class="code-number">1</span><span class="code-symbol">)</span> <span class="code-keywords3">delete</span><span class="code-symbol">:</span><span class="code-keywords1">true</span> <span class="code-identifier">asMesh</span><span class="code-symbol">:</span><span class="code-keywords1">true</span></code>
<code> <span class="code-symbol">(</span><span class="code-identifier">detachedObjs</span><span class="code-symbol">[</span><span class="code-identifier">element</span><span class="code-symbol">]</span> <span class="code-symbol">=</span> <span class="code-symbol">(</span><span class="code-keywords3">copy</span> <span class="code-identifier">obj</span> <span class="code-keywords4">name</span><span class="code-symbol">:#detached</span> <span class="code-keywords4">isHidden</span><span class="code-symbol">:</span><span class="code-keywords1">true</span><span class="code-symbol">)).</span><span class="code-keywords3">mesh</span> <span class="code-symbol">=</span> <span class="code-identifier">newMesh</span></code>
<code> <span class="code-keywords3">delete</span> <span class="code-identifier">newMesh</span></code>
<code> <span class="code-symbol">)</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords1">fn</span> <span class="code-identifier">explodeMeshNoCollect</span> <span class="code-identifier">obj</span> <span class="code-identifier">intCount</span> <span class="code-symbol">=</span></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">element</span> <span class="code-symbol">=</span> <span class="code-number">2</span> <span class="code-keywords1">to</span> <span class="code-identifier">intCount</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">newMesh</span> <span class="code-symbol">=</span> <span class="code-keywords3">detachFaces</span> <span class="code-identifier">obj</span> <span class="code-symbol">(</span><span class="code-identifier">getElement</span> <span class="code-identifier">obj</span> <span class="code-number">1</span><span class="code-symbol">)</span> <span class="code-keywords3">delete</span><span class="code-symbol">:</span><span class="code-keywords1">true</span> <span class="code-identifier">asMesh</span><span class="code-symbol">:</span><span class="code-keywords1">true</span></code>
<code> <span class="code-symbol">(</span><span class="code-keywords3">copy</span> <span class="code-identifier">obj</span> <span class="code-keywords4">name</span><span class="code-symbol">:#detached</span> <span class="code-keywords4">isHidden</span><span class="code-symbol">:</span><span class="code-keywords1">true</span><span class="code-symbol">).</span><span class="code-keywords3">mesh</span> <span class="code-symbol">=</span> <span class="code-identifier">newMesh</span></code>
<code> <span class="code-keywords3">delete</span> <span class="code-identifier">newMesh</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords1">fn</span> <span class="code-identifier">sliceObjXY</span> <span class="code-identifier">obj</span> <span class="code-identifier">intCount</span> <span class="code-symbol">=</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">objFaces</span> <span class="code-symbol">=</span> <span class="code-identifier">obj</span><span class="code-symbol">.</span><span class="code-identifier">faces</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">sliceWidthX</span> <span class="code-symbol">=</span> <span class="code-symbol">(</span><span class="code-identifier">obj</span><span class="code-symbol">.</span><span class="code-keywords1">max</span> <span class="code-symbol">-</span> <span class="code-identifier">obj</span><span class="code-symbol">.</span><span class="code-identifier">min</span><span class="code-symbol">).</span><span class="code-identifier">x</span><span class="code-symbol">/</span><span class="code-identifier">intCount</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">slicePosX</span> <span class="code-symbol">=</span> <span class="code-identifier">obj</span><span class="code-symbol">.</span><span class="code-identifier">min</span><span class="code-symbol">.</span><span class="code-identifier">x</span> <span class="code-symbol">-</span> <span class="code-identifier">obj</span><span class="code-symbol">.</span><span class="code-keywords3">pos</span><span class="code-symbol">.</span><span class="code-identifier">x</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">sliceWidthY</span> <span class="code-symbol">=</span> <span class="code-symbol">(</span><span class="code-identifier">obj</span><span class="code-symbol">.</span><span class="code-keywords1">max</span> <span class="code-symbol">-</span> <span class="code-identifier">obj</span><span class="code-symbol">.</span><span class="code-identifier">min</span><span class="code-symbol">).</span><span class="code-identifier">y</span><span class="code-symbol">/</span><span class="code-identifier">intCount</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">slicePosY</span> <span class="code-symbol">=</span> <span class="code-identifier">obj</span><span class="code-symbol">.</span><span class="code-identifier">min</span><span class="code-symbol">.</span><span class="code-identifier">y</span> <span class="code-symbol">-</span> <span class="code-identifier">obj</span><span class="code-symbol">.</span><span class="code-keywords3">pos</span><span class="code-symbol">.</span><span class="code-identifier">y</span></code>
<code></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">i</span> <span class="code-symbol">=</span> <span class="code-number">2</span> <span class="code-keywords1">to</span> <span class="code-identifier">intCount</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-identifier">meshSlice</span> <span class="code-identifier">obj</span> <span class="code-identifier">objFaces</span> <span class="code-symbol">[</span><span class="code-number">1</span><span class="code-symbol">,</span><span class="code-number">0</span><span class="code-symbol">,</span><span class="code-number">0</span><span class="code-symbol">]</span> <span class="code-symbol">(</span><span class="code-identifier">slicePosX</span> <span class="code-symbol">+=</span> <span class="code-identifier">sliceWidthX</span><span class="code-symbol">)</span> <span class="code-identifier">separate</span><span class="code-symbol">:</span><span class="code-keywords1">true</span></code>
<code> <span class="code-identifier">meshSlice</span> <span class="code-identifier">obj</span> <span class="code-identifier">objFaces</span> <span class="code-symbol">[</span><span class="code-number">0</span><span class="code-symbol">,</span><span class="code-number">1</span><span class="code-symbol">,</span><span class="code-number">0</span><span class="code-symbol">]</span> <span class="code-symbol">(</span><span class="code-identifier">slicePosY</span> <span class="code-symbol">+=</span> <span class="code-identifier">sliceWidthY</span><span class="code-symbol">)</span> <span class="code-identifier">separate</span><span class="code-symbol">:</span><span class="code-keywords1">true</span></code>
<code> <span class="code-symbol">)</span></code>
<code> <span class="code-identifier">obj</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords1">fn</span> <span class="code-identifier">sliceObjChunks</span> <span class="code-identifier">obj</span> <span class="code-identifier">intStep1</span> <span class="code-identifier">intStep2</span> <span class="code-identifier">intStep3</span> <span class="code-symbol">=</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">if</span> <span class="code-keywords3">queryBox</span> <span class="code-symbol">(</span><span class="code-string">"This operation will reset undo buffer.\nAre you sure you want to continue?"</span><span class="code-symbol">)</span> <span class="code-identifier">title</span><span class="code-symbol">:</span><span class="code-string">"Warning"</span></code>
<code> <span class="code-keywords1">do</span> <span class="code-keywords1">with</span> <span class="code-keywords1">redraw</span> <span class="code-keywords1">off</span><span class="code-symbol">,</span> <span class="code-keywords1">undo</span> <span class="code-keywords1">off</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords3">gc</span><span class="code-symbol">()</span></code>
<code> <span class="code-keywords3">clearSelection</span><span class="code-symbol">()</span></code>
<code> <span class="code-keywords3">statusPanel</span><span class="code-symbol">.</span><span class="code-keywords1">visible</span> <span class="code-symbol">=</span> <span class="code-keywords1">false</span></code>
<code> <span class="code-keywords3">setCommandPanelTaskMode</span> <span class="code-identifier">mode</span><span class="code-symbol">:#</span><span class="code-identifier">create</span></code>
<code></code>
<code> <span class="code-keywords1">if</span> <span class="code-keywords2">NOT</span> <span class="code-keywords3">isKindOf</span> <span class="code-identifier">obj</span> <span class="code-keywords4">Editable_mesh</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-keywords3">convertToMesh</span> <span class="code-identifier">obj</span></code>
<code></code>
<code> <span class="code-identifier">obj</span><span class="code-symbol">.</span><span class="code-keywords4">name</span> <span class="code-symbol">=</span> <span class="code-symbol">#detached</span></code>
<code> <span class="code-keywords3">hide</span> <span class="code-identifier">obj</span></code>
<code></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">intStep1_2</span> <span class="code-symbol">=</span> <span class="code-identifier">intStep1</span><span class="code-symbol">^</span><span class="code-number">2</span><span class="code-symbol">,</span> <span class="code-identifier">intStep2_2</span> <span class="code-symbol">=</span> <span class="code-identifier">intStep2</span><span class="code-symbol">^</span><span class="code-number">2</span><span class="code-symbol">,</span> <span class="code-identifier">intStep3_2</span> <span class="code-symbol">=</span> <span class="code-identifier">intStep3</span><span class="code-symbol">^</span><span class="code-number">2</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">progressStep1</span> <span class="code-symbol">=</span> <span class="code-number">100</span><span class="code-symbol">/</span><span class="code-identifier">intStep1_2</span><span class="code-symbol">,</span> <span class="code-identifier">progressStep2</span> <span class="code-symbol">=</span> <span class="code-number">100</span><span class="code-symbol">/</span><span class="code-identifier">intStep2_2</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">detachedObjs</span> <span class="code-symbol">=</span> <span class="code-symbol">#()</span> <span class="code-symbol">;</span> <span class="code-identifier">detachedObjs</span><span class="code-symbol">[</span><span class="code-identifier">intStep1_2</span><span class="code-symbol">]</span> <span class="code-symbol">=</span> <span class="code-keywords1">undefined</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">explodedArr</span> <span class="code-symbol">=</span> <span class="code-symbol">#()</span> <span class="code-symbol">;</span> <span class="code-identifier">explodedArr</span><span class="code-symbol">[</span><span class="code-identifier">intStep2_2</span><span class="code-symbol">]</span> <span class="code-symbol">=</span> <span class="code-keywords1">undefined</span></code>
<code></code>
<code> <span class="code-identifier">explodeMesh</span> <span class="code-symbol">(</span><span class="code-identifier">sliceObjXY</span> <span class="code-identifier">obj</span> <span class="code-identifier">intStep1</span><span class="code-symbol">)</span> <span class="code-identifier">intStep1_2</span> <span class="code-symbol">&</span><span class="code-identifier">detachedObjs</span></code>
<code></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">each</span> <span class="code-keywords1">in</span> <span class="code-identifier">detachedObjs</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-identifier">pbStep2</span><span class="code-symbol">.</span><span class="code-keywords3">value</span> <span class="code-symbol">=</span> <span class="code-number">0</span></code>
<code> <span class="code-identifier">explodeMesh</span> <span class="code-symbol">(</span><span class="code-identifier">sliceObjXY</span> <span class="code-identifier">each</span> <span class="code-identifier">intStep2</span><span class="code-symbol">)</span> <span class="code-identifier">intStep2_2</span> <span class="code-symbol">&</span><span class="code-identifier">explodedArr</span></code>
<code></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">chunk</span> <span class="code-keywords1">in</span> <span class="code-identifier">explodedArr</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-identifier">explodeMeshNoCollect</span> <span class="code-symbol">(</span><span class="code-identifier">sliceObjXY</span> <span class="code-identifier">chunk</span> <span class="code-identifier">intStep3</span><span class="code-symbol">)</span> <span class="code-identifier">intStep3_2</span></code>
<code> <span class="code-identifier">pbStep2</span><span class="code-symbol">.</span><span class="code-keywords3">value</span> <span class="code-symbol">+=</span> <span class="code-identifier">progressStep2</span></code>
<code> <span class="code-symbol">)</span></code>
<code> <span class="code-identifier">each</span> <span class="code-symbol">=</span> <span class="code-keywords1">undefined</span></code>
<code> <span class="code-keywords1">if</span> <span class="code-keywords3">keyboard</span><span class="code-symbol">.</span><span class="code-identifier">escPressed</span> <span class="code-keywords1">do</span> <span class="code-keywords1">exit</span></code>
<code> <span class="code-identifier">pbStep1</span><span class="code-symbol">.</span><span class="code-keywords3">value</span> <span class="code-symbol">+=</span> <span class="code-identifier">progressStep1</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-identifier">detachedObjs</span> <span class="code-symbol">=</span> <span class="code-symbol">$</span><span class="code-identifier">detached</span><span class="code-symbol">*</span> <span class="code-keywords1">as</span> <span class="code-keywords4">array</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">objCount</span> <span class="code-symbol">=</span> <span class="code-number">0</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">formatStr</span> <span class="code-symbol">=</span> <span class="code-string">"."</span> <span class="code-symbol">+</span> <span class="code-symbol">((</span><span class="code-identifier">detachedObjs</span><span class="code-symbol">.</span><span class="code-keywords1">count</span> <span class="code-keywords1">as</span> <span class="code-keywords4">string</span><span class="code-symbol">).</span><span class="code-keywords1">count</span> <span class="code-keywords1">as</span> <span class="code-keywords4">string</span><span class="code-symbol">)</span> <span class="code-symbol">+</span> <span class="code-string">"i"</span></code>
<code> <span class="code-identifier">renameDetached</span> <span class="code-identifier">detachedObjs</span> <span class="code-identifier">formatStr</span> <span class="code-symbol">&</span><span class="code-identifier">objCount</span></code>
<code> <span class="code-keywords1">if</span> <span class="code-keywords2">NOT</span> <span class="code-identifier">chxHidden</span><span class="code-symbol">.</span><span class="code-keywords1">checked</span> <span class="code-keywords1">do</span> <span class="code-keywords3">unhide</span> <span class="code-identifier">detachedObjs</span></code>
<code></code>
<code> <span class="code-keywords3">statusPanel</span><span class="code-symbol">.</span><span class="code-keywords1">visible</span> <span class="code-symbol">=</span> <span class="code-keywords1">true</span></code>
<code> <span class="code-identifier">pbStep1</span><span class="code-symbol">.</span><span class="code-keywords3">value</span> <span class="code-symbol">=</span> <span class="code-identifier">pbStep2</span><span class="code-symbol">.</span><span class="code-keywords3">value</span> <span class="code-symbol">=</span> <span class="code-number">0</span></code>
<code> <span class="code-keywords3">completeRedraw</span><span class="code-symbol">()</span></code>
<code> <span class="code-symbol">)</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords1">on</span> <span class="code-identifier">sliceInChunks</span> <span class="code-keywords3">open</span> <span class="code-keywords1">do</span> <span class="code-identifier">updateCount</span><span class="code-symbol">()</span></code>
<code></code>
<code> <span class="code-keywords1">on</span> <span class="code-identifier">spnStep1</span> <span class="code-keywords1">changed</span> <span class="code-identifier">val</span> <span class="code-keywords1">do</span> <span class="code-identifier">updateCount</span><span class="code-symbol">()</span></code>
<code> <span class="code-keywords1">on</span> <span class="code-identifier">spnStep2</span> <span class="code-keywords1">changed</span> <span class="code-identifier">val</span> <span class="code-keywords1">do</span> <span class="code-identifier">updateCount</span><span class="code-symbol">()</span></code>
<code> <span class="code-keywords1">on</span> <span class="code-identifier">spnStep3</span> <span class="code-keywords1">changed</span> <span class="code-identifier">val</span> <span class="code-keywords1">do</span> <span class="code-identifier">updateCount</span><span class="code-symbol">()</span></code>
<code></code>
<code> <span class="code-keywords1">on</span> <span class="code-identifier">btnSlice</span> <span class="code-keywords1">pressed</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-identifier">st</span> <span class="code-symbol">=</span> <span class="code-keywords3">timeStamp</span><span class="code-symbol">()</span></code>
<code> <span class="code-identifier">sliceObjChunks</span> <span class="code-keywords1">selection</span><span class="code-symbol">[</span><span class="code-number">1</span><span class="code-symbol">]</span> <span class="code-identifier">spnStep1</span><span class="code-symbol">.</span><span class="code-keywords3">value</span> <span class="code-identifier">spnStep2</span><span class="code-symbol">.</span><span class="code-keywords3">value</span> <span class="code-identifier">spnStep3</span><span class="code-symbol">.</span><span class="code-keywords3">value</span></code>
<code> <span class="code-keywords3">format</span> <span class="code-string">"Time: % sec.\n"</span> <span class="code-symbol">((</span><span class="code-keywords3">timeStamp</span><span class="code-symbol">()</span> <span class="code-symbol">-</span> <span class="code-identifier">st</span><span class="code-symbol">)/</span><span class="code-number">1000</span><span class="code-symbol">.)</span><span class="code-space"> </code>
<code> </span><span class="code-symbol">)</span> </code>
<code><span class="code-symbol">)</span></code>
<code><span class="code-keywords3">createDialog</span> <span class="code-identifier">sliceInChunks</span></code>
</pre><p>USAGE: Select an object that you want to slice, enter numbers that when multiplied together give the number of segments in X as well as Y direction and press the button. If you want to stop execution of the script, press and hold ESC key (it needs to be pressed when the blue bar reaches end). If you don't want the resulting meshes to be hidden, uncheck the checkbox.</p><div style="margin-right: 1em; text-align: center; border:none;"><a name="Slicer" imageanchor="1"><img alt="Slicer UI" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2TdgTQDoAD5EL23by9PyNUqCq9daKIDWTcsh5j-mXT8AhHVLda3NOdIH533EqBhQC-Z14KLiYEfiHuL-ws3ilT0maLEehpYwULIK6fPyh74xkzijlNpon4iopWSHJmRsDEtAm1NF4tuo/s1600/slicer.png" title="Slicer UI" /></a></div><br />
<p>DISCLAIMER: All scripts and snippets are provided as is under <a href="http://creativecommons.org/publicdomain/zero/1.0/">Creative Commons Zero (public domain, no restrictions) license</a>. The author and this blog cannot be held liable for any loss caused as a result of inaccuracy or error within these web pages. Use at your own risk.</p>Swordslayerhttp://www.blogger.com/profile/09124250713006663760noreply@blogger.com0tag:blogger.com,1999:blog-4212150079314071223.post-61866397286160135532011-06-09T17:54:00.003+02:002012-11-19T12:16:52.317+01:00Random UVW Map Gizmo Shift<p>Recently I've been asked by a co-worker to write a very simple script to randomly shift UVW Map gizmo of selected objects by an amount in a given range. And that's what it does. I'm open to any suggestion as to how to increase its usefulness, though.</p><a name='more'></a><pre class="notranslate" style="height: 400px;"><code><span class="code-keywords1">try</span> <span class="code-keywords3">destroyDialog</span> <span class="code-identifier">randomizeUVWdialog</span> <span class="code-keywords1">catch</span><span class="code-symbol">()</span></code>
<code><span class="code-keywords5">rollout</span> <span class="code-identifier">randomizeUVWdialog</span> <span class="code-string">"Randomize UVW"</span> <span class="code-keywords3">height</span><span class="code-symbol">:</span><span class="code-number">155</span> <span class="code-keywords3">width</span><span class="code-symbol">:</span><span class="code-number">175</span></code>
<code><span class="code-symbol">(</span></code>
<code> <span class="code-keywords5">label</span> <span class="code-identifier">lblVectorX</span> <span class="code-string">"Range X:"</span> <span class="code-keywords3">pos</span><span class="code-symbol">:[</span><span class="code-number">15</span><span class="code-symbol">,</span><span class="code-number">7</span><span class="code-symbol">]</span></code>
<code> <span class="code-keywords5">label</span> <span class="code-identifier">lblVectorY</span> <span class="code-string">"Range Y:"</span> <span class="code-keywords3">pos</span><span class="code-symbol">:[</span><span class="code-number">15</span><span class="code-symbol">,</span><span class="code-number">25</span><span class="code-symbol">]</span></code>
<code> <span class="code-keywords5">label</span> <span class="code-identifier">lblVectorZ</span> <span class="code-string">"Range Z:"</span> <span class="code-keywords3">pos</span><span class="code-symbol">:[</span><span class="code-number">15</span><span class="code-symbol">,</span><span class="code-number">43</span><span class="code-symbol">]</span></code>
<code></code>
<code> <span class="code-keywords5">spinner</span> <span class="code-identifier">spnRangeX</span> <span class="code-string">"\xB1"</span> <span class="code-keywords3">width</span><span class="code-symbol">:</span><span class="code-number">65</span> <span class="code-keywords3">range</span><span class="code-symbol">:[-</span><span class="code-number">1e9</span><span class="code-symbol">,</span><span class="code-number">1e9</span><span class="code-symbol">,</span><span class="code-number">0</span><span class="code-symbol">.]</span> <span class="code-keywords3">scale</span><span class="code-symbol">:</span><span class="code-number">1</span> <span class="code-keywords3">pos</span><span class="code-symbol">:[</span><span class="code-number">100</span><span class="code-symbol">,</span><span class="code-number">7</span><span class="code-symbol">]</span></code>
<code> <span class="code-keywords5">spinner</span> <span class="code-identifier">spnRangeY</span> <span class="code-string">"\xB1"</span> <span class="code-keywords3">width</span><span class="code-symbol">:</span><span class="code-number">65</span> <span class="code-keywords3">range</span><span class="code-symbol">:[-</span><span class="code-number">1e9</span><span class="code-symbol">,</span><span class="code-number">1e9</span><span class="code-symbol">,</span><span class="code-number">0</span><span class="code-symbol">.]</span> <span class="code-keywords3">scale</span><span class="code-symbol">:</span><span class="code-number">1</span> <span class="code-keywords3">pos</span><span class="code-symbol">:[</span><span class="code-number">100</span><span class="code-symbol">,</span><span class="code-number">25</span><span class="code-symbol">]</span></code>
<code> <span class="code-keywords5">spinner</span> <span class="code-identifier">spnRangeZ</span> <span class="code-string">"\xB1"</span> <span class="code-keywords3">width</span><span class="code-symbol">:</span><span class="code-number">65</span> <span class="code-keywords3">range</span><span class="code-symbol">:[-</span><span class="code-number">1e9</span><span class="code-symbol">,</span><span class="code-number">1e9</span><span class="code-symbol">,</span><span class="code-number">0</span><span class="code-symbol">.]</span> <span class="code-keywords3">scale</span><span class="code-symbol">:</span><span class="code-number">1</span> <span class="code-keywords3">pos</span><span class="code-symbol">:[</span><span class="code-number">100</span><span class="code-symbol">,</span><span class="code-number">43</span><span class="code-symbol">]</span></code>
<code></code>
<code> <span class="code-keywords5">checkBox</span> <span class="code-identifier">chxLinkSpinners</span> <span class="code-string">"Use X Range For All"</span> <span class="code-keywords3">align</span><span class="code-symbol">:#</span><span class="code-identifier">center</span> <span class="code-keywords3">offset</span><span class="code-symbol">:[</span><span class="code-number">0</span><span class="code-symbol">,</span><span class="code-number">5</span><span class="code-symbol">]</span></code>
<code> <span class="code-keywords5">radioButtons</span> <span class="code-identifier">rbCoords</span> <span class="code-identifier">labels</span><span class="code-symbol">:#(</span><span class="code-string">"World"</span><span class="code-symbol">,</span> <span class="code-string">"Local"</span><span class="code-symbol">)</span> <span class="code-keywords3">offset</span><span class="code-symbol">:[</span><span class="code-number">0</span><span class="code-symbol">,</span><span class="code-number">7</span><span class="code-symbol">]</span></code>
<code></code>
<code> <span class="code-keywords5">button</span> <span class="code-identifier">btnRandomize</span> <span class="code-string">"RANDOMIZE"</span> <span class="code-keywords3">offset</span><span class="code-symbol">:[</span><span class="code-number">0</span><span class="code-symbol">,</span><span class="code-number">7</span><span class="code-symbol">]</span> <span class="code-keywords3">width</span><span class="code-symbol">:</span><span class="code-number">160</span> <span class="code-keywords3">height</span><span class="code-symbol">:</span><span class="code-number">25</span></code>
<code></code>
<code> <span class="code-keywords1">mapped</span> <span class="code-keywords1">fn</span> <span class="code-identifier">randomizeUvw</span> <span class="code-identifier">obj</span> <span class="code-keywords3">range</span> <span class="code-identifier">coord</span> <span class="code-symbol">=</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">howManyModifiers</span> <span class="code-symbol">=</span> <span class="code-identifier">obj</span><span class="code-symbol">.</span><span class="code-identifier">modifiers</span><span class="code-symbol">.</span><span class="code-keywords1">count</span></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">m</span> <span class="code-symbol">=</span> <span class="code-identifier">howManyModifiers</span> <span class="code-keywords1">to</span> <span class="code-number">1</span> <span class="code-keywords1">by</span> <span class="code-symbol">-</span><span class="code-number">1</span></code>
<code> <span class="code-keywords1">where</span> <span class="code-keywords3">isKindOf</span> <span class="code-symbol">(</span><span class="code-keywords1">local</span> <span class="code-identifier">objMod</span> <span class="code-symbol">=</span> <span class="code-identifier">obj</span><span class="code-symbol">.</span><span class="code-identifier">modifiers</span><span class="code-symbol">[</span><span class="code-identifier">m</span><span class="code-symbol">])</span> <span class="code-keywords4">Uvwmap</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-keywords1">if</span> <span class="code-identifier">coord</span> <span class="code-keywords1">then</span> <span class="code-keywords1">exit</span> <span class="code-keywords1">with</span> <span class="code-identifier">objMod</span><span class="code-symbol">.</span><span class="code-identifier">gizmo</span><span class="code-symbol">.</span><span class="code-keywords3">pos</span> <span class="code-symbol">+=</span> <span class="code-symbol">[</span><span class="code-keywords3">random</span> <span class="code-symbol">-</span><span class="code-keywords3">range</span><span class="code-symbol">.</span><span class="code-identifier">x</span> <span class="code-keywords3">range</span><span class="code-symbol">.</span><span class="code-identifier">x</span><span class="code-symbol">,</span><span class="code-keywords3">random</span> <span class="code-symbol">-</span><span class="code-keywords3">range</span><span class="code-symbol">.</span><span class="code-identifier">y</span> <span class="code-keywords3">range</span><span class="code-symbol">.</span><span class="code-identifier">y</span><span class="code-symbol">,</span><span class="code-keywords3">random</span> <span class="code-symbol">-</span><span class="code-keywords3">range</span><span class="code-symbol">.</span><span class="code-identifier">z</span> <span class="code-keywords3">range</span><span class="code-symbol">.</span><span class="code-identifier">z</span><span class="code-symbol">]/</span><span class="code-identifier">obj</span><span class="code-symbol">.</span><span class="code-keywords3">scale</span></code>
<code> <span class="code-keywords1">else</span> <span class="code-keywords1">exit</span> <span class="code-keywords1">with</span> <span class="code-identifier">objMod</span><span class="code-symbol">.</span><span class="code-identifier">gizmo</span><span class="code-symbol">.</span><span class="code-keywords3">pos</span> <span class="code-symbol">=</span> <span class="code-symbol">((</span><span class="code-identifier">objMod</span><span class="code-symbol">.</span><span class="code-identifier">gizmo</span><span class="code-symbol">.</span><span class="code-keywords3">pos</span> <span class="code-symbol">*</span> <span class="code-identifier">obj</span><span class="code-symbol">.</span><span class="code-keywords3">transform</span><span class="code-symbol">)</span> <span class="code-symbol">+</span> <span class="code-symbol">[</span><span class="code-keywords3">random</span> <span class="code-symbol">-</span><span class="code-keywords3">range</span><span class="code-symbol">.</span><span class="code-identifier">x</span> <span class="code-keywords3">range</span><span class="code-symbol">.</span><span class="code-identifier">x</span><span class="code-symbol">,</span><span class="code-keywords3">random</span> <span class="code-symbol">-</span><span class="code-keywords3">range</span><span class="code-symbol">.</span><span class="code-identifier">y</span> <span class="code-keywords3">range</span><span class="code-symbol">.</span><span class="code-identifier">y</span><span class="code-symbol">,</span><span class="code-keywords3">random</span> <span class="code-symbol">-</span><span class="code-keywords3">range</span><span class="code-symbol">.</span><span class="code-identifier">z</span> <span class="code-keywords3">range</span><span class="code-symbol">.</span><span class="code-identifier">z</span><span class="code-symbol">])</span> <span class="code-symbol">*</span> <span class="code-keywords3">inverse</span> <span class="code-identifier">obj</span><span class="code-symbol">.</span><span class="code-keywords3">transform</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords1">on</span> <span class="code-identifier">spnRangeX</span> <span class="code-keywords1">changed</span> <span class="code-identifier">val</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-keywords1">if</span> <span class="code-identifier">chxLinkSpinners</span><span class="code-symbol">.</span><span class="code-keywords1">checked</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">#(</span><span class="code-identifier">spnRangeY</span><span class="code-symbol">,</span> <span class="code-identifier">spnRangeZ</span><span class="code-symbol">).</span><span class="code-keywords3">value</span> <span class="code-symbol">=</span> <span class="code-identifier">val</span></code>
<code></code>
<code> <span class="code-keywords1">on</span> <span class="code-identifier">chxLinkSpinners</span> <span class="code-keywords1">changed</span> <span class="code-identifier">state</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-symbol">#(</span><span class="code-identifier">spnRangeY</span><span class="code-symbol">,</span> <span class="code-identifier">spnRangeZ</span><span class="code-symbol">).</span><span class="code-keywords1">enabled</span> <span class="code-symbol">=</span> <span class="code-keywords2">NOT</span> <span class="code-identifier">state</span></code>
<code> <span class="code-keywords1">if</span> <span class="code-identifier">state</span> <span class="code-keywords1">do</span> <span class="code-symbol">#(</span><span class="code-identifier">spnRangeY</span><span class="code-symbol">,</span> <span class="code-identifier">spnRangeZ</span><span class="code-symbol">).</span><span class="code-keywords3">value</span> <span class="code-symbol">=</span> <span class="code-identifier">spnRangeX</span><span class="code-symbol">.</span><span class="code-keywords3">value</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords1">on</span> <span class="code-identifier">btnRandomize</span> <span class="code-keywords1">pressed</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">if</span> <span class="code-keywords1">selection</span><span class="code-symbol">.</span><span class="code-keywords1">count</span> <span class="code-symbol">==</span> <span class="code-number">0</span> <span class="code-keywords1">then</span></code>
<code> <span class="code-keywords3">messageBox</span> <span class="code-string">"Nothing selected!"</span> <span class="code-identifier">title</span><span class="code-symbol">:</span><span class="code-string">"Error"</span></code>
<code> <span class="code-keywords1">else</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords3">setCommandPanelTaskMode</span> <span class="code-identifier">mode</span><span class="code-symbol">:#</span><span class="code-identifier">modify</span></code>
<code> <span class="code-keywords1">with</span> <span class="code-keywords1">undo</span> <span class="code-keywords5">label</span><span class="code-symbol">:</span><span class="code-string">"Randomize UVW"</span> <span class="code-keywords1">on</span> <span class="code-identifier">randomizeUvw</span> <span class="code-keywords1">selection</span> <span class="code-symbol">[</span><span class="code-identifier">spnRangeX</span><span class="code-symbol">.</span><span class="code-keywords3">value</span><span class="code-symbol">,</span><span class="code-identifier">spnRangeY</span><span class="code-symbol">.</span><span class="code-keywords3">value</span><span class="code-symbol">,</span><span class="code-identifier">spnRangeZ</span><span class="code-symbol">.</span><span class="code-keywords3">value</span><span class="code-symbol">]</span> <span class="code-symbol">(</span><span class="code-identifier">rbCoords</span><span class="code-symbol">.</span><span class="code-identifier">state</span> <span class="code-symbol">==</span> <span class="code-number">2</span><span class="code-symbol">)</span></code>
<code> <span class="code-symbol">)</span></code>
<code> <span class="code-symbol">)</span></code>
<code><span class="code-symbol">)</span></code>
<code><span class="code-keywords3">createDialog</span> <span class="code-identifier">randomizeUVWdialog</span></code>
</pre><p>USAGE: Select some objects with UVW Map modifier applied, enter maximum XYZ values in the range input fields and press Randomize. You can choose whether you want the shift to happen in the world coordinate system or local. The units will be always world units, independent on the scale of the object.</p><div style="margin-right: 1em; text-align: center; border:none;"><a name="Randomize UVW" imageanchor="1"><img alt="Randomize UVW UI" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9Q2-SxN0vKTdIkvnjLwIIpGLNXGj49IMsC_-G1ML5mBqlyU0SckdjcF_IGyIdchc8UsGmgQugkuHn4RyV-3if3uVNxK66quOrHTHh5dIEI5O4Ci6fxfzYlPJ1aaQNXRpz6nT9u8J3ets/s1600/randomize.png" title="Randomize UVW UI" /></a></div><p></ br><br />
DISCLAIMER: All scripts and snippets are provided as is under <a href="http://creativecommons.org/publicdomain/zero/1.0/">Creative Commons Zero (public domain, no restrictions) license</a>. The author and this blog cannot be held liable for any loss caused as a result of inaccuracy or error within these web pages. Use at your own risk.</p>Swordslayerhttp://www.blogger.com/profile/09124250713006663760noreply@blogger.com2tag:blogger.com,1999:blog-4212150079314071223.post-37658679003265560782011-06-09T16:52:00.000+02:002013-01-13T16:08:48.852+01:00Spline - Connect Vertices<p>As the standard way of connecting vertices in a spline has always been a personal pet peeve of mine I've made this small macroscript and assigned it to a keyboard shortcut. Before using that I'd occasionally stumble upon a case where Create Line method would ask me if wanted to weld the vertices and whether I picked Yes or No the new line wouldn't be created. This as well as some snapping issues made me write the script. So much for the background, I hope it will be useful for someone else as well.</p><a name='more'></a><pre class="notranslate"><code><span class="code-keywords5">macroScript</span> <span class="code-identifier">connectSplineVerts</span></code>
<code> <span class="code-identifier">category</span><span class="code-symbol">:</span> <span class="code-string">"Advanced"</span></code>
<code> <span class="code-identifier">buttonText</span><span class="code-symbol">:</span> <span class="code-string">"Connect Verts"</span></code>
<code> <span class="code-identifier">toolTip</span><span class="code-symbol">:</span> <span class="code-string">"Connect Spline Vertices"</span></code>
<code><span class="code-comment">-- author: Vojtech Cada</span></code>
<code><span class="code-comment">-- email: <a href="mailto:vojta@krypton.cz">vojta@krypton.cz</a></span></code>
<code><span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">if</span> <span class="code-keywords1">selection</span><span class="code-symbol">.</span><span class="code-keywords1">count</span> <span class="code-symbol">==</span> <span class="code-number">1</span> <span class="code-keywords2">AND</span> <span class="code-keywords3">isKindOf</span> <span class="code-symbol">(</span><span class="code-keywords1">local</span> <span class="code-identifier">obj</span> <span class="code-symbol">=</span> <span class="code-keywords1">selection</span><span class="code-symbol">[</span><span class="code-number">1</span><span class="code-symbol">])</span> <span class="code-keywords4">Shape</span> <span class="code-keywords1">then</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">splineCount</span> <span class="code-symbol">=</span> <span class="code-keywords3">numSplines</span> <span class="code-identifier">obj</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">knotCount</span> <span class="code-symbol">=</span> <span class="code-number">0</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">knotPositons</span> <span class="code-symbol">=</span> <span class="code-symbol">#()</span></code>
<code></code>
<code> <span class="code-keywords1">fn</span> <span class="code-identifier">drawLine2Points</span> <span class="code-identifier">spline</span> <span class="code-identifier">point1</span> <span class="code-keywords4">point2</span> <span class="code-symbol">=</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">index</span> <span class="code-symbol">=</span> <span class="code-keywords3">addNewSpline</span> <span class="code-identifier">spline</span></code>
<code> <span class="code-keywords3">addKnot</span> <span class="code-identifier">spline</span> <span class="code-identifier">index</span> <span class="code-symbol">#</span><span class="code-identifier">corner</span> <span class="code-symbol">#</span><span class="code-keywords4">line</span> <span class="code-identifier">point1</span></code>
<code> <span class="code-keywords3">addKnot</span> <span class="code-identifier">spline</span> <span class="code-identifier">index</span> <span class="code-symbol">#</span><span class="code-identifier">corner</span> <span class="code-symbol">#</span><span class="code-keywords4">line</span> <span class="code-keywords4">point2</span></code>
<code> <span class="code-keywords3">updateShape</span> <span class="code-identifier">spline</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">spline</span> <span class="code-symbol">=</span> <span class="code-number">1</span> <span class="code-keywords1">to</span> <span class="code-identifier">splineCount</span></code>
<code> <span class="code-keywords1">where</span> <span class="code-symbol">(</span><span class="code-keywords1">local</span> <span class="code-identifier">selectedKnots</span> <span class="code-symbol">=</span> <span class="code-keywords3">getKnotSelection</span> <span class="code-identifier">obj</span> <span class="code-identifier">spline</span><span class="code-symbol">)</span> <span class="code-symbol">!=</span> <span class="code-symbol">#()</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords3">join</span> <span class="code-identifier">knotPositons</span> <span class="code-symbol">(</span><span class="code-keywords1">for</span> <span class="code-identifier">knot</span> <span class="code-keywords1">in</span> <span class="code-identifier">selectedKnots</span> <span class="code-keywords1">collect</span> <span class="code-keywords3">getKnotPoint</span> <span class="code-identifier">obj</span> <span class="code-identifier">spline</span> <span class="code-identifier">knot</span><span class="code-symbol">)</span></code>
<code> <span class="code-keywords1">if</span> <span class="code-symbol">(</span><span class="code-identifier">knotCount</span> <span class="code-symbol">+=</span> <span class="code-identifier">selectedKnots</span><span class="code-symbol">.</span><span class="code-keywords1">count</span><span class="code-symbol">)</span> <span class="code-symbol">></span> <span class="code-number">2</span> <span class="code-keywords1">do</span> <span class="code-keywords1">exit</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords1">if</span> <span class="code-identifier">knotCount</span> <span class="code-symbol">!=</span> <span class="code-number">2</span> <span class="code-keywords1">then</span></code>
<code> <span class="code-keywords3">messageBox</span> <span class="code-string">"Exactly 2 vertices have to be selected."</span></code>
<code> <span class="code-keywords1">else</span> <span class="code-identifier">drawLine2Points</span> <span class="code-identifier">obj</span> <span class="code-identifier">knotPositons</span><span class="code-symbol">[</span><span class="code-number">1</span><span class="code-symbol">]</span> <span class="code-identifier">knotPositons</span><span class="code-symbol">[</span><span class="code-number">2</span><span class="code-symbol">]</span></code>
<code> <span class="code-symbol">)</span></code>
<code> <span class="code-keywords1">else</span> <span class="code-keywords3">messageBox</span> <span class="code-string">"No spline selected!"</span></code>
<code><span class="code-symbol">)</span></code>
</pre>
<p>USAGE: Run the script and find it in the Advanced category in the Customize UI dialog. assign a shortcut to it, put it to quadmenu or toolbar, do whatever you may want to with it. Select two spline vertices and fire it up.</p>
<p>UPDATE: a version supporting multiple vertices is now available at ScriptSpot as <a href="http://www.scriptspot.com/3ds-max/scripts/connect-spline-vertices" title="ScriptSpot :: Connect Spline Vertices">Connect Spline Vertices</a>.</p>
<p>DISCLAIMER: All scripts and snippets are provided as is under <a href="http://creativecommons.org/publicdomain/zero/1.0/">Creative Commons Zero (public domain, no restrictions) license</a>. The author and this blog cannot be held liable for any loss caused as a result of inaccuracy or error within these web pages. Use at your own risk.</p>Swordslayerhttp://www.blogger.com/profile/09124250713006663760noreply@blogger.com0tag:blogger.com,1999:blog-4212150079314071223.post-22657764141751951572011-05-21T16:04:00.000+02:002012-11-19T12:17:35.491+01:00Project Euler: Problem 14Yet another day and yet another problem to discuss. Today it is <a href="http://projecteuler.net/index.php?section=problems&id=14" title="Find the longest sequence using a starting number under one million">problem No. 14</a>:
<blockquote><p>The following iterative sequence is defined for the set of positive integers:</p>
<p> n → n/2 (n is even)<br />
n → 3n + 1 (n is odd)</p>
<p>Using the rule above and starting with 13, we generate the following sequence:</p>
<p> 13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1</p>
<p>It can be seen that this sequence (starting at 13 and finishing at 1) contains 10 terms. Although it has not been proved yet (Collatz Problem), it is thought that all starting numbers finish at 1.</p>
<p>Which starting number, under one million, produces the longest chain?</p>
<p>NOTE: Once the chain starts the terms are allowed to go above one million.</p></blockquote>
<a name='more'></a><p>There are not many tweaks in this one. First of all we raise the heap size to 128 MB to avoid automatic garbage collection interrupting the execution almost instantly, then we go through the sequence, saving values less then one million to a predeclared array. If the number is even, we first look if there is a value for <code>nr/2</code> – if it is so, we just add one and return the lenght, if not, we go the whole way of finding the sequence. Well, almost, as in the <code>getLengthIter</code> function we save and search for previous results as well, adding them to the <code>count</code> so far if we find any. That's basically it.</p>
<pre class="notranslate" style="height: 400px;">
<code><span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">if</span> <span class="code-keywords3">heapSize</span> <span class="code-symbol"><</span> <span class="code-number">134217728L</span> <span class="code-keywords1">do</span> <span class="code-keywords3">heapSize</span> <span class="code-symbol">=</span> <span class="code-number">134217728L</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">arr</span> <span class="code-symbol">=</span> <span class="code-symbol">#(</span><span class="code-number">1L</span><span class="code-symbol">)</span></code>
<code> <span class="code-identifier">arr</span><span class="code-symbol">[</span><span class="code-number">1000000</span><span class="code-symbol">]</span> <span class="code-symbol">=</span> <span class="code-keywords1">undefined</span></code>
<code></code>
<code> <span class="code-keywords1">fn</span> <span class="code-identifier">isEven</span> <span class="code-identifier">nr</span> <span class="code-symbol">=</span> <span class="code-keywords3">bit</span><span class="code-symbol">.</span><span class="code-keywords2">and</span> <span class="code-number">1L</span> <span class="code-identifier">nr</span> <span class="code-symbol">==</span> <span class="code-number">0</span></code>
<code></code>
<code> <span class="code-keywords1">fn</span> <span class="code-identifier">alg</span> <span class="code-identifier">nr</span> <span class="code-symbol">=</span> <span class="code-keywords1">if</span> <span class="code-identifier">isEven</span> <span class="code-identifier">nr</span> <span class="code-keywords1">then</span> <span class="code-identifier">nr</span><span class="code-symbol">/</span><span class="code-number">2</span> <span class="code-keywords1">else</span> <span class="code-number">3</span><span class="code-symbol">*</span><span class="code-identifier">nr</span> <span class="code-symbol">+</span> <span class="code-number">1</span></code>
<code></code>
<code> <span class="code-keywords1">fn</span> <span class="code-identifier">getLengthIter</span> <span class="code-identifier">nr</span> <span class="code-symbol">=</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-keywords1">count</span> <span class="code-symbol">=</span> <span class="code-number">1L</span></code>
<code></code>
<code> <span class="code-keywords1">while</span> <span class="code-identifier">nr</span> <span class="code-symbol">!=</span> <span class="code-number">1</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-identifier">nr</span> <span class="code-symbol">=</span> <span class="code-identifier">alg</span> <span class="code-identifier">nr</span></code>
<code> <span class="code-keywords1">if</span> <span class="code-identifier">nr</span> <span class="code-symbol"><</span> <span class="code-number">1000000</span> <span class="code-keywords2">AND</span> <span class="code-identifier">arr</span><span class="code-symbol">[</span><span class="code-identifier">nr</span><span class="code-symbol">]</span> <span class="code-symbol">!=</span> <span class="code-keywords1">undefined</span> <span class="code-keywords1">then</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">count</span> <span class="code-symbol">+=</span> <span class="code-identifier">arr</span><span class="code-symbol">[</span><span class="code-identifier">nr</span><span class="code-symbol">]</span></code>
<code> <span class="code-identifier">nr</span> <span class="code-symbol">=</span> <span class="code-number">1</span></code>
<code> <span class="code-symbol">)</span></code>
<code> <span class="code-keywords1">else</span> <span class="code-keywords1">count</span> <span class="code-symbol">+=</span> <span class="code-number">1</span></code>
<code> <span class="code-symbol">)</span></code>
<code> <span class="code-keywords1">count</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords1">fn</span> <span class="code-identifier">getLength</span> <span class="code-identifier">nr</span> <span class="code-symbol">=</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">if</span> <span class="code-identifier">arr</span><span class="code-symbol">[</span><span class="code-identifier">nr</span><span class="code-symbol">]</span> <span class="code-symbol">!=</span> <span class="code-keywords1">undefined</span> <span class="code-keywords1">then</span> <span class="code-identifier">arr</span><span class="code-symbol">[</span><span class="code-identifier">nr</span><span class="code-symbol">]</span></code>
<code> <span class="code-keywords1">else</span> <span class="code-keywords1">if</span> <span class="code-identifier">isEven</span> <span class="code-identifier">nr</span> <span class="code-keywords2">AND</span> <span class="code-identifier">arr</span><span class="code-symbol">[</span><span class="code-identifier">nr</span><span class="code-symbol">/</span><span class="code-number">2</span><span class="code-symbol">]</span> <span class="code-symbol">!=</span> <span class="code-keywords1">undefined</span> <span class="code-keywords1">then</span></code>
<code> <span class="code-identifier">arr</span><span class="code-symbol">[</span><span class="code-identifier">nr</span><span class="code-symbol">]</span> <span class="code-symbol">=</span> <span class="code-identifier">arr</span><span class="code-symbol">[</span><span class="code-identifier">nr</span><span class="code-symbol">/</span><span class="code-number">2</span><span class="code-symbol">]</span></code>
<code> <span class="code-keywords1">else</span> <span class="code-identifier">arr</span><span class="code-symbol">[</span><span class="code-identifier">nr</span><span class="code-symbol">]</span> <span class="code-symbol">=</span> <span class="code-identifier">getLengthIter</span> <span class="code-symbol">(</span><span class="code-identifier">alg</span> <span class="code-identifier">nr</span><span class="code-symbol">)</span> <span class="code-symbol">+</span> <span class="code-number">1</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">result</span><span class="code-symbol">,</span> <span class="code-identifier">seqLength</span> <span class="code-symbol">=</span> <span class="code-number">10L</span></code>
<code></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">i</span> <span class="code-symbol">=</span> <span class="code-number">2L</span> <span class="code-keywords1">to</span> <span class="code-number">999999L</span></code>
<code> <span class="code-keywords1">where</span> <span class="code-identifier">getLength</span> <span class="code-identifier">i</span> <span class="code-symbol">></span> <span class="code-identifier">seqLength</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-identifier">seqLength</span> <span class="code-symbol">=</span> <span class="code-identifier">getLength</span> <span class="code-identifier">i</span></code>
<code> <span class="code-identifier">result</span> <span class="code-symbol">=</span> <span class="code-identifier">i</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-identifier">result</span></code>
<code><span class="code-symbol">)</span></code>
</pre>
<p>Although it satisfies the 1-minute limit, it's quite slow and I'm not very happy about it. I'd really love to hear some suggestions of a different approach to make it faster and less memory hungry.</p>
<p>DISCLAIMER: All scripts and snippets are provided as is under <a href="http://creativecommons.org/publicdomain/zero/1.0/">Creative Commons Zero (public domain, no restrictions) license</a>. The author and this blog cannot be held liable for any loss caused as a result of inaccuracy or error within these web pages. Use at your own risk.</p>Swordslayerhttp://www.blogger.com/profile/09124250713006663760noreply@blogger.com3tag:blogger.com,1999:blog-4212150079314071223.post-65506115244767401692011-05-19T22:56:00.000+02:002012-11-19T12:17:46.580+01:00Project Euler: Problem 13Another day, another problem to solve, let's see what the <a href="http://projecteuler.net/index.php?section=problems&id=13" title="
Find the first ten digits of the sum of one-hundred 50-digit numbers.">problem No. 13</a> is about:
<blockquote><p>Work out the first ten digits of the sum of the following one-hundred 50-digit numbers.</p>
<p><code> 37107287533902102798797998220837590246510135740250</code><br />
<code> 46376937677490009712648124896970078050417018260538</code><br />
<code> 74324986199524741059474233309513058123726617309629</code><br />
<code> …[44 more numbers]…</code><br />
<code> 72107838435069186155435662884062257473692284509516</code><br />
<code> 20849603980134001723930671666823555245252804609722</code><br />
<code> 53503534226472524250874054075591789781264330331690</code></p></blockquote>
<a name='more'></a><p>Okay, this time the issue to overcome is dealing with such large numbers. Adding them then is easy, just the strategy need to be developed. I decided to stick with the usual way of adding numbers where you wrtie the numbers below each other and then add the corresponding numbers. If the result is bigger than 9, you add the leftover to the next row of numbers of higher order.</p>
<p>Using simple arrays this can be accomplished without complications, what we will do is that we'll parse all the number strings and create arrays of numbers from them. Then, adding corresponding numbers together we get our mid results and parse them again, and adding new arrays if they'd be bigger than 9 and only collecting single digits. When all these digits are collected, appending first ten to an empty string does the trick.</p>
<pre class="notranslate" style="height: 400px;">
<code><span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">fn</span> <span class="code-identifier">getNums</span> <span class="code-identifier">filePath</span> <span class="code-symbol">=</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">result</span> <span class="code-symbol">=</span> <span class="code-symbol">#()</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">file</span> <span class="code-symbol">=</span> <span class="code-keywords3">openFile</span> <span class="code-identifier">filePath</span></code>
<code></code>
<code> <span class="code-keywords1">while</span> <span class="code-keywords2">NOT</span> <span class="code-keywords3">EOF</span> <span class="code-identifier">file</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-keywords3">append</span> <span class="code-identifier">result</span> <span class="code-symbol">(</span><span class="code-keywords3">readLine</span> <span class="code-identifier">file</span><span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords3">close</span> <span class="code-identifier">file</span></code>
<code> <span class="code-identifier">result</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords1">fn</span> <span class="code-identifier">parseNum</span> <span class="code-identifier">str</span> <span class="code-symbol">=</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">charCount</span> <span class="code-symbol">=</span> <span class="code-identifier">str</span><span class="code-symbol">.</span><span class="code-keywords1">count</span></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">char</span> <span class="code-symbol">=</span> <span class="code-number">1</span> <span class="code-keywords1">to</span> <span class="code-identifier">charCount</span> <span class="code-keywords1">collect</span> <span class="code-identifier">str</span><span class="code-symbol">[</span><span class="code-identifier">char</span><span class="code-symbol">]</span> <span class="code-keywords1">as</span> <span class="code-keywords4">integer</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords1">fn</span> <span class="code-identifier">addNums</span> <span class="code-identifier">strArr</span> <span class="code-symbol">=</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">resultArr</span> <span class="code-symbol">=</span> <span class="code-symbol">#()</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">arr</span> <span class="code-symbol">=</span> <span class="code-keywords1">for</span> <span class="code-identifier">str</span> <span class="code-keywords1">in</span> <span class="code-identifier">strArr</span> <span class="code-keywords1">collect</span> <span class="code-identifier">parseNum</span> <span class="code-identifier">str</span></code>
<code></code>
<code> <span class="code-keywords1">while</span> <span class="code-identifier">arr</span><span class="code-symbol">.</span><span class="code-keywords1">count</span> <span class="code-symbol">></span> <span class="code-number">0</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">eachCount</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">sum</span> <span class="code-symbol">=</span> <span class="code-number">0</span></code>
<code></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">index</span> <span class="code-symbol">=</span> <span class="code-identifier">arr</span><span class="code-symbol">.</span><span class="code-keywords1">count</span> <span class="code-keywords1">to</span> <span class="code-number">1</span> <span class="code-keywords1">by</span> <span class="code-symbol">-</span><span class="code-number">1</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">each</span> <span class="code-symbol">=</span> <span class="code-identifier">arr</span><span class="code-symbol">[</span><span class="code-identifier">index</span><span class="code-symbol">]</span></code>
<code> <span class="code-keywords1">if</span> <span class="code-symbol">(</span><span class="code-identifier">eachCount</span> <span class="code-symbol">=</span> <span class="code-identifier">each</span><span class="code-symbol">.</span><span class="code-keywords1">count</span><span class="code-symbol">)</span> <span class="code-symbol">></span> <span class="code-number">0</span> <span class="code-keywords1">then</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-identifier">sum</span> <span class="code-symbol">+=</span> <span class="code-identifier">each</span><span class="code-symbol">[</span><span class="code-identifier">eachCount</span><span class="code-symbol">]</span></code>
<code> <span class="code-keywords3">deleteItem</span> <span class="code-identifier">each</span> <span class="code-identifier">eachCount</span></code>
<code> <span class="code-symbol">)</span></code>
<code> <span class="code-keywords1">else</span> <span class="code-keywords3">deleteItem</span> <span class="code-identifier">arr</span> <span class="code-identifier">index</span></code>
<code> <span class="code-symbol">)</span></code>
<code> <span class="code-keywords1">if</span> <span class="code-identifier">sum</span> <span class="code-symbol">>=</span> <span class="code-number">10</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">parsedSum</span> <span class="code-symbol">=</span> <span class="code-identifier">parseNum</span> <span class="code-symbol">(</span><span class="code-identifier">sum</span> <span class="code-keywords1">as</span> <span class="code-keywords4">string</span><span class="code-symbol">)</span></code>
<code> <span class="code-identifier">sum</span> <span class="code-symbol">=</span> <span class="code-identifier">parsedSum</span><span class="code-symbol">[</span><span class="code-identifier">parsedSum</span><span class="code-symbol">.</span><span class="code-keywords1">count</span><span class="code-symbol">]</span></code>
<code> <span class="code-keywords3">deleteItem</span> <span class="code-identifier">parsedSum</span> <span class="code-identifier">parsedSum</span><span class="code-symbol">.</span><span class="code-keywords1">count</span></code>
<code> <span class="code-keywords3">append</span> <span class="code-identifier">arr</span> <span class="code-identifier">parsedSum</span></code>
<code> <span class="code-symbol">)</span></code>
<code> <span class="code-keywords3">insertItem</span> <span class="code-identifier">sum</span> <span class="code-identifier">resultArr</span> <span class="code-number">1</span></code>
<code> <span class="code-symbol">)</span></code>
<code> <span class="code-keywords1">if</span> <span class="code-identifier">resultArr</span><span class="code-symbol">[</span><span class="code-number">1</span><span class="code-symbol">]</span> <span class="code-symbol">==</span> <span class="code-number">0</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-keywords3">deleteItem</span> <span class="code-identifier">resultArr</span> <span class="code-number">1</span></code>
<code></code>
<code> <span class="code-identifier">resultArr</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">res</span> <span class="code-symbol">=</span> <span class="code-identifier">addNums</span> <span class="code-symbol">(</span><span class="code-identifier">getNums</span> <span class="code-string">"Z:\Euler\prob13.txt"</span><span class="code-symbol">)</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">solution</span> <span class="code-symbol">=</span> <span class="code-string">""</span></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">i</span> <span class="code-symbol">=</span> <span class="code-number">1</span> <span class="code-keywords1">to</span> <span class="code-number">10</span> <span class="code-keywords1">do</span> <span class="code-keywords3">append</span> <span class="code-identifier">solution</span> <span class="code-symbol">(</span><span class="code-identifier">res</span><span class="code-symbol">[</span><span class="code-identifier">i</span><span class="code-symbol">]</span> <span class="code-keywords1">as</span> <span class="code-keywords4">string</span><span class="code-symbol">)</span></code>
<code> <span class="code-identifier">solution</span></code>
<code><span class="code-symbol">)</span></code>
</pre>
<p>Just one side note, if I'd do it again, I'd collect the digits in reverse order, makes iterating and adding higher order digits much easier and elegant.</p>
<p>DISCLAIMER: All scripts and snippets are provided as is under <a href="http://creativecommons.org/publicdomain/zero/1.0/">Creative Commons Zero (public domain, no restrictions) license</a>. The author and this blog cannot be held liable for any loss caused as a result of inaccuracy or error within these web pages. Use at your own risk.</p>Swordslayerhttp://www.blogger.com/profile/09124250713006663760noreply@blogger.com0tag:blogger.com,1999:blog-4212150079314071223.post-73413664808315780122011-05-17T16:59:00.002+02:002012-11-19T12:18:09.077+01:00Project Euler: Problem 12<p>A new day, new Project Euler challenge, who would guess that after problem No. 11 comes <a href="http://projecteuler.net/index.php?section=problems&id=12" title="What is the value of the first triangle number to have over five hundred divisors?">problem No. 12</a>:</p>
<blockquote>
<p>The sequence of triangle numbers is generated by adding the natural numbers. So the <code>7<sup>th</sup></code> triangle number would be <code>1 + 2 + 3 + 4 + 5 + 6 + 7 = 28</code>. The first ten terms would be:</p>
<div style="text-align: center;">
<code>1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...</code>
</div>
<p>Let us list the factors of the first seven triangle numbers:<br />
<code> 1: 1</code><br />
<code> 3: 1,3</code><br />
<code> 6: 1,2,3,6</code><br />
<code> 10: 1,2,5,10</code><br />
<code> 15: 1,3,5,15</code><br />
<code> 21: 1,3,7,21</code><br />
<code> 28: 1,2,4,7,14,28</code><br /></p>
<p>We can see that 28 is the first triangle number to have over five divisors.</p>
<p>What is the value of the first triangle number to have over five hundred divisors?</p></blockquote>
<a name='more'></a><p>So, we will need a function to count divisors of a number, that's for sure. If we look in detail on the <a href="http://en.wikipedia.org/wiki/Divisor_function#Properties" title="'Wikipedia :: Divisor Function Properties">method</a> to get a number of all the positive divisors of a value, we soon find out that it can be broken into getting the prime factors of a number and multiplying their powers increased by one. We've already done a similar thing with the <a href="http://creativescratchpad.blogspot.com/2011/05/project-euler-problem-5.html#primeFactorsPow" title="Project Euler: Problem 5 :: Getting prime factors of a number and their powers"><code>primeFactorsPow</code></a> function. This time there's no need to keep an array of the values as we only work with individual numbers. Also, as the powers are to be increased by one, the <code>pow</code> variable is initialized with a value of <code>1L</code> instead of <code>0L</code>:</p>
<pre class="notranslate"><code><span class="code-keywords1">fn</span> <span class="code-identifier">countDivisors</span> <span class="code-identifier">nr</span> <span class="code-keywords1">count</span><span class="code-symbol">:</span><span class="code-number">1</span> <span class="code-symbol">=</span></code>
<code><span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">if</span> <span class="code-identifier">isEven</span> <span class="code-identifier">nr</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-keywords3">pow</span> <span class="code-symbol">=</span> <span class="code-number">1</span><span class="code-identifier">L</span></code>
<code> <span class="code-keywords1">do</span> <span class="code-symbol">(</span><span class="code-identifier">nr</span> <span class="code-symbol">/=</span> <span class="code-number">2</span><span class="code-identifier">L</span><span class="code-symbol">;</span> <span class="code-keywords3">pow</span> <span class="code-symbol">+=</span> <span class="code-number">1</span><span class="code-symbol">)</span> <span class="code-keywords1">while</span> <span class="code-identifier">isEven</span> <span class="code-identifier">nr</span></code>
<code> <span class="code-keywords1">count</span> <span class="code-symbol">*=</span> <span class="code-keywords3">pow</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">rootN</span> <span class="code-symbol">=</span> <span class="code-identifier">nr</span><span class="code-symbol">^</span><span class="code-number">0</span><span class="code-symbol">.</span><span class="code-number">5</span></code>
<code></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">i</span> <span class="code-symbol">=</span> <span class="code-number">3</span> <span class="code-keywords1">to</span> <span class="code-identifier">rootN</span> <span class="code-keywords1">by</span> <span class="code-number">2</span></code>
<code> <span class="code-keywords1">where</span> <span class="code-keywords3">mod</span> <span class="code-identifier">nr</span> <span class="code-identifier">i</span> <span class="code-symbol">==</span> <span class="code-number">0</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-keywords3">pow</span> <span class="code-symbol">=</span> <span class="code-number">1</span><span class="code-identifier">L</span></code>
<code> <span class="code-keywords1">do</span> <span class="code-symbol">(</span><span class="code-identifier">nr</span> <span class="code-symbol">/=</span> <span class="code-identifier">i</span><span class="code-symbol">;</span> <span class="code-keywords3">pow</span> <span class="code-symbol">+=</span> <span class="code-number">1</span><span class="code-symbol">)</span> <span class="code-keywords1">while</span> <span class="code-keywords3">mod</span> <span class="code-identifier">nr</span> <span class="code-identifier">i</span> <span class="code-symbol">==</span> <span class="code-number">0</span></code>
<code> <span class="code-keywords1">count</span> <span class="code-symbol">*=</span> <span class="code-keywords3">pow</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords1">if</span> <span class="code-identifier">nr</span> <span class="code-symbol">></span> <span class="code-number">1</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-keywords1">count</span> <span class="code-symbol">*=</span> <span class="code-number">2</span></code>
<code></code>
<code> <span class="code-keywords1">count</span></code>
<code><span class="code-symbol">)</span></code>
</pre>
<p>But wait, do we really have to count the divisors for each and every number? Let's have a look at what we are dealing with, what are the properties of the <a href="http://en.wikipedia.org/wiki/Triangular_number">triangle numbers</a> that we could use? The infographic on the right says that <code>T<sub>n</sub></code> equals <code>(n × (n+1))/2</code>. The proof here is quite simple, when you take the triangle that represents the number <code>T<sub>n</sub></code>, mirror it and put them together, this is what you will get <code>(for n = 4)</code>:</p>
<div style="margin-right: 1em; text-align: center; border:none; ">
<a name="TriangleNumbers" imageanchor="1"><img alt="Triangle numbers" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRo6jG4v-ULL5u47u9-UAfPZ1S9Gm5FiuUa4LLkrITMlh4X1wJxgXDRZnQHwo3FNRLo14sJ3Khv56u0xpTnIokOo-DJhsfWsELR0_9c8WVQ3lVfXHYVXn1BtqbX1HhBnMuCAaaHQmZp20/s1600/triangle.png" title="Triangle numbers" /></a></div>
</p>As each element represents an addition of one (i.e. row of four elements equals four), the rectangle contains <code>n × (n+1)</code> elements, and as it is double the size we need, by dividing it by two, we get our result. So it's always a multiplication and we could use it to our advantage as <i><q cite="http://en.wikipedia.org/wiki/Divisor">the total number of positive divisors of <code>n</code> is a multiplicative function <code>d(n)</code>, e.g. <code>d(42) = 8 = 2 × 2 × 2 = d(2) × d(3) × d(7)</code></q></i>. The difference here is that we have <code>(n × (n+1))/2</code> and not just <code>n × (n+1)</code>. But there's always one of those values that's even, as they differ exactly by one, so we can just take the even one (once again using the <a href="http://creativescratchpad.blogspot.com/2011/05/project-euler-problem-2.html#isEven" title="Project Euler: Problem 2 :: Find the sum of the even-valued Fibonacci terms"><code>isEven</code></a> function) and divide it by two:</p>
<pre class="notranslate"><code><span class="code-keywords1">fn</span> <span class="code-identifier">countTriangleDivisors</span> <span class="code-identifier">nr</span> <span class="code-symbol">=</span></code>
<code><span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">if</span> <span class="code-identifier">isEven</span> <span class="code-identifier">nr</span> <span class="code-keywords1">then</span></code>
<code> <span class="code-symbol">(</span><span class="code-identifier">countDivisors</span> <span class="code-symbol">(</span><span class="code-identifier">nr</span><span class="code-symbol">/</span><span class="code-number">2</span><span class="code-symbol">))</span> <span class="code-symbol">*</span> <span class="code-symbol">(</span><span class="code-identifier">countDivisors</span> <span class="code-symbol">(</span><span class="code-identifier">nr</span><span class="code-symbol">+</span><span class="code-number">1</span><span class="code-symbol">))</span></code>
<code> <span class="code-keywords1">else</span> <span class="code-symbol">(</span><span class="code-identifier">countDivisors</span> <span class="code-identifier">nr</span><span class="code-symbol">)</span> <span class="code-symbol">*</span> <span class="code-symbol">(</span><span class="code-identifier">countDivisors</span> <span class="code-symbol">((</span><span class="code-identifier">nr</span><span class="code-symbol">+</span><span class="code-number">1</span><span class="code-symbol">)/</span><span class="code-number">2</span><span class="code-symbol">))</span></code>
<code><span class="code-symbol">)</span></code>
</pre>
</p>To wrap it all together in a nice package we only have to write the for loop (I've started with seven here as the biggest triangle number in the description was the seventh in order) and exit with <code>nthTriangle</code>:</p>
<pre class="notranslate" style="height: 400px;"><code><span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">inf</span> <span class="code-symbol">=</span> <span class="code-number">1</span><span class="code-symbol">.</span><span class="code-number">0</span><span class="code-symbol">/</span><span class="code-number">0</span><span class="code-symbol">.</span></code>
<code></code>
<code> <span class="code-keywords1">fn</span> <span class="code-identifier">isEven</span> <span class="code-identifier">nr</span> <span class="code-symbol">=</span> <span class="code-keywords3">bit</span><span class="code-symbol">.</span><span class="code-keywords2">and</span> <span class="code-number">1</span><span class="code-identifier">L</span> <span class="code-identifier">nr</span> <span class="code-symbol">==</span> <span class="code-number">0</span></code>
<code></code>
<code> <span class="code-keywords1">fn</span> <span class="code-identifier">countDivisors</span> <span class="code-identifier">nr</span> <span class="code-keywords1">count</span><span class="code-symbol">:</span><span class="code-number">1</span> <span class="code-symbol">=</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">if</span> <span class="code-identifier">isEven</span> <span class="code-identifier">nr</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-keywords3">pow</span> <span class="code-symbol">=</span> <span class="code-number">1</span><span class="code-identifier">L</span></code>
<code> <span class="code-keywords1">do</span> <span class="code-symbol">(</span><span class="code-identifier">nr</span> <span class="code-symbol">/=</span> <span class="code-number">2</span><span class="code-identifier">L</span><span class="code-symbol">;</span> <span class="code-keywords3">pow</span> <span class="code-symbol">+=</span> <span class="code-number">1</span><span class="code-symbol">)</span> <span class="code-keywords1">while</span> <span class="code-identifier">isEven</span> <span class="code-identifier">nr</span></code>
<code> <span class="code-keywords1">count</span> <span class="code-symbol">*=</span> <span class="code-keywords3">pow</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">rootN</span> <span class="code-symbol">=</span> <span class="code-identifier">nr</span><span class="code-symbol">^</span><span class="code-number">0</span><span class="code-symbol">.</span><span class="code-number">5</span></code>
<code></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">i</span> <span class="code-symbol">=</span> <span class="code-number">3</span> <span class="code-keywords1">to</span> <span class="code-identifier">rootN</span> <span class="code-keywords1">by</span> <span class="code-number">2</span></code>
<code> <span class="code-keywords1">where</span> <span class="code-keywords3">mod</span> <span class="code-identifier">nr</span> <span class="code-identifier">i</span> <span class="code-symbol">==</span> <span class="code-number">0</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-keywords3">pow</span> <span class="code-symbol">=</span> <span class="code-number">1</span><span class="code-identifier">L</span></code>
<code> <span class="code-keywords1">do</span> <span class="code-symbol">(</span><span class="code-identifier">nr</span> <span class="code-symbol">/=</span> <span class="code-identifier">i</span><span class="code-symbol">;</span> <span class="code-keywords3">pow</span> <span class="code-symbol">+=</span> <span class="code-number">1</span><span class="code-symbol">)</span> <span class="code-keywords1">while</span> <span class="code-keywords3">mod</span> <span class="code-identifier">nr</span> <span class="code-identifier">i</span> <span class="code-symbol">==</span> <span class="code-number">0</span></code>
<code> <span class="code-keywords1">count</span> <span class="code-symbol">*=</span> <span class="code-keywords3">pow</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords1">if</span> <span class="code-identifier">nr</span> <span class="code-symbol">></span> <span class="code-number">1</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-keywords1">count</span> <span class="code-symbol">*=</span> <span class="code-number">2</span></code>
<code></code>
<code> <span class="code-keywords1">count</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords1">fn</span> <span class="code-identifier">countTriangleDivisors</span> <span class="code-identifier">nr</span> <span class="code-symbol">=</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">if</span> <span class="code-identifier">isEven</span> <span class="code-identifier">nr</span> <span class="code-keywords1">then</span></code>
<code> <span class="code-symbol">(</span><span class="code-identifier">countDivisors</span> <span class="code-symbol">(</span><span class="code-identifier">nr</span><span class="code-symbol">/</span><span class="code-number">2</span><span class="code-symbol">))</span> <span class="code-symbol">*</span> <span class="code-symbol">(</span><span class="code-identifier">countDivisors</span> <span class="code-symbol">(</span><span class="code-identifier">nr</span><span class="code-symbol">+</span><span class="code-number">1</span><span class="code-symbol">))</span></code>
<code> <span class="code-keywords1">else</span> <span class="code-symbol">(</span><span class="code-identifier">countDivisors</span> <span class="code-identifier">nr</span><span class="code-symbol">)</span> <span class="code-symbol">*</span> <span class="code-symbol">(</span><span class="code-identifier">countDivisors</span> <span class="code-symbol">((</span><span class="code-identifier">nr</span><span class="code-symbol">+</span><span class="code-number">1</span><span class="code-symbol">)/</span><span class="code-number">2</span><span class="code-symbol">))</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords1">fn</span> <span class="code-identifier">nthTriangle</span> <span class="code-identifier">n</span> <span class="code-symbol">=</span> <span class="code-symbol">(</span><span class="code-identifier">n</span><span class="code-symbol">^</span><span class="code-number">2</span><span class="code-symbol">+</span><span class="code-identifier">n</span><span class="code-symbol">)/</span><span class="code-number">2</span></code>
<code></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">i</span> <span class="code-symbol">=</span> <span class="code-number">7</span> <span class="code-keywords1">to</span> <span class="code-identifier">inf</span></code>
<code> <span class="code-keywords1">where</span> <span class="code-identifier">countTriangleDivisors</span> <span class="code-identifier">i</span> <span class="code-symbol">></span> <span class="code-number">500</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-keywords1">exit</span> <span class="code-keywords1">with</span> <span class="code-identifier">nthTriangle</span> <span class="code-symbol">(</span><span class="code-keywords3">integer64</span> <span class="code-identifier">i</span><span class="code-symbol">)</span></code>
<code><span class="code-symbol">)</span></code>
</pre>
<p>It could use some work to make the preformance better, though. Note that there would be no significant speed gain (if any) if we would store previous results of our iterative <code>countDivisors</code> function but it could be an important factor if using recursive version of the same function.</p>
<p>DISCLAIMER: All scripts and snippets are provided as is under <a href="http://creativecommons.org/publicdomain/zero/1.0/">Creative Commons Zero (public domain, no restrictions) license</a>. The author and this blog cannot be held liable for any loss caused as a result of inaccuracy or error within these web pages. Use at your own risk.</p>Swordslayerhttp://www.blogger.com/profile/09124250713006663760noreply@blogger.com0tag:blogger.com,1999:blog-4212150079314071223.post-9651347391130026142011-05-15T18:11:00.000+02:002012-11-19T12:18:21.258+01:00Project Euler: Problem 11It's cold and rainy outside, let's move on to solve some other Euler problem, this time it would be <a href="http://projecteuler.net/index.php?section=problems&id=11" title="What is the greatest product of four numbers on the same straight line in the 20 by 20 grid?">problem No. 11</a>:
<blockquote><p>In the <code>20×20</code> grid below, four numbers along a diagonal line have been marked in red.</p>
<p style="text-align: center;"><code>08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08</code><br />
<code>49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00</code><br />
<code>81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65</code><br />
<code>52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91</code><br />
<code>22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80</code><br />
<code>24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50</code><br />
<code>32 98 81 28 64 23 67 10 <span style="color: red">26</span> 38 40 67 59 54 70 66 18 38 64 70</code><br />
<code>67 26 20 68 02 62 12 20 95 <span style="color: red">63</span> 94 39 63 08 40 91 66 49 94 21</code><br />
<code>24 55 58 05 66 73 99 26 97 17 <span style="color: red">78</span> 78 96 83 14 88 34 89 63 72</code><br />
<code>21 36 23 09 75 00 76 44 20 45 35 <span style="color: red">14</span> 00 61 33 97 34 31 33 95</code><br />
<code>78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92</code><br />
<code>16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57</code><br />
<code>86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58</code><br />
<code>19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40</code><br />
<code>04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66</code><br />
<code>88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69</code><br />
<code>04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36</code><br />
<code>20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16</code><br />
<code>20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54</code><br />
<code>01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48</code></p>
<p>The product of these numbers is <code>26 × 63 × 78 × 14 = 1788696</code>.</p>
<p>What is the greatest product of four adjacent numbers in any direction (up, down, left, right, or diagonally) in the <code>20×20</code> grid?</p></blockquote>
<a name='more'></a><p>This particular task doesn't leave much space for imagination, and as zeros are included, it doesn't make sense to use previous products to speed it up a little bit. So, we'll keep it simple, with just one array of all the numbers (knowing the column count, we don't have to have each row as one array) we will iterate over the horizontals, verticals and in both diagonal ways. We already know the value of one of the non-zero products so we can use it as an initial value for our maximum. For the iterators, only additions would do (well, to keep it short, I'll use <code>2*colCount</code> instead of <code>colCount + colCount</code>) and then we just multiply the four values. Easy this time.</p>
<p>Just for the fun of I've used <code>fileStream</code> this time, at least it keeps me from repeating the exact same code as the <a href="http://creativescratchpad.blogspot.com/2011/05/project-euler-problem-8.html" title="Discover the largest product of five consecutive digits in the 1000-digit number">last time</a>.
<pre class="notranslate" style="height: 400px;">
<code><span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">fn</span> <span class="code-identifier">getGrid</span> <span class="code-identifier">filePath</span> <span class="code-symbol">=</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">row</span><span class="code-symbol">,</span> <span class="code-identifier">lineNr</span> <span class="code-symbol">=</span> <span class="code-number">1</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">result</span> <span class="code-symbol">=</span> <span class="code-symbol">#()</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">file</span> <span class="code-symbol">=</span> <span class="code-keywords3">openFile</span> <span class="code-identifier">filePath</span></code>
<code> <span class="code-keywords1">while</span> <span class="code-keywords2">NOT</span> <span class="code-keywords3">EOF</span> <span class="code-identifier">file</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-identifier">row</span> <span class="code-symbol">=</span> <span class="code-symbol">(</span><span class="code-keywords3">filterString</span> <span class="code-symbol">(</span><span class="code-keywords3">readLine</span> <span class="code-identifier">file</span><span class="code-symbol">)</span> <span class="code-string">" "</span><span class="code-symbol">)</span></code>
<code> <span class="code-keywords3">join</span> <span class="code-identifier">result</span> <span class="code-symbol">(</span><span class="code-keywords1">for</span> <span class="code-identifier">i</span> <span class="code-symbol">=</span> <span class="code-number">1</span> <span class="code-keywords1">to</span> <span class="code-identifier">row</span><span class="code-symbol">.</span><span class="code-keywords1">count</span> <span class="code-keywords1">collect</span> <span class="code-identifier">row</span><span class="code-symbol">[</span><span class="code-identifier">i</span><span class="code-symbol">]</span> <span class="code-keywords1">as</span> <span class="code-keywords4">integer</span><span class="code-symbol">)</span></code>
<code> <span class="code-identifier">lineNr</span> <span class="code-symbol">+=</span> <span class="code-number">1</span></code>
<code> <span class="code-symbol">)</span></code>
<code> <span class="code-keywords3">close</span> <span class="code-identifier">file</span></code>
<code> <span class="code-identifier">result</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords1">fn</span> <span class="code-identifier">iterateOverGrid</span> <span class="code-keywords4">grid</span> <span class="code-identifier">rowCount</span><span class="code-symbol">:</span><span class="code-number">20</span> <span class="code-identifier">colCount</span><span class="code-symbol">:</span><span class="code-number">20</span> <span class="code-symbol">=</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">maxProduct</span> <span class="code-symbol">=</span> <span class="code-number">1788696</span></code>
<code></code>
<code> <span class="code-comment">-- horizontal</span></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">i</span> <span class="code-symbol">=</span> <span class="code-number">0</span> <span class="code-keywords1">to</span> <span class="code-symbol">(</span><span class="code-identifier">rowCount</span> <span class="code-symbol">-</span> <span class="code-number">1</span><span class="code-symbol">)</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">index</span> <span class="code-symbol">=</span> <span class="code-identifier">i</span><span class="code-symbol">*</span><span class="code-identifier">colCount</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">horMax</span> <span class="code-symbol">=</span> <span class="code-keywords3">amax</span> <span class="code-symbol">\</span></code>
<code> <span class="code-symbol">(</span><span class="code-keywords1">for</span> <span class="code-identifier">j</span> <span class="code-symbol">=</span> <span class="code-number">1</span> <span class="code-keywords1">to</span> <span class="code-symbol">(</span><span class="code-identifier">colCount</span> <span class="code-symbol">-</span> <span class="code-number">3</span><span class="code-symbol">)</span> <span class="code-keywords1">collect</span></code>
<code> <span class="code-keywords4">grid</span><span class="code-symbol">[</span><span class="code-identifier">index</span> <span class="code-symbol">+=</span> <span class="code-number">1</span><span class="code-symbol">]*</span><span class="code-keywords4">grid</span><span class="code-symbol">[</span><span class="code-identifier">index</span><span class="code-symbol">+</span><span class="code-number">1</span><span class="code-symbol">]*</span><span class="code-keywords4">grid</span><span class="code-symbol">[</span><span class="code-identifier">index</span><span class="code-symbol">+</span><span class="code-number">2</span><span class="code-symbol">]*</span><span class="code-keywords4">grid</span><span class="code-symbol">[</span><span class="code-identifier">index</span><span class="code-symbol">+</span><span class="code-number">3</span><span class="code-symbol">])</span></code>
<code></code>
<code> <span class="code-keywords1">if</span> <span class="code-identifier">horMax</span> <span class="code-symbol">></span> <span class="code-identifier">maxProduct</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-identifier">maxProduct</span> <span class="code-symbol">=</span> <span class="code-identifier">horMax</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-comment">-- vertical</span></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">i</span> <span class="code-symbol">=</span> <span class="code-number">1</span> <span class="code-keywords1">to</span> <span class="code-identifier">colCount</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">index</span> <span class="code-symbol">=</span> <span class="code-identifier">i</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">verMax</span> <span class="code-symbol">=</span> <span class="code-keywords3">amax</span> <span class="code-symbol">\</span></code>
<code> <span class="code-symbol">(</span><span class="code-keywords1">for</span> <span class="code-identifier">j</span> <span class="code-symbol">=</span> <span class="code-number">0</span> <span class="code-keywords1">to</span> <span class="code-symbol">(</span><span class="code-identifier">rowCount</span> <span class="code-symbol">-</span> <span class="code-number">4</span><span class="code-symbol">)</span> <span class="code-keywords1">collect</span></code>
<code> <span class="code-keywords4">grid</span><span class="code-symbol">[</span><span class="code-identifier">index</span><span class="code-symbol">]*</span><span class="code-keywords4">grid</span><span class="code-symbol">[</span><span class="code-identifier">index</span> <span class="code-symbol">+=</span> <span class="code-identifier">colCount</span><span class="code-symbol">]*</span><span class="code-keywords4">grid</span><span class="code-symbol">[</span><span class="code-identifier">index</span><span class="code-symbol">+</span><span class="code-identifier">colCount</span><span class="code-symbol">]*</span><span class="code-keywords4">grid</span><span class="code-symbol">[</span><span class="code-identifier">index</span><span class="code-symbol">+</span><span class="code-number">2</span><span class="code-symbol">*</span><span class="code-identifier">colCount</span><span class="code-symbol">])</span></code>
<code></code>
<code> <span class="code-keywords1">if</span> <span class="code-identifier">verMax</span> <span class="code-symbol">></span> <span class="code-identifier">maxProduct</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-identifier">maxProduct</span> <span class="code-symbol">=</span> <span class="code-identifier">verMax</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-comment">-- diagonal 1</span></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">i</span> <span class="code-symbol">=</span> <span class="code-number">0</span> <span class="code-keywords1">to</span> <span class="code-symbol">(</span><span class="code-identifier">rowCount</span> <span class="code-symbol">-</span> <span class="code-number">4</span><span class="code-symbol">)</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">index</span> <span class="code-symbol">=</span> <span class="code-identifier">i</span><span class="code-symbol">*</span><span class="code-identifier">colCount</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">diff</span> <span class="code-symbol">=</span> <span class="code-identifier">colCount</span> <span class="code-symbol">+</span> <span class="code-number">1</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">diagMax1</span> <span class="code-symbol">=</span> <span class="code-keywords3">amax</span> <span class="code-symbol">\</span></code>
<code> <span class="code-symbol">(</span><span class="code-keywords1">for</span> <span class="code-identifier">j</span> <span class="code-symbol">=</span> <span class="code-number">1</span> <span class="code-keywords1">to</span> <span class="code-symbol">(</span><span class="code-identifier">colCount</span> <span class="code-symbol">-</span> <span class="code-number">3</span><span class="code-symbol">)</span> <span class="code-keywords1">collect</span></code>
<code> <span class="code-keywords4">grid</span><span class="code-symbol">[</span><span class="code-identifier">index</span> <span class="code-symbol">+=</span> <span class="code-number">1</span><span class="code-symbol">]*</span><span class="code-keywords4">grid</span><span class="code-symbol">[</span><span class="code-identifier">index</span><span class="code-symbol">+</span><span class="code-identifier">diff</span><span class="code-symbol">]*</span><span class="code-keywords4">grid</span><span class="code-symbol">[</span><span class="code-identifier">index</span><span class="code-symbol">+</span><span class="code-number">2</span><span class="code-symbol">*</span><span class="code-identifier">diff</span><span class="code-symbol">]*</span><span class="code-keywords4">grid</span><span class="code-symbol">[</span><span class="code-identifier">index</span><span class="code-symbol">+</span><span class="code-number">3</span><span class="code-symbol">*</span><span class="code-identifier">diff</span><span class="code-symbol">])</span><span class="code-space"> </code>
<code></code>
<code> </span><span class="code-keywords1">if</span> <span class="code-identifier">diagMax1</span> <span class="code-symbol">></span> <span class="code-identifier">maxProduct</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-identifier">maxProduct</span> <span class="code-symbol">=</span> <span class="code-identifier">diagMax1</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-comment">-- diagonal 2</span></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">i</span> <span class="code-symbol">=</span> <span class="code-number">3</span> <span class="code-keywords1">to</span> <span class="code-symbol">(</span><span class="code-identifier">rowCount</span> <span class="code-symbol">-</span> <span class="code-number">1</span><span class="code-symbol">)</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">index</span> <span class="code-symbol">=</span> <span class="code-identifier">i</span><span class="code-symbol">*</span><span class="code-identifier">colCount</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">diff</span> <span class="code-symbol">=</span> <span class="code-identifier">colCount</span> <span class="code-symbol">-</span> <span class="code-number">1</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">diagMax2</span> <span class="code-symbol">=</span> <span class="code-keywords3">amax</span> <span class="code-symbol">\</span></code>
<code> <span class="code-symbol">(</span><span class="code-keywords1">for</span> <span class="code-identifier">j</span> <span class="code-symbol">=</span> <span class="code-number">1</span> <span class="code-keywords1">to</span> <span class="code-symbol">(</span><span class="code-identifier">colCount</span> <span class="code-symbol">-</span> <span class="code-number">3</span><span class="code-symbol">)</span> <span class="code-keywords1">collect</span></code>
<code> <span class="code-keywords4">grid</span><span class="code-symbol">[</span><span class="code-identifier">index</span> <span class="code-symbol">+=</span> <span class="code-number">1</span><span class="code-symbol">]*</span><span class="code-keywords4">grid</span><span class="code-symbol">[</span><span class="code-identifier">index</span><span class="code-symbol">-</span><span class="code-identifier">diff</span><span class="code-symbol">]*</span><span class="code-keywords4">grid</span><span class="code-symbol">[</span><span class="code-identifier">index</span><span class="code-symbol">-</span><span class="code-number">2</span><span class="code-symbol">*</span><span class="code-identifier">diff</span><span class="code-symbol">]*</span><span class="code-keywords4">grid</span><span class="code-symbol">[</span><span class="code-identifier">index</span><span class="code-symbol">-</span><span class="code-number">3</span><span class="code-symbol">*</span><span class="code-identifier">diff</span><span class="code-symbol">])</span></code>
<code></code>
<code> <span class="code-keywords1">if</span> <span class="code-identifier">diagMax2</span> <span class="code-symbol">></span> <span class="code-identifier">maxProduct</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-identifier">maxProduct</span> <span class="code-symbol">=</span> <span class="code-identifier">diagMax2</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-identifier">maxProduct</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-identifier">testGrid</span> <span class="code-symbol">=</span> <span class="code-identifier">getGrid</span> <span class="code-string">"Z:\Euler\prob11.txt"</span></code>
<code> <span class="code-identifier">iterateOverGrid</span> <span class="code-identifier">testGrid</span></code>
<code><span class="code-symbol">)</span></code>
</pre>
<p>DISCLAIMER: All scripts and snippets are provided as is under <a href="http://creativecommons.org/publicdomain/zero/1.0/">Creative Commons Zero (public domain, no restrictions) license</a>. The author and this blog cannot be held liable for any loss caused as a result of inaccuracy or error within these web pages. Use at your own risk.</p>Swordslayerhttp://www.blogger.com/profile/09124250713006663760noreply@blogger.com0tag:blogger.com,1999:blog-4212150079314071223.post-20673328476902954842011-05-14T22:33:00.002+02:002012-12-26T00:21:15.717+01:00Project Euler: Problem 10The problems start to get real, yet maxscript still holds up well. Let's have a look at <a href="http://projecteuler.net/index.php?section=problems&id=10" title="Calculate the sum of all the primes below two million">problem No. 10</a>:
<blockquote><p>The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.</p>
<p>Find the sum of all the primes below two million.</p></blockquote>
<a name='more'></a>
<p>The first thing that comes in mind is to use the <a href="http://creativescratchpad.blogspot.com/2011/05/project-euler-problem-7.html" title="Problem 7: Find the 10001st prime">previously defined</a> <code>sieveEratosthenes</code> function but where's the fun in that? So the very next thing that crossed my mind was to actually make that sluggish function a bit faster. If you do your research, you'll soon find a technique called <a href="http://en.wikipedia.org/wiki/Wheel_factorization">wheel factorization</a>.</p>
<p>Wheel factorization in short means that what you first do is that you pick a certain set of consecutive primes, then you multiply them together and in the range <code>1..result</code> you identify multiples of your original primes (including the primes themselves). You're then supposed to write them around a circle but I don't see any good reason why not to write them in a line instead. Then in each new row (ring) the elements in marked spokes/columns can be discarded as multiples as well and only the remaining numbers are tested for primarility.</p>
<p>To give an example, this is what wheel factorization using 2 and 3 looks like:</p>
<code> 1 <u>2</u> <u>3</u> <strike>4</strike> 5 <strike>6</strike></code><br />
<code> 7 <strike>8</strike> <strike>9</strike> <strike>10</strike> 11 <strike>12</strike></code><br />
<code> 13 <strike>14</strike> <strike>15</strike> <strike>16</strike> 17 <strike>18</strike></code><br />
<code> 19 <strike>20</strike> <strike>21</strike> <strike>22</strike> 23 <strike>24</strike></code><br /><br />
<p>Although it can't be seen, number four is also striked through. We've identified 2 and 3 (the original primes) and eliminated 4 and 6 and then in every n-th set 2+n*6, 3+n*6, 4+n*6, 6+n*6. We then use regular sieve for the remaining numbers.</p>
<p>For the first three primes the code goes like this:</p>
<pre class="notranslate">
<code><span class="code-keywords1">fn</span> <span class="code-identifier">wheelSieve</span> <span class="code-identifier">nr</span> <span class="code-symbol">=</span></code>
<code><span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-keywords1">count</span> <span class="code-symbol">=</span> <span class="code-identifier">nr</span><span class="code-symbol">/</span><span class="code-number">30</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">wheel</span> <span class="code-symbol">=</span> <span class="code-symbol">#{</span><span class="code-number">1</span><span class="code-symbol">,</span><span class="code-number">7</span><span class="code-symbol">,</span><span class="code-number">11</span><span class="code-symbol">,</span><span class="code-number">13</span><span class="code-symbol">,</span><span class="code-number">17</span><span class="code-symbol">,</span><span class="code-number">19</span><span class="code-symbol">,</span><span class="code-number">23</span><span class="code-symbol">,</span><span class="code-number">29</span><span class="code-symbol">}</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">sieve</span> <span class="code-symbol">=</span> <span class="code-symbol">#{</span><span class="code-number">7</span><span class="code-symbol">,</span><span class="code-number">11</span><span class="code-symbol">,</span><span class="code-number">13</span><span class="code-symbol">,</span><span class="code-number">17</span><span class="code-symbol">,</span><span class="code-number">19</span><span class="code-symbol">,</span><span class="code-number">23</span><span class="code-symbol">,</span><span class="code-number">29</span><span class="code-symbol">,</span><span class="code-identifier">nr</span><span class="code-symbol">}</span></code>
<code></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">i</span> <span class="code-symbol">=</span> <span class="code-number">1</span> <span class="code-keywords1">to</span> <span class="code-keywords1">count</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">w</span> <span class="code-keywords1">in</span> <span class="code-identifier">wheel</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-identifier">sieve</span><span class="code-symbol">[</span><span class="code-number">30</span><span class="code-symbol">*</span><span class="code-identifier">i</span> <span class="code-symbol">+</span> <span class="code-identifier">w</span><span class="code-symbol">]</span> <span class="code-symbol">=</span> <span class="code-keywords1">true</span></code>
<code></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">rootNr</span> <span class="code-symbol">=</span> <span class="code-identifier">nr</span><span class="code-symbol">^</span><span class="code-number">0</span><span class="code-symbol">.</span><span class="code-number">5</span></code>
<code></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">p</span> <span class="code-keywords1">in</span> <span class="code-identifier">sieve</span> <span class="code-keywords1">while</span> <span class="code-identifier">p</span> <span class="code-symbol"><</span> <span class="code-identifier">rootNr</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">pSquared</span> <span class="code-symbol">=</span> <span class="code-identifier">p</span><span class="code-symbol">^</span><span class="code-number">2</span><span class="code-symbol">,</span> <span class="code-identifier">twoP</span> <span class="code-symbol">=</span> <span class="code-number">2</span><span class="code-symbol">*</span><span class="code-identifier">p</span></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">i</span> <span class="code-symbol">=</span> <span class="code-identifier">pSquared</span> <span class="code-keywords1">to</span> <span class="code-identifier">nr</span> <span class="code-keywords1">by</span> <span class="code-identifier">twoP</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-identifier">sieve</span><span class="code-symbol">[</span><span class="code-identifier">i</span><span class="code-symbol">]</span> <span class="code-symbol">=</span> <span class="code-keywords1">false</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-identifier">sieve</span> <span class="code-symbol">+</span> <span class="code-symbol">#{</span><span class="code-number">2</span><span class="code-symbol">..</span><span class="code-number">3</span><span class="code-symbol">,</span><span class="code-number">5</span><span class="code-symbol">}</span> <span class="code-symbol">-</span> <span class="code-symbol">#{</span><span class="code-identifier">nr</span><span class="code-symbol">..</span><span class="code-identifier">sieve</span><span class="code-symbol">.</span><span class="code-keywords1">count</span><span class="code-symbol">}</span></code>
<code><span class="code-symbol">)</span></code>
</pre>
<p>First we define how many times the task has to be repeated – we use integer division as we will treat the first 30 differently. Then the wheel is defined (as there are just a few elements I didn't bother writing the code to calculate it for me; if using four or more primes, it would make sense, though) and then the base for our sieve which differs from the wheel only in that it doesn't include one and that it includes the upper limit itself. The reason it doesn't include the primes we were testing for in the beginning is that we would be repeating the work there, and inclusion of the upper boundary is there to preallocate the memory for the <code>bitarray</code>.</p>
<p>Then it's just repeated addition of the values and sieving the potential primes. We get rid of surplus elements of the <code>bitarray</code>, i.e. the upper value set in the beginning and the primes that might be bigger than that in the last line, together with adding the primes we've initially excluded. All in all, it's only slightly faster than <code>sieveEratosthenes</code> but at least it isn't slower. The solution to the problem then is quite an elementary one, just add up all the primes and return the result:</p>
<pre class="notranslate" style="height: 400px;">
<code><span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">fn</span> <span class="code-identifier">wheelSieve</span> <span class="code-identifier">nr</span> <span class="code-symbol">=</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-keywords1">count</span> <span class="code-symbol">=</span> <span class="code-identifier">nr</span><span class="code-symbol">/</span><span class="code-number">30</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">wheel</span> <span class="code-symbol">=</span> <span class="code-symbol">#{</span><span class="code-number">1</span><span class="code-symbol">,</span><span class="code-number">7</span><span class="code-symbol">,</span><span class="code-number">11</span><span class="code-symbol">,</span><span class="code-number">13</span><span class="code-symbol">,</span><span class="code-number">17</span><span class="code-symbol">,</span><span class="code-number">19</span><span class="code-symbol">,</span><span class="code-number">23</span><span class="code-symbol">,</span><span class="code-number">29</span><span class="code-symbol">}</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">sieve</span> <span class="code-symbol">=</span> <span class="code-symbol">#{</span><span class="code-number">7</span><span class="code-symbol">,</span><span class="code-number">11</span><span class="code-symbol">,</span><span class="code-number">13</span><span class="code-symbol">,</span><span class="code-number">17</span><span class="code-symbol">,</span><span class="code-number">19</span><span class="code-symbol">,</span><span class="code-number">23</span><span class="code-symbol">,</span><span class="code-number">29</span><span class="code-symbol">,</span><span class="code-identifier">nr</span><span class="code-symbol">}</span></code>
<code></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">i</span> <span class="code-symbol">=</span> <span class="code-number">1</span> <span class="code-keywords1">to</span> <span class="code-keywords1">count</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">w</span> <span class="code-keywords1">in</span> <span class="code-identifier">wheel</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-identifier">sieve</span><span class="code-symbol">[</span><span class="code-number">30</span><span class="code-symbol">*</span><span class="code-identifier">i</span> <span class="code-symbol">+</span> <span class="code-identifier">w</span><span class="code-symbol">]</span> <span class="code-symbol">=</span> <span class="code-keywords1">true</span></code>
<code></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">rootNr</span> <span class="code-symbol">=</span> <span class="code-identifier">nr</span><span class="code-symbol">^</span><span class="code-number">0</span><span class="code-symbol">.</span><span class="code-number">5</span></code>
<code></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">p</span> <span class="code-keywords1">in</span> <span class="code-identifier">sieve</span> <span class="code-keywords1">while</span> <span class="code-identifier">p</span> <span class="code-symbol"><</span> <span class="code-identifier">rootNr</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">pSquared</span> <span class="code-symbol">=</span> <span class="code-identifier">p</span><span class="code-symbol">^</span><span class="code-number">2</span><span class="code-symbol">,</span> <span class="code-identifier">twoP</span> <span class="code-symbol">=</span> <span class="code-number">2</span><span class="code-symbol">*</span><span class="code-identifier">p</span></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">i</span> <span class="code-symbol">=</span> <span class="code-identifier">pSquared</span> <span class="code-keywords1">to</span> <span class="code-identifier">nr</span> <span class="code-keywords1">by</span> <span class="code-identifier">twoP</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-identifier">sieve</span><span class="code-symbol">[</span><span class="code-identifier">i</span><span class="code-symbol">]</span> <span class="code-symbol">=</span> <span class="code-keywords1">false</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-identifier">sieve</span> <span class="code-symbol">+</span> <span class="code-symbol">#{</span><span class="code-number">2</span><span class="code-symbol">..</span><span class="code-number">3</span><span class="code-symbol">,</span><span class="code-number">5</span><span class="code-symbol">}</span> <span class="code-symbol">-</span> <span class="code-symbol">#{</span><span class="code-identifier">nr</span><span class="code-symbol">..</span><span class="code-identifier">sieve</span><span class="code-symbol">.</span><span class="code-keywords1">count</span><span class="code-symbol">}</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">primes</span> <span class="code-symbol">=</span> <span class="code-identifier">wheelSieve</span> <span class="code-number">2000000</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">result</span> <span class="code-symbol">=</span> <span class="code-number">0</span><span class="code-identifier">L</span></code>
<code></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">p</span> <span class="code-keywords1">in</span> <span class="code-identifier">primes</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-identifier">result</span> <span class="code-symbol">+=</span> <span class="code-identifier">p</span></code>
<code></code>
<code> <span class="code-identifier">result</span></code>
<code><span class="code-symbol">)</span></code>
</pre>
<p>DISCLAIMER: All scripts and snippets are provided as is under <a href="http://creativecommons.org/publicdomain/zero/1.0/">Creative Commons Zero (public domain, no restrictions) license</a>. The author and this blog cannot be held liable for any loss caused as a result of inaccuracy or error within these web pages. Use at your own risk.</p>Swordslayerhttp://www.blogger.com/profile/09124250713006663760noreply@blogger.com0tag:blogger.com,1999:blog-4212150079314071223.post-88346034762859875002011-05-14T09:11:00.001+02:002012-11-19T12:18:50.087+01:00Project Euler: Problem 9After a short break because of Blogger being in read-only mode for quite a while, I'm back again, now with <a href="http://projecteuler.net/index.php?section=problems&id=9" title="Find the only Pythagorean triplet, {a, b, c}, for which a + b + c = 1000">problem No. 9</a>
<blockquote><p>A Pythagorean triplet is a set of three natural numbers, a < b < c, for which,</p>
<p style="text-align: center;">a<sup>2</sup> + b<sup>2</sup> = c<sup>2</sup></p>
<p>For example, 3<sup>2</sup> + 4<sup>2</sup> = 9 + 16 = 25 = 5<sup>2</sup>.</p>
<p>There exists exactly one Pythagorean triplet for which <code>a + b + c</code> = 1000.<br />
Find the product <code>abc</code>.</p></blockquote>
<a name='more'></a><p>So, here we are, we have the sum and we know that <code>a < b < c</code> and on paper the sides would make a right-angled triangle. That gives us <code>a + b > c</code> as we can't have a triangle where the sum of the lenghts of two of its sides would be smaller than the length of the third one. For this case it means that <code>c</code> can't be bigger than <code>500</code>, and as it is as well the biggest of the three numbers it also implies that neither <code>a</code> nor <code>b</code> can get bigger than <code>500</code>. This means that we can set our upper limit to <code>nr/2</code>. As <code>a < b</code> it makes sense to start searching for <code>b</code> at <code>a + 1</code>. For each such pair of <code>a</code> and <code>b</code> we get <code>c</code> by substracting them from the target sum and if it works in the Pythagorean equation, we return it.</p>
<pre class="notranslate">
<code><span class="code-keywords1">fn</span> <span class="code-identifier">getTripleForSum</span> <span class="code-identifier">nr</span> <span class="code-symbol">=</span></code>
<code><span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">half</span> <span class="code-symbol">=</span> <span class="code-identifier">nr</span><span class="code-symbol">/</span><span class="code-number">2</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">a</span><span class="code-symbol">,</span> <span class="code-identifier">b</span><span class="code-symbol">,</span> <span class="code-identifier">c</span></code>
<code></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">a</span> <span class="code-symbol">=</span> <span class="code-number">1</span> <span class="code-keywords1">to</span> <span class="code-identifier">half</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">b</span> <span class="code-symbol">=</span> <span class="code-symbol">(</span><span class="code-identifier">a</span> <span class="code-symbol">+</span> <span class="code-number">1</span><span class="code-symbol">)</span> <span class="code-keywords1">to</span> <span class="code-identifier">half</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-identifier">c</span> <span class="code-symbol">=</span> <span class="code-identifier">nr</span> <span class="code-symbol">-</span> <span class="code-identifier">a</span> <span class="code-symbol">-</span> <span class="code-identifier">b</span></code>
<code> <span class="code-keywords1">if</span> <span class="code-identifier">c</span><span class="code-symbol">^</span><span class="code-number">2</span> <span class="code-symbol">==</span> <span class="code-symbol">(</span><span class="code-identifier">a</span><span class="code-symbol">^</span><span class="code-number">2</span> <span class="code-symbol">+</span> <span class="code-identifier">b</span><span class="code-symbol">^</span><span class="code-number">2</span><span class="code-symbol">)</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-keywords1">return</span> <span class="code-identifier">a</span><span class="code-symbol">*</span><span class="code-identifier">b</span><span class="code-symbol">*</span><span class="code-identifier">c</span></code>
<code> <span class="code-symbol">)</span></code>
<code><span class="code-symbol">)</span></code>
</pre>
<p>DISCLAIMER: All scripts and snippets are provided as is under <a href="http://creativecommons.org/publicdomain/zero/1.0/">Creative Commons Zero (public domain, no restrictions) license</a>. The author and this blog cannot be held liable for any loss caused as a result of inaccuracy or error within these web pages. Use at your own risk.</p>Swordslayerhttp://www.blogger.com/profile/09124250713006663760noreply@blogger.com0tag:blogger.com,1999:blog-4212150079314071223.post-90230556368681871522011-05-14T08:03:00.001+02:002012-11-19T12:18:59.666+01:00Project Euler: Problem 8The next problem in our collection of maxscript experiments in Project Euler is <a href="http://projecteuler.net/index.php?section=problems&id=8" title="Discover the largest product of five consecutive digits in the 1000-digit number.">problem No. 8</a>:
<blockquote><p>Find the greatest product of five consecutive digits in the 1000-digit number.</p>
<code> 73167176531330624919225119674426574742355349194934</code>
<code> 96983520312774506326239578318016984801869478851843</code>
<code> 85861560789112949495459501737958331952853208805511</code>
<code> 12540698747158523863050715693290963295227443043557</code>
<code> 66896648950445244523161731856403098711121722383113</code>
<code> 62229893423380308135336276614282806444486645238749</code>
<code> 30358907296290491560440772390713810515859307960866</code>
<code> 70172427121883998797908792274921901699720888093776</code>
<code> 65727333001053367881220235421809751254540594752243</code>
<code> 52584907711670556013604839586446706324415722155397</code>
<code> 53697817977846174064955149290862569321978468622482</code>
<code> 83972241375657056057490261407972968652414535100474</code>
<code> 82166370484403199890008895243450658541227588666881</code>
<code> 16427171479924442928230863465674813919123162824586</code>
<code> 17866458359124566529476545682848912883142607690042</code>
<code> 24219022671055626321111109370544217506941658960408</code>
<code> 07198403850962455444362981230987879927244284909188</code>
<code> 84580156166097919133875499200524063689912560717606</code>
<code> 05886116467109405077541002256983155200055935729725</code>
<code> 71636269561882670428252483600823257530420752963450</code></blockquote>
<a name='more'></a><p>For a change, this is quite a no-brainer. I saved the number in the original format of individual lines as a txt file and used a <code>memStream</code> to read it. Although I could have just as well used <code>fileStream</code>, this is supposed to be a little faster. The sole purpose of the <code>_int</code> function is to shorten the code later on. All the lines are appended to a <code>string</code> (using <code>stringStream</code> didn't result in any benefit), which is then iterated over and for each five numbers a product is calculated and assigned to a <code>midResult</code> variable. If it is bigger than a previously saved value, we replace it with it:</p>
<pre class="notranslate">
<code><span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">fn</span> <span class="code-identifier">_int</span> <span class="code-identifier">str</span> <span class="code-symbol">=</span></code>
<code> <span class="code-identifier">nr</span> <span class="code-symbol">=</span> <span class="code-identifier">str</span> <span class="code-keywords1">as</span> <span class="code-keywords4">integer</span></code>
<code></code>
<code> <span class="code-keywords1">fn</span> <span class="code-identifier">getNum</span> <span class="code-identifier">filePath</span> <span class="code-symbol">=</span></code>
<code> <span class="code-symbol">(</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">result</span> <span class="code-symbol">=</span> <span class="code-string">""</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-keywords4">fileStream</span> <span class="code-symbol">=</span> <span class="code-keywords3">memStreamMgr</span><span class="code-symbol">.</span><span class="code-keywords3">openFile</span> <span class="code-identifier">filePath</span></code>
<code></code>
<code> <span class="code-keywords1">while</span> <span class="code-keywords2">NOT</span> <span class="code-keywords4">fileStream</span><span class="code-symbol">.</span><span class="code-identifier">eos</span><span class="code-symbol">()</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-keywords3">append</span> <span class="code-identifier">result</span> <span class="code-symbol">(</span><span class="code-keywords4">fileStream</span><span class="code-symbol">.</span><span class="code-keywords3">readLine</span><span class="code-symbol">())</span></code>
<code></code>
<code> <span class="code-keywords3">memStreamMgr</span><span class="code-symbol">.</span><span class="code-keywords3">close</span> <span class="code-keywords4">fileStream</span></code>
<code> <span class="code-identifier">result</span></code>
<code> <span class="code-symbol">)</span></code>
<code></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">nr</span> <span class="code-symbol">=</span> <span class="code-identifier">getNum</span> <span class="code-string">"Z:\Euler\prob8.txt"</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-keywords3">length</span> <span class="code-symbol">=</span> <span class="code-identifier">nr</span><span class="code-symbol">.</span><span class="code-keywords1">count</span> <span class="code-symbol">-</span> <span class="code-number">4</span></code>
<code> <span class="code-keywords1">local</span> <span class="code-identifier">midResult</span><span class="code-symbol">,</span> <span class="code-identifier">result</span> <span class="code-symbol">=</span> <span class="code-number">0</span></code>
<code></code>
<code> <span class="code-keywords1">for</span> <span class="code-identifier">i</span> <span class="code-symbol">=</span> <span class="code-number">1</span> <span class="code-keywords1">to</span> <span class="code-keywords3">length</span></code>
<code> <span class="code-keywords1">where</span> <span class="code-symbol">(</span><span class="code-identifier">midResult</span> <span class="code-symbol">=</span> <span class="code-identifier">_int</span><span class="code-symbol">(</span><span class="code-identifier">nr</span><span class="code-symbol">[</span><span class="code-identifier">i</span><span class="code-symbol">])*</span><span class="code-identifier">_int</span><span class="code-symbol">(</span><span class="code-identifier">nr</span><span class="code-symbol">[</span><span class="code-identifier">i</span><span class="code-symbol">+</span><span class="code-number">1</span><span class="code-symbol">])*</span><span class="code-identifier">_int</span><span class="code-symbol">(</span><span class="code-identifier">nr</span><span class="code-symbol">[</span><span class="code-identifier">i</span><span class="code-symbol">+</span><span class="code-number">2</span><span class="code-symbol">])*</span><span class="code-identifier">_int</span><span class="code-symbol">(</span><span class="code-identifier">nr</span><span class="code-symbol">[</span><span class="code-identifier">i</span><span class="code-symbol">+</span><span class="code-number">3</span><span class="code-symbol">])*</span><span class="code-identifier">_int</span><span class="code-symbol">(</span><span class="code-identifier">nr</span><span class="code-symbol">[</span><span class="code-identifier">i</span><span class="code-symbol">+</span><span class="code-number">4</span><span class="code-symbol">]))</span> <span class="code-symbol">></span> <span class="code-identifier">result</span> <span class="code-keywords1">do</span></code>
<code> <span class="code-identifier">result</span> <span class="code-symbol">=</span> <span class="code-identifier">midResult</span></code>
<code> <span class="code-identifier">result</span></code>
<code><span class="code-symbol">)</span></code>
</pre>
<p>DISCLAIMER: All scripts and snippets are provided as is under <a href="http://creativecommons.org/publicdomain/zero/1.0/">Creative Commons Zero (public domain, no restrictions) license</a>. The author and this blog cannot be held liable for any loss caused as a result of inaccuracy or error within these web pages. Use at your own risk.</p>Swordslayerhttp://www.blogger.com/profile/09124250713006663760noreply@blogger.com1