Share

Multiple Nodes in a Library - Arnold Developer Guide

If you create several custom nodes, it can 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.

Two Simple Shaders

The first thing you need are the shaders you want to include; here are two very basic ones. Each node is defined in its own source code file, and both export their methods using the AI_SHADER_NODE_EXPORT_METHODS macro.

shader1.cpp

#include <ai.h>

AI_SHADER_NODE_EXPORT_METHODS(Shader1Mtd);
enum MyShader1Params { p_color };

node_parameters
{
   AiParameterRGB("color1", 0.0f, 0.0f, 0.0f);
}

node_initialize {}
node_update {}
node_finish {}

shader_evaluate
{
   sg->out.RGB() = AiShaderEvalParamRGB(p_color);
} 

shader2.cpp

#include <ai.h>

AI_SHADER_NODE_EXPORT_METHODS(Shader2Mtd);
enum MyShader2Params { p_color };

node_parameters
{
   AiParameterRGB("color2", 1.0f, 1.0f, 1.0f);
}

node_initialize {}
node_update {}
node_finish {}

shader_evaluate
{
   sg->out.RGB() = AiShaderEvalParamRGB(p_color);
} 

The Loader

When Arnold loads the shared, it will call the node_loader entry point several times, each time increasing the index i, until one of the calls returns false . So for loading two shaders, node_loader should return true for values of i between 0 and 1 and set the corresponding shader data in node , and return false for all other values.

loader.cpp

#include <ai.h>
#include <cstring>

extern const AtNodeMethods* Shader1Mtd;
extern const AtNodeMethods* Shader2Mtd;

enum{
   SHADER_1 = 0,
   SHADER_2
};

node_loader
{
   switch (i)
   {
   case SHADER_1:
      node->methods = Shader1Mtd;
      node->output_type = AI_TYPE_RGB;
      node->name = "shader1";
      node->node_type = AI_NODE_SHADER;
      break;

   case SHADER_2:
      node->methods = Shader2Mtd;
      node->output_type = AI_TYPE_RGB;
      node->name = "shader2";
      node->node_type = AI_NODE_SHADER;
      break;

   default:
      return false;
   }

   strcpy(node->version, AI_VERSION);
   return true;
} 

Compiling

The commands to compile are similar to a single shader, just using more files.

Linux

export ARNOLD_PATH=/path/to/arnold
c++ shader1.cpp shader2.cpp loader.cpp -o simple_shaders.so -Wall -O2 -shared -fPIC -I$ARNOLD_PATH/include -L$ARNOLD_PATH/bin -lai 

macOS

export ARNOLD_PATH=/path/to/arnold
c++ shader1.cpp shader2.cpp loader.cpp -o simple_shaders.dylib -Wall -O2 -shared -fPIC -I$ARNOLD_PATH/include -L$ARNOLD_PATH/bin -lai 

Windows Visual Studio command prompt

set ARNOLD_PATH=c:/path/to/arnold
cl /LD shader1.cpp shader2.cpp loader.cpp /I %ARNOLD_PATH%/include %ARNOLD_PATH%/lib/ai.lib /link /out:simple_shaders.dll 

When you run kick -nodes in the directory containing the shader library (or run kick -nodes with the -l flag).

> cd /shader/location
> kick -nodes

or

> kick -l /shader/location -nodes

You should see entries for shader1 and shader2 in the output list

built-in nodes sorted by name:
...

loading plugins from .
 shader1                          shader
 shader2                          shader

Was this information helpful?