Looking for the Arnold API Reference?


Here’s the table of contents for the API Reference

Writing an Arnold-based app:

Core data structures:

Writing plug-in extensions:

Writing shaders:

[Arnold] Loading plugins when you edit ASS files


If you’re using the Arnold API to update ASS files (for example, to change paths), you need to load all the plugins (aka shaders) that are referenced by the ASS file. Otherwise, the unknown nodes are skipped on load, and therefore won’t be in any ASS file you write.

For example, if you set ARNOLD_PLUGIN_PATH to point to the locations of the MtoA shaders and any custom shaders you use, then you could do something like this:

from arnold import *
import os

AiBegin()
AiMsgSetConsoleFlags(AI_LOG_ALL)
AiLoadPlugins( os.getenv( 'ARNOLD_PLUGIN_PATH' ) )
AiASSLoad("original.1001.ass", AI_NODE_ALL)

#
# Do your edits here
#

AiASSWrite("edited.1001.ass", AI_NODE_ALL, False)
AiEnd()

Soccer balls and Arnold procedurals


I’m partial, but I like the Softimage soccer ball better than the Maya soccer ball.
soccerballs

The Softimage soccer ball is the one on the left. I took the ASS file for the soccer ball, did a few search and replace ops, and compiled my first procedural node. It’s pretty trivial, but it illustrates the basic framework. numNodes() returns the number of nodes you’re going to create; Arnold calls getNode() once for each node you create. I’m just creating one node, so I do it in getNode(), but you could also do it in init().

If you’re interested in learning more about the Arnold SDK and procedurals, you can download the SDK (docs included) at solidangle.com.

#include <ai.h>
#include <string.h>

static int init(AtNode *mynode, void **user_ptr )
{
  AiMsgInfo( "[soccer] -- greetings!" );
  return 1;
}

static int cleanup( void *d )
{
  return 1;
}

static int numNodes( void *d )
{
  return 1;
}

static AtNode *getNode( void *d, int index )
{

	AtByte nsides[540] = {
		4, 4, 4, 4, 4,
		// ...
		4, 4, 4, 4, 4};
  
	unsigned int vidxs[2160] = {
		292, 301, 12, 293, 302, 303, 304, 305, 302, 305, 306,
		//...
		169, 538, 537, 116, 168, 540, 539, 79, 151, 25, 541};

	unsigned int nidxs[2160] = {
		0, 1, 2, 3, 4, 5, 6, 7, 4, 7, 8, 9, 4, 9, 10, 11, 4, 
		// ...
		1211, 1216, 1215, 1230, 1229, 311, 322, 1231, 312};

	float vlist[1626] = {
		2.33102179f, 4.68985701f, -7.74118519f, -4.0108633f, -2.08138514f, 8.18039227f,
		//...
		1.70574367f, 2.03463793f, 9.00535202f, 2.94963598f, 0.0429565944f, 8.85224628f};

	float nlist[3696] = {
		-0.00219265698f, -0.443717808f, -0.896163881f, -0.112498537f, -0.405027777f, -0.907356858f, 
		//...
		-0.316353977f, -0.846433043f, 0.428335458f, 0.514008343f, -0.00765316607f, 0.857751012f};

	AtMatrix m;
	AiM4Identity( m );
	
	AtNode *n = AiNode( "polymesh" );
	AiNodeSetByte(n, "visibility", 255);
	AiNodeSetArray(n, "vlist",  AiArrayConvert(1626,  1, AI_TYPE_FLOAT, vlist));
	AiNodeSetArray(n, "nsides", AiArrayConvert(540,  1, AI_TYPE_BYTE,  nsides));
	AiNodeSetArray(n, "vidxs",  AiArrayConvert(2160,  1, AI_TYPE_UINT,  vidxs));
	AiNodeSetArray(n, "nlist",  AiArrayConvert(3696,  1, AI_TYPE_FLOAT, nlist));
	AiNodeSetArray(n, "nidxs",  AiArrayConvert(2160,  1, AI_TYPE_UINT,  vidxs));
//	AiNodeSetArray(n, "uvidxs", AiArrayConvert(384,  1, AI_TYPE_UINT,  uvidxs));
//	AiNodeSetArray(n, "uvlist", AiArrayConvert(270,  1, AI_TYPE_FLOAT, uvlist));

	AiNodeSetMatrix(n, "matrix", m );

	AiNodeSetStr(n, "name", "SISoccerBall");
	return n;
};



// --------------------------------------------------------------------------------
// dso hook.
// --------------------------------------------------------------------------------
proc_loader
{
  vtable->Init     = init;
  vtable->Cleanup  = cleanup;
  vtable->NumNodes = numNodes;
  vtable->GetNode  = getNode;
  strcpy_s(vtable->version, AI_VERSION);
  return 1;
}