Simple Driver - Arnold Developer Guide
Writing an output driver
An output driver gives you access to the one filtered value per pixel, after a bucket has been completely rendered. You can use drivers for example to write to new image file formats, or to send pixels to a display device, to an application's window, etc.
You can specify a driver in an .ass file like this:
outputs 1 1 STRING
"RGBA RGBA my_main_filter my_main_driver"
You can also specify multiple drivers for different AOVs, potentially using different filters and data types:
outputs 3 1 STRING
"RGBA RGBA my_filter my_main_driver"
"direct_diffuse RGBA my_filter my_direct_diffuse_driver"
"indirect_diffuse RGBA my_filter my_indirect_diffuse_driver"
Example Driver
The implementation of a sample driver that writes out to a file a list of all the objects in a pointer AOV would look like:
pointer_driver.cpp
#include <ai.h>
#include <strings.h>
#include <fstream>
#include <unordered_map>
// This driver will write to a file a list of all the objects in a pointer AOV
AI_DRIVER_NODE_EXPORT_METHODS(DriverPtrMtd);
namespace ASTR {
const AtString name("name");
const AtString filename("filename");
};
typedef struct {
std::unordered_map<AtString, AtNode*, AtStringHash> names;
} DriverPtrStruct;
node_parameters
{
AiParameterStr(ASTR::filename, "objects.txt");
}
node_initialize
{
DriverPtrStruct *driver = new DriverPtrStruct();
// initialize the driver
AiDriverInitialize(node, false);
AiNodeSetLocalData(node, driver);
}
driver_needs_bucket
{
return true;
}
driver_process_bucket
{ }
node_update
{ }
driver_supports_pixel_type
{
// this driver will only support pointer formats
return pixel_type == AI_TYPE_POINTER || pixel_type == AI_TYPE_NODE;
}
driver_open
{
// this driver is unusual and happens to do all the writing at the end, so this function is
// empty.
}
driver_extension
{
static const char *extensions[] = { "txt", NULL };
return extensions;
}
driver_prepare_bucket
{ }
driver_write_bucket
{
DriverPtrStruct *driver = (DriverPtrStruct *)AiNodeGetLocalData(node);
const void *bucket_data;
// Iterate over all the AOVs hooked up to this driver
while (AiOutputIteratorGetNext(iterator, NULL, NULL, &bucket_data))
{
for (int y = 0; y < bucket_size_y; y++)
{
for (int x = 0; x < bucket_size_x; x++)
{
// Get source bucket coordinates for pixel
int sidx = y * bucket_size_x + x;
// Because of driver_supports_pixel_type, we know pixel is a
// pointer to an AtNode.
AtNode* pixel_node = ((AtNode **)bucket_data)[sidx];
const AtString name = AiNodeGetStr(pixel_node, ASTR::name);
if (pixel_node != nullptr)
AiMsgDebug("[driver_ptr] %s", name.c_str());
driver->names.emplace(name, pixel_node);
}
}
}
}
driver_close
{
DriverPtrStruct *driver = (DriverPtrStruct *)AiNodeGetLocalData(node);
std::ofstream myfile(AiNodeGetStr(node, ASTR::filename));
for (auto &i : driver->names)
myfile << i.first << ":\t " <<i.second << std::endl;
myfile.close();
}
node_finish
{
// Free local data
DriverPtrStruct *driver = (DriverPtrStruct *)AiNodeGetLocalData(node);
delete driver;
AiNodeDestroy(node);
}
node_loader
{
if (i>0)
return false;
node->methods = (AtNodeMethods*) DriverPtrMtd;
node->output_type = AI_TYPE_NONE;
node->name = "driver_ptr";
node->node_type = AI_NODE_DRIVER;
strcpy(node->version, AI_VERSION);
return true;
} true;
}
For the above driver, we need to choose the correct output AOV to feed data to the driver. Here is an example .ass file that sets up a simple cube and the driver to output the object AOV to a file
options
{
AA_samples 3
outputs 2 1 STRING
"RGBA RGBA g_filter main_driver"
"object POINTER c_filter obj_driver" # Set the output for the driver and make sure we are feeding the object aov to it
}
closest_filter
{
name c_filter
}
# our custom driver
driver_ptr
{
name obj_driver
filename "test_objs.txt" # write out to a file called test_objs.txt
}
gaussian_filter
{
name g_filter
width 3
}
driver_tiff
{
name main_driver
filename "testrender.tif"
}
persp_camera
{
name mycam
position
3 3 3
look_at
0 0 0
}
box
{
name mycube
min
-1 -1 -1
max
1 1 1
}
The output of the driver will then print something like the following to the output file name.
mycube: 0x7f5db73cb3c0