Wiki
Clone wikiarnold_shaders / assExport_source_code
Source Code Documentation
The plugin is called assExport because it's main purpose it to extend Maya to be able to export a scene description for Arnold's .ass (ASS - Arnold Scene Source) file format.
Directory Structure
The source for the plug-in is found in arnold_shaders/maya/src and has a couple of sub-directories:
> cd $GIT/arnold_shaders/maya/src/
> ls -1 -F
Makefile
assExport.cpp
assExport.hpp
commands/
helpers/
nodes/
shapes/
translator/
Entry Point
The main entry point is the file assExport.cpp where the plug-in gets initialized and un-initialized during loading and un-loading of the plug-in. It needs to register a couple of things to Maya:
A Simple Ass File
Let's look at a simple .ass file exported from another application (in this case from within Blender). The original scene consisted of:
- camera
- point light
- sphere (with a single material)
A screenshot of a part of the outliner is visible in the image below on the lower right part:
Beside the four entries we would expect, there are four additional entries being found on the Arnold side. One of it is a default material which we will export from within Maya as well. The strategy is to define such a default shader (or material) and fall back to use it, whenever the exporter runs into a problem, while exporting some geometry (which needs a shader). This way we will always end up with a valid .ass file and a warning can be printed to the Maya user about the problem the exporter was facing when it tried to export a part of the scene.
AiSetAppString
One information we would like to keep in the .ass file is the host application (and probably additional settings) where the file was exported from. Therefore we will use a function from the Arnold API before we write the .ass file. That will result in a comment line starting with ### host app:
The instance of the class AssTranslator
is created immediately after the plug-in was loaded, but the function writer(...)
will be invoked either using the GUI (File->Export All...) or from within Maya's Script Editor using MEL:
file -force -options "..." -type "ASSexport" -pr -ea "/path/simple.ass";
Supported Shapes
If you ask Arnold about the built-in shapes you will get the following list:
> kick -nodes n | grep shape
box shape
cone shape
curves shape
cylinder shape
disk shape
ginstance shape
implicit shape
nurbs shape
plane shape
points shape
polymesh shape
procedural shape
sphere shape
Most of them are supported by the assExport plug-in. Currently only the ginstance
, implicit
, and procedural
don't have an equivalent Maya node. Subdivision surfaces are part of the polymesh
using related parameters. Here is a scene file (.ass) exported by the assExport plug-in and being renderer via Arnold's standalone kick command:
Particles are rendered by using the points
shape.
Export an .ASS File
As mentioned before the main purpose of the plug-in is to export an .ass file (e.g. to render a frame of a sequence on a render farm). From Maya's Script Editor you can accomplish this with the following MEL command:
file -force -options "..." -type "ASSexport" -pr -ea "/path/simple.ass";
How does this work on the C++ side? First you have to register the new command and then shovel data from the Maya side to the Arnold side (which handles the writing to an .ass file once it has all the info). We have seen already how the class AssTranslator
gets registered and how we end up in the exportAll(...)
member function (see above). See the MEL command reference for the file
command and flags for exportAll (-ea) and exportSelected (-es).
Render an Exported .ASS File
For convenience you can start a sub-process to render an exported .ass file via Arnold's standalone kick program. Maya isn't blocked in any way and can be used immediately again, once the sub-process got spawned. From within Maya's Script Editor you call a MEL command providing the camera resolution, a gamma value, the camera name (used to render the image), and a camera exposure value (easy to adjust the brightness for an already exported scene:
arnoldRender -x 640 -y 480 -cam persp -g 2.2 -e 0;
Currently all perspective cameras are exported and the orthographic ones (e.g. for the viewport) are ignored. Therefore you can prepare several cameras, export a single .ass file and render different views using the command above.
Auto-Generating most of the Source Code
There is a very simple strategy to generate C++ code from built-in Arnold lights, shaders, filters, drivers, shapes, cameras, and custom nodes (of those types). Basically there are Maya nodes (classes which inherit from MPxNode
) and the resulting C++ code resides in the arnold_shaders/maya/src/nodes sub-directory. Those Maya nodes need unique IDs which are stored in arnold_shaders/maya/src/nodes/AssMayaTypeIds.hpp and are responsible for storing Arnold specific settings (encapsulated in Maya nodes) within a Maya scene. Removing all the plug-in specific nodes and attributes should cleanly remove everything from a Maya scene which was created by the plug-in.
For each Maya node (which can for example be seen in the Hypershade window) you can specify a MEL script to re-order the parameters and group them in different layouts (this is especially useful for shaders with lots of parameters), but if such a MEL script doesn't exists (or Maya can't find it) the parameters are nevertheless there and the values can be edited - the layout might just look ugly.
So here is an example how I want the C++ code to look like if I have to retrieve the shader parameter values for Arnold's standard shader from Maya and make Arnold aware of individual parameter settings (using the Arnold C/C++ API) before writing the .ass file to disk:
...
// try to retrieve all data to export ...
AssStandard assStandard = AssStandard(shadingEngineName);
float Kd = assStandard.getKd();
...
// ... before doing Arnold stuff
arnoldShader = AiNode("standard");
AiNodeSetStr(arnoldShader, "name", shadingEngineName.asChar());
AiNodeSetFlt(arnoldShader, "Kd", Kd);
...
Before we dig deeper into the automatically generated C++ code, let's look how those nodes and shaders parameters look like in the graphical user interface of Maya:
On the left you see individual nodes and their connections in the Hypershade, on the right you see the shader parameters of the Arnold standard shader in the Attribute Editor. The layout was done by a MEL script (as mentioned before). The main concept is that we want to keep already existing shader nodes (for example for Maya's internal renderer or mental ray specific nodes) and just add Arnold specific nodes (so they can be removed and the Maya scene still be rendered with other renderers).
So the instance of the Maya node on the upper left (called aiStandard
) was registered to Maya in arnold_shaders/maya/src/assExport.cpp and will be de-registered while un-loading the plug-in:
...
#include "nodes/AssMayaStandard.hpp"
...
DLLEXPORT
MStatus
initializePlugin(MObject object) {
MStatus status;
...
typeName = "aiStandard";
status = plugin.registerNode(typeName,
AssMayaStandard::id,
AssMayaStandard::creator,
AssMayaStandard::initialize);
CHECK_MSTATUS(status);
...
return status;
}
DLLEXPORT
MStatus
uninitializePlugin(MObject object) {
MStatus status;
...
status = plugin.deregisterNode(AssMayaStandard::id);
CHECK_MSTATUS(status);
...
return status;
}
...
The C++ code for the classes AssMayaStandard
and AssStandard
was created automatically from a Python script called kick_info_to_cpp.py. And this is true for all supported Maya nodes and helper classes. Let's look into one of the Makefiles to see what's going on:
... all: options atmosphere cameras lights shaders non_built_in ... shaders: \ ... standard \ ... standard: python kick_info_to_cpp.py standard node_hpp > \ ../src/nodes/AssMayaStandard.hpp python kick_info_to_cpp.py standard node_cpp > \ ../src/nodes/AssMayaStandard.cpp python kick_info_to_cpp.py standard helper_hpp > \ ../src/helpers/AssStandard.hpp python kick_info_to_cpp.py standard helper_cpp > \ ../src/helpers/AssStandard.cpp ...
There is a rule called all which refers to other rules. One of them is called shaders and refers (again) to more rules. The standard rule finally calls the python script several times (with different) parameters and divert the output (the resulting C++ code) into header and source files for the classes AssMayaStandard
and AssStandard
.
Updated