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 a .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"

 

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:

#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, 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 *)AiDriverGetLocalData(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);
            driver->names.emplace(name, pixel_node);
         }
      }
   }
}

driver_close
{
   DriverPtrStruct *driver = (DriverPtrStruct *)AiDriverGetLocalData(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 *)AiDriverGetLocalData(node);
   delete driver;
   AiDriverDestroy(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;
}

 

 

  • No labels