Creating Your First Arnold Shader

By
-
Login to Follow
-
Industry
  • Film & VFX
  • Games
  • Design Visualization
Subject
  • Rendering
  • 1.0
  • Shading
Products
  • Maya
  • Arnold
Skill Level
  • Beginner

Creating a Shader

1.1 Pre-requisites

To be able to create Arnold shaders, you need these three components installed: 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 Windows, 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 ?rst 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 (see the installation instructions).

1.2 Creating a shader

To create your ?rst Arnold shader, write the following code in a ?le called simpleShader.cpp.


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

Windows

Open a Visual Studio command prompt and execute the following command:

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 ?le

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

OSX

Execute the following commands in a terminal:

gcc -I$ARNOLD_PATH/include -L$ARNOLD_PATH/bin -lai -dynamiclib simpleShader.cpp -o simpleShader

Congratulations! You have created your ?rst shader. Now, to check if Arnold can recognize it, execute the following command:

%ARNOLD_PATH%\bin\kick -l -info simple

If you execute this command in the same folder where your shader is located, the -l is not required.

You should get this result:

node: simple
type: shader
output: RGB
parameters: 2
filename: /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:

?

Render this scene using this command:

%ARNOLD_PATH%\bin\kick -l simpleScene.ass

And you will get the following image:


Figure 1: simpleScene

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 ?le

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 ?le that will be automatically used when the shader is loaded. This way, it willbe easier to make modi?cations without having to recompile the shader. This will also keep the Maya speci?c 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:

If you do not give the shader a maya.name, the shader is automatically assigned a name that is its Arnold node name pre?xed by ai. In this case, the name would be aiSimple.


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 numeric range 0 - 0x7?? (524288 ids) has been reserved for such plug-ins.
The example plug-ins provided with Maya in the plug-in development kit will use ids in the range 0x80000 - 0x??f (524288 ids). If you customize one of these example plug-ins, you should change the id to avoid future con?icts.
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 id's in blocks of 256. You will be assigned one or more 24-bit pre?xes. Once this has been obtained, use the MTypeId constructor that takes 2 unsigned int parameters. The pre?x goes in the ?rst 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 beginning 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 community, 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 following ?le:

In the addControl method, the ?rst 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 de?ned class should be: AETemplate and the ?le nameTemplate.py where is the value of the maya.name metadata of the shader.

1.3.4 Where to place your ?les

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

Compiled Shader

This is the shader you compiled, and it will be responsible for the shader behaviour. In this example, it issimpleShader.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 ?le where all the metadata information is located. This will add information that Maya needs about the shader. The name of this ?le must be the same as the compiled file, but with a .mtd extension. In this example, the file name is simpleShader.mtd . This ?le will have to be copied to the same folder where the compiled shader is located.

Template File

This is the ?le where the Maya Template for this shader is de?ned. The name of this ?le and the class name inside it has to follow the rules from previous section. In this example it is mySimpleTemplate.py. This ?le 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_TEMPLATES_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 ?le. The following example code shows the syntax for this; but remember that a separate metadata ?le is more ?exible.
A good use for this method could be to add needed metadata that is not speci?c to any plugin.


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 ?le. It is also possible to create a metadata ?le with all the metadata information from all the shaders.

2.1 Two Basic Shaders

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

With these two shaders, it will be easy to write a loader for them:

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

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 myShader1.obj myShader2.obj /link /LIBPATH:%ARNOLD_PATH%\lib ai.lib

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

>> %ARNOLD_PATH%\bin\kick -l -info myShader1
node: myShader1
type: shader
output: RGB
parameters: 2
filename: /loader.dll
version: X.X.X.X
Type Name Default
------------ -------------------------------- --------------------------
RGB color 0, 0, 0
STRING name default_name
>> %ARNOLD_PATH%\bin\kick -l -info myShader2
node: myShader2
type: shader
output: RGB
parameters: 2
filename: /loader.dll
version: 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 compiled ?le to this location: %MTOA_PATH%\shaders\

2.3 Add the metadata ?le

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

Then copy this ?le to the same folder where the compiled shaders are: %MTOA_PATH%\shaders\

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


Adding Parameters


Here we will add more di?erent 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:

Enum values
Strings for enum values should not start with a number. So this: "1st value" is not a valid enum value.

You can see that node parameters of di?erent types are de?ned, 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 ?le from the previous section:


You will be able to compile the loader again as described in the previous section, check that Arnold can load the shader correctly, and copy the compiled 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 ?rst section, add information to the metadata ?le 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.mt ?le created in the previous section that you placed in this folder: %MTOA_PATH%\shaders\

This describes attributes that will be used for the Maya representation of the parameters as name, shortname, slider limits, descriptions and default values.
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 ?rst section: self.addControl(parameterName, label="Parameter Label"). But adding the rest of the controls. The correct control for each attribute will be created automatically.
Create an aiParametersShaderTemplate.py ?le in %MTOA_PATH%\scripts\mtoa\ui\ae\ or in any folder that is de?nded in %MTOA_TEMPLATES_PATH%


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


Figure 4: ParametersShader Template

Now you will be able to con?gure your shader's 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")
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

3.2.4 Method called when an attribute is changed

Sometimes we may need a certain action to be performed everytime an attribute is changed. For example to evaluate that the introduced value is correct. Let's 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):
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, let's 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, ?rst we can de?ne a hangeCommand 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):
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")
Posted By
Tags
  • Maya
  • Arnold
  • Rendering
  • 1.0
  • Shading
0 Comments
To post a comment please login or register
*Save $66 per month on Autodesk's Suggested Retail Price (SRP) when purchasing 1 year term 3ds Max or Maya subscription.