How to get a list of AOVs and LPEs


Here’s a simple kick trick to get a list of AOVs and LPEs.

The -laovs flag lists all the AOVs in the loaded scene, but if you give kick no input, you’ll get a list of all built-in AOVs defined by Arnold.

For example, on Windows, run kick -laovs -i Nul

On Linux or macOS, run kick -laovs -i /dev/null

kick -laovs -i Nul
Available aovs:
    Type:    Name:                        LPE:
    --------------------------------------------------------------
    VECTOR2  motionvector (~)
    RGBA     RGBA                         C.*
    VECTOR   N (~)
    FLOAT    Z (~)
    RGB      direct                       C[DSV]L
    RGB      indirect                     C[DSV][DSVOB].*
    VECTOR   Pref (~)
    RGB      albedo                       C[DSV]A
    RGB      emission                     C[LO]
    RGB      diffuse_direct               C<RD>L
    RGB      background                   CB
    RGB      denoise_albedo               ((C<TD>A)|(CVA)|(C<RD>A))
    RGB      sss_albedo                   C<TD>A
    RGB      specular_albedo              C<RS[^'coat''sheen']>A
    RGB      diffuse                      C<RD>.*
    FLOAT    cputime (~)
    RGB      diffuse_indirect             C<RD>[DSVOB].*
    RGB      sss_indirect                 C<TD>[DSVOB].*
    RGB      diffuse_albedo               C<RD>A
    RGBA     shadow_matte
    FLOAT    volume_Z (~)
    RGB      specular                     C<RS[^'coat''sheen']>.*
    RGB      coat_direct                  C<RS'coat'>L
    RGB      specular_direct              C<RS[^'coat''sheen']>L
    RGB      specular_indirect            C<RS[^'coat''sheen']>[DSVOB].*
    RGB      volume_direct                CVL
    RGB      coat                         C<RS'coat'>.*
    RGB      coat_indirect                C<RS'coat'>[DSVOB].*
    RGB      coat_albedo                  C<RS'coat'>A
    RGB      sheen                        C<RS'sheen'>.*
    RGB      transmission                 C<TS>.*
    RGB      transmission_direct          C<TS>L
    RGB      transmission_indirect        C<TS>[DSVOB].*
    VECTOR2  AA_offset (~)
    RGB      transmission_albedo          C<TS>A
    VECTOR   P (~)
    RGB      sheen_direct                 C<RS'sheen'>L
    RGB      volume                       CV.*
    RGB      sheen_indirect               C<RS'sheen'>[DSVOB].*
    NODE     shader (~)
    RGB      sheen_albedo                 C<RS'sheen'>A
    RGB      sss                          C<TD>.*
    RGB      sss_direct                   C<TD>L
    RGB      volume_indirect              CV[DSVOB].*
    RGB      volume_albedo                CVA
    FLOAT    A (~)
    FLOAT    ZBack (~)
    RGB      opacity (~)
    RGB      volume_opacity (~)
    FLOAT    raycount (~)
    UINT     ID (~)
    NODE     object (~)
    FLOAT    AA_inv_density (~)
    RGBA     RGBA_denoise (~)
    --------------------------------------------------------------
    (~) No opacity blending

Kicking Bifrost ASS


You can export a Bifrost scene to an Arnold ass file and then render it with kick.

Just use the -l flag (or the ARNOLD_PLUGIN_PATH environment variable) to point to the Arnold plugins that comes with the Bifrost install. For example, on Windows:

kick -v 5 -dp bifrost_aeroColors.ass 
-l "C:\Program Files\Autodesk\Bifrost\Maya2020\2.2.0.2\bifrost\arnold-6.2.0.0"
kick render of a Bifrost graph

In the Arnold log, we see that Arnold loads the procedural nodes for Bifrost:

00:00:00 88MB | loading plugins from C:\Program Files\Autodesk\Bifrost\Maya2020\2.2.0.2\bifrost\arnold-6.2.0.0 …
00:00:00 100MB | arnold_bifrost.dll: bifrost_graph uses Arnold 6.2.0.0
00:00:00 100MB | arnold_bifrost.dll: bifrost_object uses Arnold 6.2.0.0
00:00:00 100MB | arnold_bifrost.dll: bifrost_multires_volume uses Arnold 6.2.0.0
00:00:00 100MB | arnold_bifrost.dll: bifrost_multires_implicit uses Arnold 6.2.0.0
00:00:00 100MB | arnold_bifrost.dll: bifrost_volume uses Arnold 6.2.0.0
00:00:00 100MB | arnold_bifrost.dll: bifrost_points uses Arnold 6.2.0.0
00:00:00 100MB | arnold_bifrost.dll: bifrost_implicit uses Arnold 6.2.0.0
00:00:00 100MB | arnold_bifrost.dll: bifrost_polymesh uses Arnold 6.2.0.0
00:00:00 100MB | arnold_bifrost.dll: bifrost_blocks uses Arnold 6.2.0.0
00:00:00 100MB | loaded 9 plugins from 1 lib(s) in 0:00.06

In other applications, like CINEMA 4D or Houdini or Katana, you can do the same thing by setting the Plugin Search Path.

ERROR: out-of-range shader index


If you see this error in your Arnold log, it most likely means that you have more than 256 per-face shaders. Arnold has a hard limit of 256 shaders that can be assigned to a single object.

[polymesh] /pPlane1/pPlaneShape1: out-of-range shader index (5/3)

You may also see this warning if you have a large number of objects merged into one single object (for example, an Alembic archive that consists of many objects). In some cases, an Alembic archive like that may have more than 256 shaders assigned to the sub-objects.

Tangent space normal maps


The built-in N AOV is in world space. So how to get a tangent-space N AOV?
Like this:

In brief, I read the N AOV, transform the normals from world to tangent space, and then map the normal values to the range 0.5, 1 (I used the range node here, but I could have used Add and Multiply to do the same thing).

Here’s the shader tree. You can save this in a .ass file and import it into Maya or whatever application you use. Then set up an AOV shader to write the custom Ntangent AOV

range
{
 name aiRange1
 input space_transform
 output_min 0.5
}

space_transform
{
 name space_transform
 input read_N_AOV
 type "normal"
 to "tangent"
 tangent 1 0 0
 normal 0 1 0
 normalize on
}

aov_read_rgb
{
 name read_N_AOV
 aov_name "N"
}

aov_write_rgb
{
 name defaultArnoldRenderOptions/aov_write_rgb_Ntangent
 aov_input aiRange1
 aov_name "Ntangent"
}

Denoising AOVs with the Optix imager


The Optix imager can denoise the beauty and any other AOV.

The so-called layer selection tells the imager what AOVs to denoise. For example, if you want to denoise both the beauty and the coat AOVs, enter RGBA or coat in the Layer Selection text box.

Using AOV names with or is an easy way to select multiple AOVs.

You can also use wildcard characters (such as *, ., and []) to select AOVs (this is what is called glob in the docs). For example:

*Selects all AOVs
RGBA_*Selects all light group AOVs for the beauty (for example, RGBA_default, RGBA_key, and so on)
RGBA_light0[135]Selects RGBA_light01, RGBA_light03, and RGBA_light05
RGBA_light0.The period (.) matches any single character, so this selects RGBA_light00 through to RGBA_light09.
RGBA_light0[1-9] does the same thing.

You can even use regular expressions for more complicated selections. But in general, using or and wildcards should be more than enough.

[MAXtoA] Denoising AOVs with noice


First, set up your AOVs like this:

Then run noice like this:


set IMAGES="C:\Users\Stephen Blair\Documents\3ds Max 2020\renderoutput\denoiseme"

set ARNOLD_BIN=S:\solidangle\arnold\Arnold-6.0.2.0-windows\bin

%ARNOLD_BIN%\noice ^
-ef 2 -sr 2 -pr 2 -v 0.5 ^
-i %IMAGES%/AOVs0003.exr ^
-i %IMAGES%/variance0003.exr ^
-l diffuse ^
-l specular ^
-o %IMAGES%/denoised_AOVs0003.exr 

The AOVs and variance AOVs are in separate EXRs
That’s necessary to be able to have different filters for the same AOV in MAXtoA

Tip: In the Windows command prompt, you can use ^ (Shift + 6) character to indicate line continuation, and break long commands into multiple lines. You can also use ^ in in a batch file.

Remapping paths at render time!


New with Arnold 6.0.4 is path mapping.

All you have to do is create a json file that looks something like this:

{
         "windows": { "S:/": "\\server\projects\" },
         "mac": { "S:/": "/Volumes/projects/"},
         "linux": {"S:/": "/mnt/projects/"}
}

and then set ARNOLD_PATHMAP to point to the json path mapping file

How Arnold handles paths

When you render a frame, here’s what Arnold does for file paths:

  1. Replace backslashes

    When Arnold loads an ass file, Arnold replaces all backslashes ( \ ) with forward slashes ( / )

  2. Expand environment variables

    When Arnold uses a parameter, Arnold expands all environment variable references, which look like this: [MY_TEXTURE_PATH]

  3. Map paths

    After Arnold expands environment variables, Arnold applies the path-mapping rules specified by the Arnold pathmap file.

Arnold expands environment variable expansion and maps paths for:

  • search paths in the options node
  • filename parameters for these nodes:
    • alembic
    • color_manager
    • all driver nodes such as driver_deepexr, driver_exr, driver_jpg, driver_png, and driver_tiff
    • image
    • include_graph
    • materialx
    • photometric_light
    • procedural
    • volume
    • volume_implicit

Setting up path mapping

You can automatically remap paths at render time using a pathmap file.

To use a pathmap

  • Set the ARNOLD_PATHMAP environment variable to point a pathmap file

The pathmap file is a json file. For example:

{
         "windows": { "S:/": "\\server\projects\" },
         "mac": { "S:/": "/Volumes/projects/"},
         "linux": {"S:/": "/mnt/projects/"}
}

Path mapping uses regular expressions. The general format of an entry is this:

{
         "windows": { "regular expression": "replacement string" },
}

For example, this pathmap replaces all drive mappings like E:/ and S:/ with //SERVER/

{
         "windows": { "[A-Z]:/": "//SERVER/" },
}

Arnold converts backslashes ( \ ) to forward slashes ( / ) when it loads the ASS file.

Path mapping happens after that, so pathmaps never have to deal with backslashes.

There can be multiple mappings for each OS:

{
         "windows": { "[A-Z]:": "//SERVER", "sourceimages/": "textures/"},
}

[MAXtoA] Setting up an Object ID AOV


Here’s how to use the 3ds Max object ids for a simple Object ID AOV.

And here’s the material (aka shader tree) that writes the AOV. Use a text editor to save this as Arnold Scene Source (.ass) file, and then import it into 3ds Max (like I did in the video).

An ASS file is a plain-text file.

### exported: Thu May 21 07:53:19 2020
### from:     Arnold 6.0.3.0 [991b08e9] windows icc-17.0.2 oiio-2.2.1 osl-1.11.0 vdb-4.0.0 clm-1.1.1.118 rlm-12.4.2 optix-6.7.0 2020/04/17 09:11:12
### host app: MAXtoA 4.0.4.36 (2021) 3ds Max 23.0.915.2021 

aov_write_rgb
{
 name /Write_Object_ID_AOV
 aov_input /gBufID_Switch
 aov_name "object_id"
 declare nodeName constant STRING
 nodeName "Material #43"
}

switch_rgba
{
 name /gBufID_Switch
 index /gBufID
 input1 1 0 0 1
 input2 0 1 0 1
 input3 0 0 1 1
}

user_data_int
{
 name /gBufID
 attribute "gBufID"
}

Updating procedural file paths with string_replace


This is actually pretty cool…you can use an operator to update file paths before an ASS file or ABC file is loaded, then use another operator to touch the geometry loaded by that procedural.

For example, suppose at render time you want to replace trex_proxy.abc with trex.abc. You can easily do that with a string replace operator:

  • *.(@node==’alembic’) selects all Alembic procedural nodes
  • Match matches any file name that ends with “_proxy.abc”
  • Replace replaces “_proxy.abc” with “.abc”

And that all happens before the abc file is loaded.

We can see this in the Arnold log (Debug verbosity). First the string replace operator is applied; then after the abc file is loaded, a set parameter operator is applied to the nodes loaded from the abc file.

| initializing 16 nodes …
| [operators] init op: 'aiStringReplace1'
| [operators] cook op: 'aiStringReplace1' | node: '/aiStandIn/aiStandInShape'
| [proc] /aiStandIn/aiStandInShape: loaded 1 nodes (1 objects, 0 shaders)
| [operators] init op: 'TRex:tRexShape_aiSetParameter1'
| [operators] cook op: 'TRex:tRexShape_aiSetParameter1' | node: '/TRex:tRex/TRex:tRexShape'