You are on page 1of 35

Arnold Shaders Tutorial

Pedro Fernando Gomez Fernandez

2012/11/16
Contents
1 Creating your first Arnold shader 1
1.1 Pre-requisites . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1.1 Installing a C++ Compiler . . . . . . . . . . . . . . . . 1
1.1.2 Installing Arnold SDK . . . . . . . . . . . . . . . . . . 1
1.1.3 Installing MtoA . . . . . . . . . . . . . . . . . . . . . . 1
1.1.4 Installing MtoA Troubleshooting . . . . . . . . . . . 2
1.1.5 Installing MtoA and Arnold in separate folders (Ad-
vanced) . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2 Creating a shader . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.3 Using the shader in Maya . . . . . . . . . . . . . . . . . . . . 7
1.3.1 Adding Maya Metadata to your shader with a meta-
data file . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.3.2 Choosing a Maya ID for the shader . . . . . . . . . . . 8
1.3.3 Creating the Maya interface for your shader . . . . . . 8
1.3.4 Where to place your files . . . . . . . . . . . . . . . . . 9
1.3.5 Adding Maya Metadata to your shader in its source
code (Advanced) . . . . . . . . . . . . . . . . . . . . . 10

2 Creating a Shader Loader 12


2.1 Two basic shaders . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.2 The loader . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.3 Add the metadata file . . . . . . . . . . . . . . . . . . . . . . 15

3 Adding parameters to your shader 17


3.1 Creating the shader . . . . . . . . . . . . . . . . . . . . . . . . 17
3.2 Integrating the shader in Maya . . . . . . . . . . . . . . . . . 19
3.2.1 Adding metadata information . . . . . . . . . . . . . . 19
3.2.2 Adding a Maya template . . . . . . . . . . . . . . . . . 21
3.2.3 Avoid Space Optimization in the Template . . . . . . . 22
3.2.4 Method called when an attribute is changed . . . . . . 24
3.2.5 Enabling and Disabling a Control . . . . . . . . . . . . 25
3.2.6 Creating a custom control . . . . . . . . . . . . . . . . 27
3.2.7 Summary of Template Commands . . . . . . . . . . . . 28

4 Creating a Light Filter Shader 30


4.1 Creating the shader . . . . . . . . . . . . . . . . . . . . . . . . 30
4.2 Integrating the light filter in Maya . . . . . . . . . . . . . . . 31
4.2.1 Adding light filter metadata information . . . . . . . . 31
4.2.2 Adding a Maya template . . . . . . . . . . . . . . . . . 32

i
1 Creating your first Arnold shader
1.1 Pre-requisites
To be able to create Arnold shaders, you need these three components in-
stalled: a C++ compiler, the Arnold SDK and the MtoA plugin.

1.1.1 Installing a C++ Compiler


You will need a C++ compiler to create your shaders. If you work in Win-
dows, Visual Studio 2008 or 2010 will be required.

1.1.2 Installing Arnold SDK


You will need to download and extract the Arnold SDK to the folder of your
choice. For the purposes of this tutorial, we will assume that you will set
the environment variable ARNOLD PATH to the path where the Arnold SDK
is located. For example, in Windows, if you have installed Arnold in this
folder:
C:\solidangle\releases\Arnold-X.X.X.X-platform
You will set ARNOLD PATH to that folder using this command:
set ARNOLD_PATH="C:\solidangle\releases\Arnold-X.X.X.X-platform"

1.1.3 Installing MtoA


The first thing you have to do is to install MtoA, that is the Maya plugin
for Arnold in your system. Depending on your OS, follow the corresponding
steps to install it.

Windows
In order to install MtoA in windows, you will have to download the
required version package, for example: MtoA-0.20.0-win64-2012.exe,
and you will have two options:

1. You can use the installer with the two component MtoA for
Maya 20XX and MtoA for Maya 20XX Env Variables se-
lected.
2. You can use the installer with only the component MtoA for
Maya 20XX selected. In this case you will need to add these
definitions to your Maya.env file
Edit this file:
C:\Users\<User_Name>\Documents\maya\20XX-x64\Maya.env
and add these definitions:

1
MAYA_RENDER_DESC_PATH = C:\solidangle\mtoadeploy\20XX
PATH = %PATH%;C:\solidangle\mtoadeploy\20XX\bin

Now, when you start Maya, you will be able to load MtoA in the Plug-in
Manager.

Of course you can select another folder that suits you better, so for the rest
of the tutorial, we will assume that you have set the environment variable
MTOA PATH to the path where the MtoA plugin is located. In this case, you
should have to execute this command:
set MTOA_PATH="C:\solidangle\mtoadeploy\20XX"

1.1.4 Installing MtoA Troubleshooting


If after following these instructions, MtoA does not work, try these steps:

If you cannot see the MtoA plugin in Maya Plug-in Manager

If MtoA plugin does not appear atumatically in the Maya Plug-in Man-
ager, try these steps:

1. Check that a file mtoa.mod exists in this folder:


C:\Users\<User_Name>\Documents\maya\20XX-x64\modules
And it contains this text:
+ mtoa any C:\solidangle\mtoadeploy\20XX

2. Try to set the following environment variables in your system:


MAYA_PLUG_IN_PATH=C:\solidangle\mtoadeploy\20XX\plug-ins
MAYA_SCRIPT_PATH=C:\solidangle\mtoadeploy\20XX\scripts
XBMLANGPATH=C:\solidangle\mtoadeploy\20XX\icons

If you can see the MtoA plugin, but it does not load
If you can see the MtoA plugin but it does not load or it crashes when
trying to load, try these steps:

1. Set the following environment variable:


PYTHONPATH=C:\solidangle\mtoadeploy\20XX\scripts
2. Create the following global environment variables
ARNOLD_PLUGIN_PATH = C:\solidangle\mtoadeploy\20XX\shaders
MTOA_EXTENSIONS_PATH = C:\solidangle\mtoadeploy\20XX\extensions
MAYA_RENDER_DESC_PATH = C:\solidangle\mtoadeploy\20XX
PATH = %PATH%;C:\solidangle\mtoadeploy\20XX\bin

2
3. Remove (and backup) your Maya preferences folder:
C:\Users\<User_Name>\Documents\maya\20XX-x64\prefs
4. Try MtoA using a clean Maya installation
5. Try MtoA using a clean configured computer

1.1.5 Installing MtoA and Arnold in separate folders (Advanced)


If you wish to install MtoA and Arnold in separate folders you can do this
by following the next steps after you have installed Arnold and MtoA.

Windows

1. Remove Arnold from MtoA. This will involve two things:

Remove Arnold libs (ai.dll, OpenImageIO.dll and tbb.dll)


from %MTOA PATH%\bin
Remove Arnold Python bindings deleting the folders arnold and
pykick from %MTOA PATH%\scripts

2. Add the Arnold bin folder (%ARNOLD PATH\bin) you want to use to the
PATH environment variable.

3. Add the Arnold python folder (%ARNOLD PATH\python) to the PYTHONPATH


environment variable.

Linux

1. Follow the same steps as in Windows, but the Arnold libs to remove in
the first step would be: libai.so.

2. Add the Arnold bin folder (%ARNOLD PATH\bin) you want to use to the
LD LIBRARY PATH environment variable.

Mac

1. Follow the same steps as in Windows, but the Arnold libs to remove in
the first step would be: libai.dylib and libOpenImageIO.dylib.

2. Add the Arnold bin folder (%ARNOLD PATH\bin) you want to use to the
DYLD LIBRARY PATH environment variable.

3
1.2 Creating a shader
To create your first Arnold shader, write the following code in a file called
simpleShader.cpp.

simpleShader.cpp
1 #include <ai.h>
2 #include <cstring>
3 // A Simple Shader
4 AI_SHADER_NODE_EXPORT_METHODS(SimpleMethods);
5
6 namespace
7 {
8
9 enum SimpleParams { p_color };
10
11 };
12
13 node_parameters
14 {
15 AiParameterRGB("constantColor", 0.7f, 0.7f, 0.7f);
16 }
17
18 node_initialize
19 {
20 }
21
22 node_update
23 {
24 }
25
26 node_finish
27 {
28 }
29
30 shader_evaluate
31 {
32 AtColor color = AiShaderEvalParamRGB(p_color);
33 sg->out.RGB = color;
34 }
35
36 node_loader
37 {
38 if (i > 0)
39 return false;
40
41 node->methods = SimpleMethods;
42 node->output_type = AI_TYPE_RGB;
43 node->name = "simple";

4
44 node->node_type = AI_NODE_SHADER;
45 strcpy(node->version, AI_VERSION);
46 return true;
47 }

To compile the shader, do the following depending on your OS:

Windows
Open a Visual Studio command prompt and execute the following com-
mand:
cl /LD /I %ARNOLD_PATH%\include /EHsc simpleShader.cpp
/link /LIBPATH:%ARNOLD_PATH%\lib ai.lib
Of course you can also create a Visual Studio project and adjust the
settings to specify the include folder, the lib folder, add the ai.lib, and
set it to create a .dll file
Linux
Execute the following commands in a console:
g++ -o simpleShader.os -c -fPIC -D_LINUX
-I$ARNOLD_PATH/include simpleShader.cpp
g++ -o simpleShader.so -shared simpleShader.os
-L$ARNOLD_PATH/bin -lai

Congratulations! You have created your first shader. Now, to check if Arnold
can recognize it, execute the following command:
%ARNOLD_PATH%\bin\kick -l <path_to_shader> -info simple
If you execute this command in the same folder where your shader is located,
the -l <path_to_shader> is not required.

You should get this result:


node: simple
type: shader
output: RGB
parameters: 2
filename: <path_to_shader>/simpleShader.dll
version: X.X.X.X

Type Name Default


------------ -------------------------------- --------------------------
RGB constantColor 0.7, 0.7, 0.7
STRING name default_name

To test how the shader is working, you can use the following simple scene:

5
simpleScene.ass
1 ### Scene using "simple" shader
2
3 options
4 {
5 name options
6 camera "camera"
7 }
8
9 persp_camera
10 {
11 name camera
12 matrix
13 1 0 0 0
14 0 1 0 0
15 0 0 1 0
16 0 0 30 1
17 }
18
19 sphere
20 {
21 name pSphereShape2
22 center 0 0 0
23 radius 10
24 shader "simpleShader"
25 }
26
27 simple
28 {
29 name simpleShader
30 constantColor 1 0 0
31 }

Render this scene using this command:


%ARNOLD_PATH%\bin\kick -l <path_to_shader> simpleScene.ass

And you will get the following image:

Figure 1: simpleScene

6
If the shader cannot be loaded, you will get this warning:
00:00:00 10MB WARNING | [ass] line 28: node "simple" is not installed
And this image:

Figure 2: simpleScene Error

1.3 Using the shader in Maya


1.3.1 Adding Maya Metadata to your shader with a metadata file
In order that your shader is correctly recognized by Maya, you need to add
some metadata to it. The preferred way to do this is to create a metadata file
that will be automatically used when the shader is loaded. This way, it will
be easier to make modifications without having to recompile the shader. This
will also keep the Maya specific metadata in the MtoA folders, rather than
in the shaders themselves (which you might want to re-use outside Maya).
This is shown in the following code:

simpleShader.mtd
1 # simple 0x00070000
2
3 [node simple]
4 maya.name STRING "mySimple"
5 maya.id INT 0x00070000
6 maya.classification STRING "shader/surface"
7 maya.output_name STRING "outColor"
8 maya.output_shortname STRING "out"
9
10 [attr constantColor]
11 maya.name STRING "color"

If you do not give it a maya.name metadata, it will be assigned a name that


is its Arnold name prefixed by ai. In this case it would be aiSimple.
You should have to follow instructions from section 1.3.6 to name and place
this metadata file.

7
1.3.2 Choosing a Maya ID for the shader
From Autodesk help:

For plug-ins that will forever be internal to your site use the
constructor that takes a single unsigned int parameter. The nu-
meric range 0 - 0x7ffff (524288 ids) has been reserved for such
plug-ins.
The example plug-ins provided with Maya in the plug-in de-
velopment kit will use ids in the range 0x80000 - 0xfffff (524288
ids). If you customize one of these example plug-ins, you should
change the id to avoid future conflicts.
Plug-ins that are intended to be shared between sites will need
to have a globally unique id. The Autodesk Developer Network
(ADN) will provide such ids in blocks of 256. You will be assigned
one or more 24-bit prefixes. Once this has been obtained, use the
MTypeId constructor that takes 2 unsigned int parameters. The
prefix goes in the first parameter, and you are responsible for
managing the allocation of the 256 ids that go into the second
parameter.

For the purposes of this text, we will use IDs begining from 0x70000, but feel
free to use the IDs that could suit you better. Also, if you are developing
a quality shader that you would like to share with the MtoA comunity, feel
free to ask us for an ID granted by Autodesk to MtoA.

1.3.3 Creating the Maya interface for your shader


If you also want to create a Maya interface for this shader, create the follow-
ing file:

mySimpleTemplate.py
1 import pymel.core as pm
2 import mtoa.utils as utils
3 import mtoa.ui.ae.utils as aeUtils
4 from mtoa.ui.ae.shaderTemplate import ShaderAETemplate
5
6
7 class AEmySimpleTemplate(ShaderAETemplate):
8
9 def setup(self):
10 # Add the shader swatch to the AE
11 self.addSwatch()

8
12
13 self.beginScrollLayout()
14
15 # Add a list that allows to replace the shader for other one
16 self.addCustom(message, AEshaderTypeNew,
17 AEshaderTypeReplace)
18
19 # Begins a "Color Section"
20 self.beginLayout("Color Section", collapse=False)
21 # Add a control for the "constatColor" shader attribute
22 self.addControl("constantColor", label="Color",
23 annotation="Constant Color")
24
25 self.endLayout()
26
27 # include/call base class/node attributes
28 pm.mel.AEdependNodeTemplate(self.nodeName)
29
30 # Add Section for the extra controls not displayed before
31 self.addExtraControls()
32 self.endScrollLayout()

In the addControl method, the first argument is the shader attribute name
or the maya.name metadata of that attribute. So in this case the parameter
could be: constantColor or color.
Note that the name of the defined class should be: AE<shader_name>Template
and the file name <shader_name>Template.py where <shader_name> is the
value of the maya.name metadata of the shader.

1.3.4 Where to place your files


In order that your shader works correctly in Maya, it is very important that
you name and place the files in the correct locations. You should have three
files:

Compiled Shader
This is the shader you compiled, and it will be responsible for the shader
behaviour. In this example, it is simpleShader.dll in Windows. You
can copy it to: %MTOA PATH%\shaders\ or to any other folder that is
included in the environment variable %ARNOLD PLUGIN PATH%

Metadata File
This is the file where all the metadata information is located. This will

9
add information that Maya needs about the shader. The name of this
file must be thes same as the shader, but with a .mtd extension. In
this example its name will be simpleShader.mtd . This file will have
to be copied to the same folder where the Compiled Shader is located.

Template File
This is the file where the Maya Template for this shader is defined. The
name of this file and the class name inside it has to follow the rules from
previous section. In this example it is mySimpleTemplate.py . This
file can be copied to this folder: %MTOA PATH%\scripts\mtoa\ui\ae\
or to any other folder that is included in the environment variable
%MTOA TEMPLATE PATH%

Now, with everything in its correct place, when you use the aiSimple shader
in Maya, you will be able to see this Attribute Editor for it.

Figure 3: Simple Template

1.3.5 Adding Maya Metadata to your shader in its source code


(Advanced)
It is also possible, though not recommended, to place Maya metadata in the
code, instead of using a metadata file. The following example code shows the
syntax for this; but remember that a separate metadata file is more flexible.
A good use for this method could be to add needed metadata that is not
specific to any plugin.

10
mayaShader.cpp
node_parameters
{
// Node metadata
AiMetaDataSetStr(mds, NULL, "maya.name", "aiSimple");
AiMetaDataSetInt(mds, NULL, "maya.id", 0x00070000);
AiMetaDataSetStr(mds, NULL, "maya.classification", "shader/surface");
AiMetaDataSetStr(mds, NULL, "maya.output_name", "outColor");
AiMetaDataSetStr(mds, NULL, "maya.output_shortname", "out");

AiParameterRGB("constantColor", 0.7f, 0.7f, 0.7f);


AiMetaDataSetStr(mds, "constantColor", "maya.name", "color");
}

11
2 Creating a Shader Loader
If you write several shaders, it could be useful to create a loader that will
load all of them from the same library file. It is also possible to create a
metadata file with all the metadata information from all the shaders.

2.1 Two basic shaders


The first thing you need are the shaders you want to include; here are two
very basic ones:

myShader1.cpp
1 #include <ai.h>
2
3 AI_SHADER_NODE_EXPORT_METHODS(MyShader1Mtd);
4
5 namespace
6 {
7
8 enum MyShader1Params { p_color };
9
10 };
11
12 node_parameters
13 {
14 AiParameterRGB("color1", 0.0f, 0.0f, 0.0f);
15 }
16
17 node_initialize
18 {
19 }
20
21 node_update
22 {
23 }
24
25 node_finish
26 {
27 }
28
29 shader_evaluate
30 {
31 AtColor color = AiShaderEvalParamRGB(p_color);
32 sg->out.RGB = color;
33 }

12
myShader2.cpp
1 #include <ai.h>
2
3 AI_SHADER_NODE_EXPORT_METHODS(MyShader2Mtd);
4
5 namespace
6 {
7
8 enum MyShader2Params { p_color };
9
10 };
11
12 node_parameters
13 {
14 AiParameterRGB("color2", 1.0f, 1.0f, 1.0f);
15 }
16
17 node_initialize
18 {
19 }
20
21 node_update
22 {
23 }
24
25 node_finish
26 {
27 }
28
29 shader_evaluate
30 {
31 AtColor color = AiShaderEvalParamRGB(p_color);
32 sg->out.RGB = color;
33 }

2.2 The loader


With these two shaders, it will be easy to write a loader for them:
loader.cpp
1 #include <ai.h>
2 #include <cstring>
3
4 extern AtNodeMethods* MyShader1Mtd;
5 extern AtNodeMethods* MyShader2Mtd;

13
6
7 enum{
8 MY_SHADER_1 = 0,
9 MY_SHADER_2
10 };
11
12 node_loader
13 {
14 switch (i)
15 {
16 case MY_SHADER_1:
17 node->methods = MyShader1Mtd;
18 node->output_type = AI_TYPE_RGB;
19 node->name = "myShader1";
20 node->node_type = AI_NODE_SHADER;
21 break;
22
23 case MY_SHADER_2:
24 node->methods = MyShader2Mtd;
25 node->output_type = AI_TYPE_RGB;
26 node->name = "myShader2";
27 node->node_type = AI_NODE_SHADER;
28 break;
29
30 default:
31 return false;
32 }
33
34 strcpy(node->version, AI_VERSION);
35
36 return true;
37 }

When you have these files, you can compile them in a similar way to a single
shader:

In Windows
Open a Visual Studio command prompt and execute the following:
cl /LD /I %ARNOLD_PATH%\include /EHsc
loader.cpp myShader1.cpp myShader2.cpp
/link /LIBPATH:%ARNOLD_PATH%\lib ai.lib
Or you can compile each shader separately and then link them to the
loader:
cl /c /I %ARNOLD_PATH%\include /EHsc myShader1.cpp
cl /c /I %ARNOLD_PATH%\include /EHsc myShader2.cpp
cl /LD /I %ARNOLD_PATH%\include /EHsc loader.cpp

14
myShader1.obj myShader2.obj
/link /LIBPATH:%ARNOLD_PATH%\lib ai.lib

Now you can, as with your first shader, use kick with the -info option to
check if they have been correctly created and loaded by Arnold.

>> %ARNOLD_PATH%\bin\kick -l <path_to_shader> -info myShader1

node: myShader1
type: shader
output: RGB
parameters: 2
filename: <path_to_shader>/loader.dll
version: X.X.X.X

Type Name Default


------------ -------------------------------- --------------------------
RGB color 0, 0, 0
STRING name default_name

>> %ARNOLD_PATH%\bin\kick -l <path_to_shader> -info myShader2

node: myShader2
type: shader
output: RGB
parameters: 2
filename: <path_to_shader>/loader.dll
version: X.X.X.X

Type Name Default


------------ -------------------------------- --------------------------
RGB color 1, 1, 1
STRING name default_name

Finally, to make these shaders availables to MtoA, you should copy the com-
piled file to this location:
%MTOA_PATH%\shaders\

2.3 Add the metadata file


To make MtoA recognize metadata information for the created shaders, you
can create a metadata file for all the shaders.
A simple metadata file for these shaders could be like this:

15
loader.mtd
1 # myShader1 0x00070001
2 # myShader2 0x00070002
3
4 [node myShader1]
5 maya.name STRING "aiMyShader1"
6 maya.id INT 0x00070001
7 maya.classification STRING "shader/surface"
8 maya.output_name STRING "outColor"
9 maya.output_shortname STRING "out"
10
11 [attr color1]
12 maya.name STRING "color"
13
14 [node myShader2]
15 maya.name STRING "aiMyShader2"
16 maya.id INT 0x00070002
17 maya.classification STRING "shader/surface"
18 maya.output_name STRING "outColor"
19 maya.output_shortname STRING "out"
20
21 [attr color2]
22 maya.name STRING "color"

Then copy this file to the same folder where the compiled shaders are:
%MTOA PATH%\shaders\

Remember that the metafile name should be the same as the compiled shader;
if for example, your loader is called loader.dll, the metadata file must be
loader.mtd.

16
3 Adding parameters to your shader
Here we will add more different parameters to our shader and they will be
integrated to the Maya interface. This will allow us to have an easy way to
modify our shader in Maya.

3.1 Creating the shader


We can add a new shader to the previous shader loader we created in the
previous section:
First, create the shader:

parametersShader.cpp
1 #include <ai.h>
2
3 AI_SHADER_NODE_EXPORT_METHODS(ParametersShaderMtd);
4
5 namespace
6 {
7
8 enum ParametersShaderParams { p_int, p_uint, p_bool, p_float,
9 p_RGB, p_vector, p_point, p_point2,
10 p_string, p_matrix, p_enum };
11
12 const char* enum_list[] =
13 {
14 "First value",
15 "Second value",
16 "Third value",
17 NULL
18 };
19
20 };
21
22 node_parameters
23 {
24 AtMatrix id;
25 AiM4Identity(id);
26
27 AiParameterInt("IntParam", 0);
28 AiParameterUInt("UIntParam", 0);
29 AiParameterBool("BoolParam", 0);
30 AiParameterFlt("FltParam", 0.0f);
31 AiParameterRGB("RGBParam", 1.0f, 0.0f, 0.0f);
32 AiParameterVec("VecParam", 1.0f, 1.0f, 1.0f);
33 AiParameterPnt("PntParam", 0.5f, 0.5f, 0.5f);
34 AiParameterPnt2("Pnt2Param", 0.7f, 0.7f);

17
35 AiParameterStr("StrParam", "");
36 AiParameterMtx("MtxParam", id);
37 AiParameterEnum("EnumParam", 0, enum_list);
38 AiParameterArray("ArrayParam", AiArray(0, 0, AI_TYPE_RGB));
39 }
40
41 node_initialize
42 {
43 }
44
45 node_update
46 {
47 }
48
49 node_finish
50 {
51 }
52
53 shader_evaluate
54 {
55 AtColor color = AiShaderEvalParamRGB(p_RGB);
56 sg->out.RGB = color;
57 }

You can see that node parameters of different types are defined, but only the
RGBParam is used.
Now, to add the shader to the loader, you only need to add this code to the
previous Loader.cpp file from the previous section:
loader.cpp
extern AtNodeMethods* ParametersShaderMtd;

enum{
MY_SHADER_1 = 0,
MY_SHADER_2,
PARAMETERS_SHADER
};
...

case PARAMETERS_SHADER:
node->methods = ParametersShaderMtd;
node->output_type = AI_TYPE_RGB;
node->name = "parametersShader";
node->node_type = AI_NODE_SHADER;
break;

You will be able to compile the loader again as described in the previous sec-
tion, check that Arnold can load the shader correctly, and copy the compiled

18
shader to the correct folder so that Maya can use it. If you do so, you will
discover that it is usable but not well integrated in Maya.

3.2 Integrating the shader in Maya


To integrate this new shader, we can, as in the first section, add information
to the metadata file and create a template script for this shader.

3.2.1 Adding metadata information


To add the metadata information, you only have to add this to the loader.mtd
file created in the previous section that you placed in this folder:
%MTOA_PATH%\shaders\

loader.mtd
25 [node parametersShader]
26 desc STRING "Arnold shader to test parameters."
27 maya.name STRING "aiParametersShader"
28 maya.id INT 0x00070003
29 maya.classification STRING "shader/surface"
30 maya.output_name STRING "outColor"
31 maya.output_shortname STRING "out"
32
33 [attr IntParam]
34 desc STRING "Integer parameter."
35 min INT -100
36 max INT 100
37 softmin INT -10
38 softmax INT 10
39 default INT -10
40 maya.shortname STRING "int"
41 maya.name STRING "integer"
42 [attr UIntParam]
43 desc STRING "UInteger parameter."
44 min INT 0
45 max INT 100
46 softmin INT 0
47 softmax INT 10
48 default INT 0
49 maya.shortname STRING "uint"
50 maya.name STRING "uinteger"
51 [attr BoolParam]
52 desc STRING "Bool parameter."
53 default BOOL True
54 maya.shortname STRING "bl"
55 maya.name STRING "bool"

19
56 [attr FltParam]
57 desc STRING "Float parameter."
58 min FLOAT 0
59 max FLOAT 10
60 softmin FLOAT 0
61 softmax FLOAT 1
62 default FLOAT 0.5
63 maya.shortname STRING "flt"
64 maya.name STRING "float"
65 [attr RGBParam]
66 desc STRING "RGB parameter."
67 maya.name STRING "color"
68 maya.shortname STRING "cl"
69 [attr VecParam]
70 desc STRING "Vector parameter."
71 maya.name STRING "vector"
72 maya.shortname STRING "vec"
73 [attr PntParam]
74 desc STRING "Point parameter."
75 maya.name STRING "point"
76 maya.shortname STRING "pnt"
77 [attr Pnt2Param]
78 desc STRING "2D Point parameter."
79 maya.name STRING "point2"
80 maya.shortname STRING "pnt2"
81 [attr StrParam]
82 desc STRING "String parameter."
83 maya.name STRING "string"
84 maya.shortname STRING "str"
85 default STRING "empty"
86 [attr MtxParam]
87 desc STRING "Matrix parameter."
88 maya.name STRING "matrix"
89 maya.shortname STRING "mtx"
90 [attr EnumParam]
91 desc STRING "Enumeration parameter."
92 default INT 1
93 maya.name STRING "enumeration"
94 maya.shortname STRING "enum"
95 [attr ArrayParam]
96 desc STRING "Color Array parameter."
97 maya.name STRING "colorarray"
98 maya.shortname STRING "carray"

This describes attributes that will be used for the Maya representation of
the parameters as name, shortname, slider limits, descriptions and default
values.

20
3.2.2 Adding a Maya template
The last task to do is to create a Maya template for this shader. This is similar
to the one created in the first section: self.addControl(parameterName,
label="Parameter Label"). But adding the rest of the controls. The cor-
rect control for each attribute will be created automatically.
Create an aiParametersShaderTemplate.py file in
%MTOA_PATH%\scripts\mtoa\ui\ae\ or in any folder that is definded in
%MTOA_TEMPLATE_PATH%

aiParametersShaderTemplate.py
1 import pymel.core as pm
2 from mtoa.ui.ae.shaderTemplate import ShaderAETemplate
3
4 class AEaiParametersShaderTemplate(ShaderAETemplate):
5 def setup(self):
6 self.addSwatch()
7 self.beginScrollLayout()
8 self.addCustom(message, AEshaderTypeNew,
9 AEshaderTypeReplace)
10
11 self.beginLayout("Parameters list", collapse=False)
12 self.addControl("integer", label="Integer Param")
13 self.addControl("uinteger", label="Unsigned Int Param")
14 self.addControl("bool", label="Bool param")
15 self.addControl("float", label="Float param")
16 self.addControl("color", label="Color param")
17 self.addControl("vector", label="Vector param")
18 self.addControl("point", label="Point param")
19 self.addControl("point2", label="2D Point param")
20 self.addControl("string", label="String param")
21 self.addControl("matrix", label="Matrix param")
22 self.addControl("enumeration", label="Enumeration param")
23 self.addControl("colorarray", label="Color Array param")
24 self.endLayout()
25
26 pm.mel.AEdependNodeTemplate(self.nodeName)
27
28 self.addExtraControls()
29 self.endScrollLayout()

When you use the ParametersShader in Maya, you will be able to see this
Attribute Editor for it.

21
Figure 4: ParametersShader Template

Now you will be able to configure your shaders input parameters from Maya.

3.2.3 Avoid Space Optimization in the Template


Maya automatically tries to optimize the layout space, for example, if in the
previous code you change from this:
aiParametersShaderTemplate.py
...
self.addControl("uinteger", label="Unsigned Int Param")
self.addControl("bool", label="Bool param")

22
self.addControl("float", label="Float param")
...

To this:
aiParametersShaderTemplate.py
...
self.addControl("uinteger", label="Unsigned Int Param")
self.addControl("bool", label="Bool param 1")
self.addControl("bool", label="Bool param 2")
self.addControl("float", label="Float param")
...

You will see this result:

Figure 5: Optimized Template

To avoid this, we can use this code instead:

aiParametersShaderTemplate.py
...
self.addControl("uinteger", label="Unsigned Int Param")
self.beginNoOptimize()
self.addControl("bool", label="Bool param 1")
self.addControl("bool", label="Bool param 2")
self.endNoOptimize()
self.addControl("float", label="Float param")
...

And you will get this result:

Figure 6: Optimized Template

23
3.2.4 Method called when an attribute is changed
Sometimes we may need a certain action to be performed everytime an at-
tribute is changed. For example to evaluate that the introduced value is
correct.
Lets imagine we require that the value of the uinteger attribute is always
greater or equal to the integer attribute. We can try to achieve thit with
the following code.

aiParametersShaderTemplate.py
import pymel.core as pm
import maya.cmds as cmds
from mtoa.ui.ae.shaderTemplate import ShaderAETemplate

class AEaiParametersShaderTemplate(ShaderAETemplate):
def checkInteger(self, nodeName):
intAttr = self.nodeAttr(integer)
uintAttr = self.nodeAttr(uinteger)
intValue = cmds.getAttr(intAttr)
uintValue = cmds.getAttr(uintAttr)
if intValue > uintValue:
cmds.setAttr(uintAttr,intValue)
def setup(self):
self.addSwatch()
self.beginScrollLayout()
self.addCustom(message, AEshaderTypeNew,
AEshaderTypeReplace)

self.beginLayout("Parameters list", collapse=False)


self.addControl("integer", label="Integer Param",
changeCommand=self.checkInteger)
self.addControl("uinteger", label="Unsigned Int Param")
...

Now everytime that that the integer attribute is updated, if it has a value
greater that the uinteger value, this will be increased to be equals to that
value. But, of course, if you decrease the uinteger parameter, this could be
lower than the integer one. To deal also with this case we can easily write
this code:

aiParametersShaderTemplate.py
import pymel.core as pm
import maya.cmds as cmds
from mtoa.ui.ae.shaderTemplate import ShaderAETemplate

class AEaiParametersShaderTemplate(ShaderAETemplate):
def checkInteger(self, nodeName):

24
intAttr = self.nodeAttr(integer)
uintAttr = self.nodeAttr(uinteger)
intValue = cmds.getAttr(intAttr)
uintValue = cmds.getAttr(uintAttr)
if intValue > uintValue:
cmds.setAttr(uintAttr,intValue)
def checkUinteger(self, nodeName):
intAttr = self.nodeAttr(integer)
uintAttr = self.nodeAttr(uinteger)
intValue = cmds.getAttr(intAttr)
uintValue = cmds.getAttr(uintAttr)
if intValue > uintValue:
cmds.setAttr(intAttr,uintValue)
def setup(self):
self.addSwatch()
self.beginScrollLayout()
self.addCustom(message, AEshaderTypeNew,
AEshaderTypeReplace)

self.beginLayout("Parameters list", collapse=False)


self.addControl("integer", label="Integer Param",
changeCommand=self.checkInteger)
self.addControl("uinteger", label="Unsigned Int Param",
changeCommand=self.checkUinteger)
...

3.2.5 Enabling and Disabling a Control


Sometimes some parameters does not have any meaning depending on other
attributes values. For example, lets imagine that the float attribute only
makes sense when the bool attribute is true. We can make this clear for
the user if disabling the float attribute when bool is false. To do this, first
we can define a changeCommand method as in the previous section, and use
there the arnoldDimControlIfFalse method to disable the attribute. Here
is an example:

aiParametersShaderTemplate.py
import pymel.core as pm
import maya.cmds as cmds
import mtoa.ui.ae.utils as aeUtils
from mtoa.ui.ae.shaderTemplate import ShaderAETemplate

class AEaiParametersShaderTemplate(ShaderAETemplate):
def changeBool(self, nodeName):
aeUtils.arnoldDimControlIfFalse(nodeName, "float", "bool")

def setup(self):

25
self.addSwatch()
self.beginScrollLayout()
self.addCustom(message, AEshaderTypeNew,
AEshaderTypeReplace)

self.beginLayout("Parameters list", collapse=False)


self.addControl("integer", label="Integer Param")
self.addControl("uinteger", label="Unsigned Int Param")
self.addControl("bool", label="Bool param",
changeCommand=self.changeBool)
self.addControl("float", label="Float param")
...

If we want the opposite, making the float attribute to be enabled only


when bool if false, you can use aeUtils.arnoldDimControlIfTrue instead
of aeUtils.arnoldDimControlIfFalse. But in some cases the condition to
enable or dissable an attribute could be more complex. For example we may
enable the float value only in the case that the red component of color is
greater than 0. You can write a code like this for that case:

aiParametersShaderTemplate.py
import pymel.core as pm
import maya.cmds as cmds
import mtoa.ui.ae.utils as aeUtils
from mtoa.ui.ae.shaderTemplate import ShaderAETemplate

class AEaiParametersShaderTemplate(ShaderAETemplate):
def changeColor(self, nodeName):
redAttr = self.nodeAttr(colorR)
redValue = pm.getAttr(redAttr)
dim = not (redValue > 0)
pm.editorTemplate(dimControl=(nodeName, "float", dim))

def setup(self):
self.addSwatch()
self.beginScrollLayout()
self.addCustom(message, AEshaderTypeNew,
AEshaderTypeReplace)

self.beginLayout("Parameters list", collapse=False)


self.addControl("integer", label="Integer Param")
self.addControl("uinteger", label="Unsigned Int Param")
self.addControl("bool", label="Bool param")
self.addControl("float", label="Float param")
self.addControl("color", label="Color param",
changeCommand=self.changeColor)
...

26
3.2.6 Creating a custom control
MtoA will automatically create a control for the attributes based on its type,
but sometimes you may need more flexibility and create a custom control for
a certain attribute. For example, lets imagine that the string attribute in
the previous example is used to point to a file. Then you may want a control
with a button that shows a file explorer so you can enter the file name in a
more intuitive way. Here is an example to get that behavior:
aiParametersShaderTemplate.py
import pymel.core as pm
import maya.cmds as cmds
from mtoa.ui.ae.shaderTemplate import ShaderAETemplate

class AEaiParametersShaderTemplate(ShaderAETemplate):
def filenameEdit(self, mData) :
attr = self.nodeAttr(string)
cmds.setAttr(attr,mData,type="string")

def LoadFilenameButtonPush(self, *args):


basicFilter = All Files (*.*)
ret = cmds.fileDialog2(fileFilter=basicFilter, dialogStyle=2,
cap=Load File,okc=Load,fm=4)
if ret is not None and len(ret):
self.filenameEdit(ret[0])
cmds.textFieldButtonGrp("filenameGrp", edit=True, text=ret[0])

def filenameNew(self, nodeName):


path = cmds.textFieldButtonGrp("filenameGrp", label="File Name",
changeCommand=self.filenameEdit, width=300)
cmds.textFieldButtonGrp(path, edit=True, text=cmds.getAttr(nodeName))
cmds.textFieldButtonGrp(path, edit=True, buttonLabel="...",
buttonCommand=self.LoadFilenameButtonPush)

def filenameReplace(self, nodeName):


cmds.textFieldButtonGrp("filenameGrp", edit=True,
text=cmds.getAttr(nodeName) )

def setup(self):
self.addSwatch()
self.beginScrollLayout()
self.addCustom(message, AEshaderTypeNew,
AEshaderTypeReplace)

self.beginLayout("Parameters list", collapse=False)


...
self.addCustom(string, self.filenameNew, self.filenameReplace)
...

27
3.2.7 Summary of Template Commands
Here we will summarize all the previously used template methods and add
some new ones:

addSwatch
As previously seen, this command creates a Swatch in the Attribute
Editor that shows a preview of the Shader.

beginScrollLayout endScrollLayout
Begins and ends a Vertical Scroll Layout where you can place sections
and attributes.

beginLayout endLayout
Begins and ends a Layout. You can give it a name and define if it will
be collapsed or not by default.
self.beginLayout("Section Name", collapse=False)

addControl
Creates a control for a shader attribute. It automatically creates the
correct control depending on the type of attribute. You can define a
label and a changeCommand.
self.addControl("attrname", label="My Attr",
changeCommand=self.changeAttr])

addCustom
Creates a custom control for a shader attribute.
self.addCustom(attrName, newMethod, replaceMethod)

addSeparator
Adds a separator in the layout.

beginNoOptimize endNoOptimize
Stops and starts again the layout space optimization.

addBumpLayout
Creates a section that will allow you to connect a bump normal map-
ping to the shader.

addExtraControls
All extra attributes will be grouped in an Extra Controls section

28
addCustom(message,AEshaderTypeNew,AEshaderTypeReplace)

Creates a Type scroll list where you can change the shader type
of the node.

pm.mel.AEdependNodeTemplate(self.nodeName)
Creates the Node Behavior section in the shader template.

29
4 Creating a Light Filter Shader
To create this shader you will need, as previously, a source code file, a loader,
a metadata and a template. We will take a look at them here.

4.1 Creating the shader


We can add the light filter shader to the previous shader loader we created
in the previous sections:
First, create the shader:

simpleLightFilter.cpp
1 #include <ai.h>
2
3
4 AI_SHADER_NODE_EXPORT_METHODS(SimpleLightFilterMtd);
5
6 enum simpleLightFilterParams {
7 p_intensity
8 };
9
10 node_parameters
11 {
12 AiParameterFlt("Intensity", 0.0f);
13 }
14
15 node_initialize
16 {
17 }
18
19 node_update
20 {
21 }
22
23 node_finish
24 {
25 }
26
27 shader_evaluate
28 {
29 float intensity = AiShaderEvalParamFlt(p_intensity);
30 sg->Liu = sg->Liu*intensity;
31 }

Now, to add the shader to the loader, you only need to add this code to the
previous Loader.cpp file from the previous sections:

30
loader.cpp
...
extern AtNodeMethods* SimpleLightFilterMtd;

enum{
MY_SHADER_1 = 0,
MY_SHADER_2,
PARAMETERS_SHADER,
SIMPLE_LIGHT_FILTER
};
...

case SIMPLE_LIGHT_FILTER:
node->methods = SimpleLightFilterMtd;
node->output_type = AI_TYPE_RGB;
node->name = "simpleLightFilter";
node->node_type = AI_NODE_SHADER;
break;
...

You will be able to compile the light filter and the loader again as described
in the previous sections, check that Arnold can load the shader correctly, and
copy the compiled shader to the correct folder (as if it was a normal shader)
so that Maya can use it.

4.2 Integrating the light filter in Maya


To integrate a light filter in Maya, we need to add extra information to the
metadata file and create a template script as in the previous section.

4.2.1 Adding light filter metadata information


To add the metadata information, you only have to add this to the loader.mtd
file created in the previous sections that you placed in the same folder as the
compiled shader file.

loader.mtd
101
102 [node simplyLightFilter]
103 maya.name STRING "aiSimplyLightFilter"
104 maya.id INT 0x00070004
105 maya.classification STRING "light/filter"
106 maya.lights STRING "pointLight spotLight"
107
108 [attr Intensity]
109 maya.name STRING "lightIntensity"

31
110 softmin FLOAT 0
111 softmax FLOAT 10
112 default FLOAT 1

Here it is important to set maya.classification to "light/filter". And


also set maya.lights to a string that contains all the lights that can use this
light filter like: ambientLight, directionalLight, pointLight, spotLight,
areaLight or aiAreaLight.

4.2.2 Adding a Maya template


As in the previous sections, we can create a simple template for this light
filter in the same was as for normal shaders. Anyway, we will avoid some of
the commands that do not make sense in a light filter:

aiSimpleLightFilterTemplate.py
1 import pymel.core as pm
2 from mtoa.ui.ae.shaderTemplate import ShaderAETemplate
3
4 class AEaiSimpleLightFilterTemplate(ShaderAETemplate):
5 def setup(self):
6 self.beginScrollLayout()
7
8 self.beginLayout("Parameters", collapse=False)
9 self.addControl(lightIntensity, label="Light Intensity")
10
11 self.endLayout()
12
13 pm.mel.AEdependNodeTemplate(self.nodeName)
14 self.addExtraControls()
15 self.endScrollLayout()

Now, when you create a type of light that is accepted by this light filter,
you will be able to add this light filter in the Light Filters section in the
Arnold section of the light:

32
Figure 7: Light Filters Menu

33

You might also like