MAXScript DirectX Scripted Material Plugin
From Tech Artists Wiki
In this tutorial, first I will go through what a DirectX Scripted Material Plugin is, what it is used for, and comparisons to other methods. Next, I provide sample files that are thoroughly documented, so the reader can understand how to implement scripted material plugins. Lastly there is an appendix with issues, caveats, and additional suggestions. It is assumed the reader has a decent grasp of both maxScript and HLSL.
Scripted materials are, in the simplest sense, just a pretty interface for a direct material. This may seem extraneous, but it is quite powerful when you realize you can put as many constants and variables into you shaders, and not expose them to a UI. Second, since the plugin interface is a UI like any other floating window or utility, you can launch utilities and commands from it, instead of having to script custom macros to use with a certain DirectX shader. These two things may not immediately sound like a big deal, but they can do wonders to simplify a pipeline and create an intuitive interface for artists.
I will also mention the obvious benefit of using a custom DirectX material, in that it allows an artist to work in a WYSIWYG environment. They can adjust material properties and be confident it will look the same in-game, since the realtime shaders in the engine and 3dsmax are almost identical. The biggest draw of a scripted material plugin comes from taking this functionality and raising it to an extremely high level.
Scripted plugins take the functionality of a MaxScript “class” and extend it. There can be plugins for geometry, helpers, particles, etc; many varieties. Specific to materials, a scripted material plugin will take a material and ‘script’ its properties to a UI as well as any additional UI features you would like.
This idea of scripting properties is at the heart of the SDXMP. You take a material, and wire it into a UI element. So therefore, it is important to you can only change UI elements that have a shader constant associated with them. This is one of the major caveats of the advanced uses of the SDXMP, and one I will explain more fully later.
If you are using a scripted material plugin and will not be using the shader via a ‘DirectX Shader’ material in max and thus have no need of an auto-generated UI, you can greatly simplify declaration of constants. You have no need of annotations for UI widgets and ranges. However, you still need the following at a minimum:
float nameOfConstant < string UIName = " "; > = 0;
Anything less will not be exposed to the SDXMP. Why I do not know, a maxScript thing probably. Simply using "float nameOfConstant;" will not work. The UI widgets don't matter to us since we will be using a scripted interface, but it doesn't matter that somethin gis there.
Code is fully documented and commented.
- In order to be exposed to the scripted plugin, shader constants must have at least a minimum UI, as related above.
- Colors with alpha channels are automatically 0-1. Colors without alpha are given by max as 0-255. I can find no reason for this, and unfortunately, no way around it. This makes many things inconvenient, because the only UI controller representing something other than a flat is clamped to 0-1. For example, if you wanted to specify multiplier values for R, G, B, and A channels of a texture in a single float4, you'd have to break it up into 4 sliders or spinners.
- If you #include something in your FX file, you need to save/update the actual FX file the plugin uses. It will not recognize if a #include'd file only is updated.
- Because of the requirement that for variables to "stick" they must be tied to a shader constant, we cannot store strings anywhere in the UI (as far as I know). You can change them, navigate away from the material (close the material editor or choose a different material) and those strings will go back to defaults. If there is a way around this, PLEASE let me know.
- In order to change values in the Scripted Material Plugin, the material editor must be open. Read that sentence again, and remember it. It seems ridiculous to me but I understand why it is needed. This means that, if you have an action on clicking a button in your UI that closes the material editor (so the window isn't cluttered, for example), it must be open in order to assign values. An example is clicking a button to use pickpoint( ) that will set material values and you close the material editor for an uncluttered view; remember to open the material editor back up, or your values will not 'stick' when they are changed.