[MtoA] Normal mapping with mayaBump2d

mayaBump2D has an RGB parameter for normal maps, and it’s named “normal_map”:

C:\solidangle\mtoadeploy\2015\bin>kick -l ..\shaders -info mayaBump2D
node:         mayaBump2D
type:         shader
output:       RGBA
parameters:   11
filename:     ..\shaders/mtoa_shaders.dll

Type          Name                              Default
------------  --------------------------------  --------------------------------

FLOAT         bump_map                          0
FLOAT         bump_height                       1
RGB           normal_map                        0, 0, 1
BOOL          flip_r                            true
BOOL          flip_g                            true
BOOL          swap_tangents                     false
BOOL          use_derivatives                   true
BOOL          gamma_correct                     true
ENUM          use_as                            bump
RGBA          shader                            0, 0, 0, 1
STRING        name

In Maya, you don’t connect your normal map directly to mayaBump2D.normal_map. Instead, just connect the normal map alpha to the Bump Value
and then change bump2d > 2d Bump Attributes > Use As to Object Space Normals or Tangent Space Normals.
The Use As parameter controls how MtoA translates the shaders to Arnold. For example, if Use As is Object Space Normals, you get this:

 name bump2d1
 bump_map file1.a
 bump_height 1
 normal_map file1
 flip_r on
 flip_g on
 swap_tangents off
 use_derivatives on
 gamma_correct on
 use_as "object_normal"
 shader aiStandard1

 name file1
 filename "shaders_offest_normalmap.jpg"

Notice that file1 (the MayaFile node) is linked to mayaBump2D.normal_map.

[MtoA] Finding your Arnold log file

When you enable file logging, it can seem a bit of a mystery where the .log files end up. You may find log files in different folders of your project, like the scenes folder, or the sourceimages folder.
Here’s how it works.

  • If the MTOA_LOG_PATH environment variable is set, the log files are saved to the folder specified by MTOA_LOG_PATH.
  • If MTOA_LOG_PATH is not set, the log files are saved in the current workspace directory (in MEL, that’s workspace -q -directory). In other words, the log files are saved to last place you went with the Maya file browser. If you haven’t used the file browser yet, the log file is saved in the root folder of the project.
  • If you click the folder icon beside the Filename text box, you can choose where the log files are saved.

Note that the log files will always include the frame number, so you’ll get arnold.1.log, arnold.2.log, and so on.

[Arnold] System requirements: minimum Windows version

As of Arnold, the minimum Windows version is Windows 7. We no longer support Windows versions before Windows 7 and Windows Server 2008 R2.

This applies to all plug-ins (such a MtoA 1.2.02 and later, or SItoA 3.4 and later) that use Arnold or later.

If you try to load an Arnold plugin on an unsupported Windows, you’ll get an error (something like “The specified procedure could not be found”).

On Vista with Arnold or later, kick -nodes gives you a more specific error:

"kick.exe - Entry Point Not Found" 
"The procedure entry point SetThreadGroupAffinity could not be located in the dynamic link library KERNEL32.dll."

[MtoA] Setting defaults for options and drivers

If you want to set default rendering options, or change the defaults for AOVs, you can use the hook functions provided by mtoadeploy/2015/scripts/mtoa/hooks.py.

hooks.py provides a number of setup functions that MtoA calls during initialization. You can override the default hook functions to do your own custom setup. For example, you could put this Python in your userSetup.py:

import mtoa.hooks

# Set some defaults for the defaultArnoldRenderOptions node
def setupOptions(options):
mtoa.hooks.setupOptions = setupOptions    

# Enable Merge AOVs for the defaultArnoldDriver and
# any other drivers created later by the user 
def setupDriver(driver, aovName=None):
mtoa.hooks.setupDriver = setupDriver    

The setupOptions() function gets a pymel.PyNode object that holds the defaultArnoldRenderOptions. setupDriver() gets an aiAOVDriver pynode and the name of the AOV as a string.

Here’s a snippet that shows how to work with the pynode for an aiAOVDriver node.

import pymel.core as pm
driver = pm.PyNode('defaultArnoldDriver')

print driver
print driver.aiTranslator.get()
print driver.mergeAOVs.get()

[Python] Linking nodes

There’s been a few questions recently about nodes that look like this in an ASS file:

 name plusMinusAverage2
 operation "sum"
 input3D 2 1 POINT
0 0 0 0 0 0
 input3D[0] file1
 input3D[1] bulge1

That’s the ASS representation of this (in Maya):
On line 6, you have the default values (two POINTs) for input3D. If there was nothing plugged into the input3D, you’d get the points (0,0,0) and (0,0,0).

Here’s an example that shows how to set up the node links for a MayaPlusMinusAverage3D node.

from arnold import *

ass_file = "mayaplusminusaverage.ass"


# Load the mtoa shaders, which include MayaPlusMinusAverage3D

AiASSLoad(ass_file, AI_NODE_ALL)

# Create a MayaPlusMinusAverage3D node
n = AiNode( "MayaPlusMinusAverage3D" )

# Set the name parameter
AiNodeSetStr( n, "name", "plusMinusAverage2" )

# Set the operation parameter
AiNodeSetStr( n, "operation", "sum" )

# input3D is of type POINT[] (an array of POINTs)

# Allocate an array; by default the array is initialized to 0s
a = AiArrayAllocate( 2, 1, AI_TYPE_POINT )
AiNodeSetArray(n, "input3D", a )

# Link input3D to the file and bulge nodes, which are assumed to already exist
f = AiNodeLookUpByName( "file1" )
b = AiNodeLookUpByName( "bulge1" )
AiNodeLink(f, "input3D[0]", n);
AiNodeLink(b, "input3D[1]", n);

AiASSWrite(ass_file, AI_NODE_ALL, False)

Here’s another example. This time, one input3D is set to (0.3, 0.2, 0.4), and the other input3D is linked to a Bulge node.

 name plusMinusAverage3
 operation "sum"
 input3D 2 1 POINT
0.3 0.2 0.4 0 0 0
 input3D[0] file1

And here’s the Python snippet that creates the node and sets up the link:

n = AiNode( "MayaPlusMinusAverage3D" )

b = AiNodeLookUpByName( "bulge1" )

AiNodeSetStr( n, "name", "plusMinusAverage3" )
AiNodeSetStr( n, "operation", "sum" )

a = AiArrayAllocate( 2, 1, AI_TYPE_POINT )
AiArraySetPnt(a, 0, AtPoint( 0.3, 0.2, 0.4 ) )

AiNodeSetArray(n, "input3D", a )

AiNodeLink(b, "input3D[1]", n);

A couple of notes:

  • You can get the type of parameters like input3D with kick:
    kick -l ..\shaders -info MayaPlusMinusAverage3
    node:         MayaPlusMinusAverage3D
    type:         shader
    output:       RGB
    parameters:   3
    filename:     ..\shaders/mtoa_shaders.dll
    Type          Name                              Default
    ------------  --------------------------------  --------------------------------
    ENUM          operation                         sum
    POINT[]       input3D                           (empty)
    STRING        name
  • For the full list of parameter types such as AI_TYPE_POINT, see the “AtParamEntry API” in the Arnold API Reference (or python/arnold/ai_params.py in the Arnold install).

[Arnold] Getting started with the Arnold Python API

You can download Arnold here. The Arnold download (aka the Arnold SDK) includes the Arnold library, the Arnold C++ API, the API docs, and the Python bindings for the Arnold API.

To use the Arnold Python API, you need to add the Arnold python folder to the PYTHONPATH:

set PYTHONPATH=C:\solidangle\arnold\Arnold-\python

Here’s a “hello world” written with the Arnold Python API:

# hello_world.py
from arnold import *


AiMsgSetConsoleFlags( AI_LOG_INFO )

AiMsgInfo( 'Hello World' )


Here’s a quick breakdown of the script.

  • You need to import the arnold module.
  • An Arnold session always starts with AiBegin() and ends with AiEnd(). You have to call AiBegin() to initialize Arnold and enable the Arnold API. Try commenting it out and see what happens…
  • We need to call AiMsgSetConsoleFlags() to set the log verbosity level (otherwise we won’t see our “Hello World”, because the default level is AI_LOG_NONE).
  • AiMsgInfo() sends our “Hello World” to the log.

Assuming that Python in is your PATH, you can run the hello world script like this:

python hello_world.py

and that will give you this output:

C:\solidangle\arnold\scripts>python helloworld.py
        | log started Wed Mar 04 14:31:40 2015
        | Arnold windows icc-14.0.2 oiio-1.4.14 rlm-11.2.2 2015/02/26 15:08:42
        | running on StephenBlair-PC with pid 33812
        |  1 x Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz (4 cores, 8 logical) with 16338MB
        |  Windows 7 Professional Service Pack 1 (version 6.1, build 7601)
        | Hello World
        | releasing resources
        | Arnold shutdown

For documentation, you use the Arnold SDK documentation. It’s for the C++ API, but the Python API is basically a one-to-one wrapper around the C++ API.

You can find the docs in the doc/api/index.html folder of the Arnold installation.

AiBegin() and AiEnd() are part of the Rendering API.
AiMsgSetConsoleFlags() and AiMsgInfo() are part of the Message Logging API, so go there to check out the possible flags, and what other logging functions are available.

[Arnold] [RLM] ARNOLD_LICENSE_HOST and ARNOLD_LICENSE_PORT no longer supported

If you’re still using ARNOLD_LICENSE_HOST and ARNOLD_LICENSE_PORT, now’s the time to stop. As of Arnold, these deprecated environment variables are no longer supported.

Instead, use solidangle_LICENSE.

For example, if you currently have these environment variable settings:


you can replace them with this:

solidangle_LICENSE 5055@lic_server

Note: solidangle_LICENSE was added in Arnold 4.0.4 (released back in 23-May-2012).

Also new with Arnold is the ability to use a .lic file instead of an environment variable. Just create a .lic file that looks like this:

HOST lic_server 5055

and put the .lic file in the same folder as Arnold (ai.dll, libai.so, or libai.dylib).

If you want to put the .lic file somewhere else, then you need to set solidangle_LICENSE to point to the lic file.