Houdini Development Toolkit - Version 9.0

Side Effects Software Inc. 2007

Compositing Operators

COP Data Structures



TIL (Tile) Library Classes



TIL_Sequence

This class holds the high level description of the COP's data. This information is constant over the frame range of the COP.
The resolution must be at least 1x1. The Frame Range can either be set to a range or a single image. To specify range, call:
setSingleImage(false);
setStart(start_frame);
setLength(length);
In addition to the frame range, you can also specify how the compositer renders frames outside that range with setTemporalExtend(). You can specify the extend condition for both before and after the range. The extend conditions are:
You can also set up the range as a single image. Single images are time-independent, and exist at every frame. Non-animated mattes and background plates fall into this category. To set up a single image, call:
setSingleImage(true);
Once you have done this, it overrides the frame range amd extend conditions.

Finally, you set up the image planes. Each image plane represents a different type of data on the image - like Color, Alpha, Normal or Depth. All the planes share the same resolution, frame range and extend conditions. You can specify the plane name, vector size, component name(s) and data format individually for each plane. All plane names must be unique (or they will be made unique by appending a number to the end). To add planes to a sequence, call:
TIL_Plane * addPlane(const char *name, TIL_DataFormat format,
             const char *vn1 = 0,
                  const char *vn2 = 0,
                  const char *vn3 = 0,
                  const char *vn4 = 0,
                  bool reorder=false);
TIL_Plane * addPlane(const TIL_Plane *plane,
                 bool reorder=false);
The vector size is determine by the number of component names that are filled in (vn1-4). The name of the plane can be custom, or one of the standard plane names. You can get the plane name from COP2_Node, by calling:
static const char    *getColorPlaneName();
static const char    *getAlphaPlaneName();
static const char    *getMaskPlaneName();
static const char    *getDepthPlaneName();
static const char    *getLumPlaneName();
static const char    *getBumpPlaneName();
static const char    *getPointPlaneName();
static const char    *getNormalPlaneName();
static const char    *getVelocityPlaneName();
For more information on planes, see TIL_Plane below.

TIL_Plane

A TIL_Plane structure contains the definition of an image plane. Planes can be scalar (like Alpha) or vector (like Color; R,G,B). Vectors of up to 4 components are supported. You can also arrange planes into arrays, though this is rarely used. Each plane has its own data format, and names for its components.

The name of the plane can be custom, or one of the standard plane names. You can get the plane name from COP2_Node, by calling:
static const char    *getColorPlaneName();
static const char    *getAlphaPlaneName();
static const char    *getMaskPlaneName();
static const char    *getDepthPlaneName();
static const char    *getLumPlaneName();
static const char    *getBumpPlaneName();
static const char    *getPointPlaneName();
static const char    *getNormalPlaneName();
static const char    *getVelocityPlaneName();
Next, specify the data format of the plane, which can be one of:
Finally, you specify the names of the components. If your plane is a scalar plane (vector size 1), you do not need to specify a name for the first component. Common component names are r, g, b, x, y, z, and w.

For integer formats, you can also specify black and white points. By default, they are set to the minimum and maximum representable values. However, you can set them to any value in between to be able to represent values greater than white or darker than black. To do this, use:
void        setBlackWhitePoints(unsigned int b, unsigned int w);
To unscope planes for cooking, use the following methods:
void setScoped(int enable);
void setPlaneMask(int enable, int i);
By default, all planes are scoped upon creation. You can unscope the entire plane or just specific components. Unscoped components and planes will not be modified by COP filters and passed through as-is.

TIL_Tile

TIL_Tile's contain the image data that the COPs engine processes. Each tile contains one component of one plane in an area of the output image, at a certain frame. These tiles are arranged into TIL_TileLists, which contain up to 4 tiles (one for each component of a TIL_Plane).

For the most part, you will only be interested in getting at the data from the tiles with getImageData(). By default, tiles are 200x200, but near the edges of images this can change (and it is a preference as well).

Tiles are very low level classes to work with, as the data is always in the data format specified by the plane, and neighbouring pixel algorithms are difficult to write within tiles. For this reason, it is often easier to use TIL_Region's to get at the input data, which allow you to grab an arbitrary area of the input (and convert it to other formats as well).

The most important functions in TIL_Tile are the getImageData() methods. Another important method is the isConstantTile() method, which returns true if the tile's image data is all set to a single value. This can be used for optimizing algorithms. Most of the other methods are only used by the compositing engine.

TIL_TileList

A TIL_TileList is a simple vector wrapper for 1 to 4 tiles. It contains a lot of useful member data collected from the tiles, and some convienience functions. Whenever you request a 'tile', you will get a tilelist back. Each tile contains one component of the plane, listed in the tilelist. The important member data is:

TIL_Tile *myItems[PLANE_MAX_VECTOR_SIZE]
The list of tiles in the tilelist.
const TIL_Plane *myPlane
The plane that these tiles are from.
short myArrayIndex
The array index of the plane.
int mySize
The number of pixels in the tile.
int myX1, myY1, myX2, myY2
The area in the image that the tile represents.
char myUsePoints
Black/White point usage flag
unsigned int myBlack, myWhite
The black and white points of the data (integer only)

The useful methods are:
Returns true if the tilelist contains the pixel (x,y).
Creates a TIL_Region which references the data in the tiles. This is useful for running code on TIL_TileList's that only works with TIL_Region's. Use TIL_Region::freeRegion() to deallocate the region when finished.
This method checks to see if the region is constant on all components. If it's not, it returns false. Otherwise, it marks all the tiles as constant and fills them with the constant color of the region (if black is false) or black (if black is true). This is useful for optimizing algorithms. For example, a blur operation can be optimized out if the input region is entirely constant. An edge detect operation can be optimized out as well, but instead of filling with the region color, it would fill with black.
Clears the tiles to black. Tiles are not cleared when you receive them in your cook method, so if you don't want to produce any output, you should clear them. If markconstant is true, the tiles are also marked as constant tiles. You will want to pass markconstant as false if you are just clearing them before operating on them.
Returns true if the TIL_TileList doesn't have any tiles in it. You will rarely need to use this method (if ever).

TIL_Region

Regions are the most versatile way to access input data. They allow you to grab any arbitrary area of the input, in any data format. Unlike tiles, they contain all the components of the plane they are extracting data from. TIL_Region's are returned by the COP2_Node methods inputRegion(), transformRegion() and outputRegion().

Useful TIL_Region methods:
Returns the plane that this region is fetching data from. Useful for checking the data format.
Returns the area the region occupies, (x1,y1)-(x2,y2) inclusive.
Gets the image data for the component specified (either by index or name).
For more details on using TIL_Region's for input, see Cooking, Input Functions.

TIL_Fill

This class and its parameter class (TIL_FillParms) are used to fill an area with a different area, convert data types, clear data, invert values, and multiply/divide by constants or arrays. It's sort of a swiss army knife class for many common operations. The TIL_Fill 'class' is actually a collection of static methods to do specific tasks:
    static void	fill(const TIL_FillParms &parms);
static void clear(const TIL_FillParms &parms);
static void invert(const TIL_FillParms &parms);
static void multiply(const TIL_FillParms &parms);
static void divide(const TIL_FillParms &parms);
The real interface is found in the TIL_FillParms class, which contains all the parameters for the operation (instead of having a fill() function with 30 parameters). The source and destination parameters are almost mirrors of one another (the destination parms are shown):
    const void		*myDest;
TIL_DataFormat myDType;
int myDX1, myDY1;
int myDX2, myDY2;
unsigned int myDBlack, myDWhite;
int myDInc;
int myDFast;
myDest is the pointer to the destination pixel array. myDType, myDFast, myDBlack and myDWhite all determine the data format of the pixels (myDType = TILE_INT8, TILE_INT16, TILE_INT32, TILE_FLOAT16, or TILE_FLOAT32; if myDFast is true, then black/white points are used for the integer formats, which are specified in myDBlack and myDWhite). The myDInc parameter specifies the offset between adjacent pixel values; this is useful for interleaving and deinterleaving data (to extract R out of interleaved RGB, use mySInc = 1 and myDInc = 3). Finally, the myDX1, myDY1, myDX2, myDY2 parameters represent the area that the pixel array represents.

For fill(), the source and destination areas don't need to match or even overlap - the filling will be handled appropriately (this is useful for extracting areas out of a raster, or putting tiles back into a raster). You can also set mySVInc and mySVOff, to extract interlaced scanlines (mySVInc = 2, mySVOFF = 1 or 0, depending on whether you want the odd or even scanline).

You can also do some minor translates on the image, with the parameters myXShift and myYShift. The source area will be shifted by these values (by default they are zero). You can also flip the source area horizontally and/or vertically with myXFlip and myYFlip (boolean values). A gamma can be applied to the fill using myGamma.

For the clear() method, the source area is the area to clear, and the dest area is the size of the pixel area. You can clear components (with myDInc set to the vector size) and subareas (with a smaller source area).

The invert() method only uses the destination parms. All the pixel values are inverted (1-p) and multiplied by the fill color (myFillColor).

The multiply() and divide() methods use only the destination parms and the multiplication parms (myMultPerPixel, myMultFactor, myMultData). If myMultPerPixel is true, then an array of floats the size of the destination area, stored in myMultData, is multiplied by destination pixels. If myMultPerPixel is false, the destination pixels are multiplied by a constant myMultFactor. For divide(), division is performed instead of multiplication.

TIL_Pixel

This template class is used to convert single values to and from floating point. To use it, declare the TIL_Pixel with the data type you want, and whether to use the 'fast' conversions (1) or not (0). The fast conversions do not take the integer black/white points into account. For example, to convert 8bit int to floating point:
TIL_Pixel<unsigned char, 1> pixel;
unsigned char data = 125;

pixel.set(data);

float_value = pixel;
You can also use TIL_Pixel to convert back to the original format:
pixel = float_value;
data = pixel.getValue();
To use TIL_Pixel with black/white points, only a small change is required to the declaration:
TIL_Pixel<unsigned char, 0> pixel(64, 192);
First is the change in the 'fast' template parameter, which tells it to use the slower black/white point conversion methods. Second, the black and white points are passed to the constructor. Floating point formats do not support black/white points, so 'fast' and the black/white point parameters are ignored.

TIL_Pixel's are very useful inside the templated RU_Algorithm classes, as you can declare them as "TIL_Pixel<type, fast> pixel" and then use them as above.


RU (Raster Utility) Library classes



RU_Algorithm

This is the interface for templated algorithms. The RU_Algorithm class by itself isn't templated; it manages the algorithm parameters and selects the templates to use based on the input provided.

To create a templated algorithm, you need to create at least 2 classes - one subclassed from RU_Algorithm (found in RU_Algorithm.h), and one subclassed from one of the following template classes (found in RU_AlgorithmTemplates.h). The RU_Algorithm subclass should contain all the parameters required for the templated operation - it will refer to this class for parameter data.

RU_GeneratorOp<class Type, int fast>

This class provides a virtual method to generate data:
    virtual int	 generate(TIL_TileList * output, float t, int thread, void *data)
Override it and define your operation, writing your data to the tiles in output. The time (t) and thread you're cooking in (thread) are also provided. The data parameter is discussed below.

Next, to call this method, you need to use the RU_Algorithm method:
    int		generate   (TIL_TileList *output, float t, void *ndata, int thread, void *data);
output is the tilelist to modify, t is the time, ndata is a pointer to the COP node calling this method, thread is the thread index that it is cooking in (from context.myThreadIndex) and data is a pointer to user defined data that is passed to RU_GeneratorOp::generate() as the last parameter.

RU_PixelOp<class Type, int fast>

This class provides a virtual method for processing pixel data on an input:
virtual int pixelAdjust(TIL_TileList *output, const TIL_TileList *input, float t, int thread, void *data)
Unlike the generator, the pixel operation has an input tile list to use. To call this method in RU_Algorithm, use:
int pixelAdjust(TIL_TileList *output, const TIL_TileList *input, float t, void *ndata, int thread, void *data)
All the parms are the same as the generator version, except for input, which are the input tiles to read from.

RU_FilterOp<class Type, int fast>

This class is similar to RU_PixelOp, but instead of an input tilelist, it uses regions. There are also two signatures, one for an output tilelist, and one for an output region.
virtual int filter(TIL_TileList *output, const TIL_Region *input,float t, int thread, void *data)

virtual int filter(TIL_Region *output, const TIL_Region *input, float t, int thread, void *data)
To call one of these methods, use the corresponding RU_Algorithm method:
int filter(TIL_TileList *output, const TIL_Region *input, float t, void *ndata, int thread, void *data)

int filter(TIL_Region *output, const TIL_Region *input, float t, void *ndata, int thread, void *data)
If you don't intend on calling the one of the signatures, you don't need to implement that signature in your RU_FilterOp subclass.

RU_BinaryOp<class Type, int fast>

Finally, the last template class is a binary operation, with one output and two inputs. It also has two signatures, one for an output tilelist and one for an output region.
virtual int binary(TIL_TileList *output, const TIL_Region *fore, const TIL_Region *back, float t,int thread, void *data)

virtual int binary(TIL_Region *output, const TIL_Region *fore, const TIL_Region *back, float t,int thread, void *data)
These correspond to the RU_Algorithm methods:
int binary(TIL_TileList *output,const TIL_Region *fore,const TIL_Region *back,float t,void *ndata,int thread,void *data)

int binary(TIL_Region *output,const TIL_Region *fore,const TIL_Region *back, float t,void *ndata,int thread,void *data)
Again, you only need to define the RU_BinaryOp method you are going to use.

Putting the Template Algorithm Together

You need to derive two classes, one from RU_Algorithm (the public interface class) and one from one of the above template classes (depending on what situation you have; 0, 1 or 2 inputs). The template class is the one that does the work, and it is hidden behind the public RU_Algorithm subclass.

A simple example:
// Declare our public interface class, a collection of parameters for the operation.
class RU_RandNoise : public RU_Algorithm
{
int mySeed;
float myScale;
float myShift;
};

// Declare our private worker template class.
template<class Type, int fast> class RU_RandNoiseOp : public RU_GeneratorOp<Type, fast>
{
RU_RandNoiseOp(RU_Algorithm *alg) : RU_GeneratorOp<Type,fast>(alg) {}

virtual int generate(TIL_TileList *output, float t, int thread, void *);
}

template<class Type,int fast> int
RU_NoiseOp<Type,fast>::generate(TIL_TileList *tilelist, float , int , void *)
{
RU_RandNoise *parms = dynamic_cast<RU_RandNoise *>(RU_GeneratorOp<Type, fast>::myAlg);
TIL_Pixel<Type, fast> pixel(tilelist->myBlack, tilelist->myWhite);
TIL_Tile *tile;
Type *data;
float noiseval;

FOR_EACH_UNCOOKED_TILE(tilelist, tile)
{
data = (Type *) tile->getImageData();
for(i=0; i<tilelist->mySize; i++)
{
// generate noise with parms->mySeed, parms->myScale, parms->myShift and stick the
// result in 'noiseval'.
pixel = noiseval;
data[i] = pixel.getValue();
}
}
return 1; // success
}

// How to call the algorithm from a cook method.
OP_ERROR
COP2_RandNoise::doCookMyTile(COP2_Context &context, TIL_TileList *tiles)
{
cop2_RandNoiseData *data = dynamic_cast<cop2_RandNoiseData *>(context.data());

// more likely, this would have been a member variable of our cop2_RandNoiseData context data,
// having been initialized in newContextData().
//
RU_RandNoise noisealg;

noisealg.mySeed = data->mySeed;
noisealg.myScale = data->myScale;
noisealg.myShift = data->myShift;

noisealg.generate(tiles, context.myTime, this, context.myThreadIndex);

return error();
}

RU_PixelFunction

Pixel Functions are very fast, input-to-output pixel algorithms. Gamma, Brighten and HueShift are examples of pixel functions. They only require a single input pixel (corresponding to the output pixel produced) and some parameters.

This class is discussed thoroughly in context in Pixel Function COPs.



COP2 Library Classes



COP2_Context

The COP2_Context class contains all the information that you need to cook an image. It is generated by the COP engine based on the requirements of the cook and passed to most cooking methods. You should never create or delete one of these objects.

A COP2_Context contains:
The only operation you will do on the COP2_Context is to set the image bounds, in the virtual method COP2_Node::computeImageBounds(). All the rest of the information is read-only.

COP2_ContextData

A COP2_ContextData class is a base class used for storing parameter values and pre-setup information needed for a cook. You will need to derive a class from it if you would need to evaluate parameters in the cook method (which is not allowed).

The base class provides some virtual methods to control the creation of context data objects:
Why would you need to override these? Here are some situations:

When you create your new context data class for your node, you only need to add data members which you'll be initializing in COP2_Node::newContextData() and reading in the cook methods. See Context Data Creation for more information.

COP2_CookAreaInfo

COP2_CookAreaInfo objects are used by the COP2_Node method getInputDependenciesForOutputArea(). They are similar to COP2_Context objects as they share a lot of the same data, except that they represent an area of an input plane to be cooked at a certain frame. This object is an input dependency.

Most of the time, you will only need to use the enlargeNeededArea() and expandNeededArea() methods to manipulate the area of an COP2_CookAreaInfo object. However, you also may need to create a new COP2_CookAreaInfo object to represent a new dependency (especially if you are referencing a frame at a different time). In this case, you will need to create a new COP2_CookAreaInfo object. It is best to base it off of an input COP2_CookAreaInfo object that best matches the dependency you want to create.

For example, to reference the color plane at the previous frame:
// cplanedep is the COP2_CookAreaInfo object that represents the color plane at the cook time.
time = cplanedep.getTime() - 1.0f / fps;

// grab the previous frame's bounds, in case they differ.
getInputBounds(0, cplanedep.getPlane(), cplanedep.getArrayIndex(), time, cplanedep.getFrameXRes(), cplanedep.getFrameYRes(),0,
bx1,by1,bx2,by2);

area = new COP2_CookAreaInfo(cplanedep.getNode(), cplanedep.getPlane(), cplanedep.getArrayIndex(), bx1, by1, bx2, by2,
cplanedep.getFrameXRes(), cplanedep.getFrameYRes(), cplanedep.getTime() - 1.0f / fps);
if(area)
area->enlargeNeededArea(output_area);
For more information on using this class, see Determine Data Dependencies.

COP2_TransformParms

This class is the parameter interface to doing 2D Transforms. You can do a normal or motion blurred transform. This class is used by the COP2_Node method transformRegion().

The normal 2D transform parameters are:
There are also parameters to specify the filtering done, and how the transformed image behaves outside its bounds:
Finally, you can specify parameters for motion blur:
See Input Functions for more information on transformRegion().

Table of Contents
Operators | Surface Operations | Particle Operations | Composite Operators | Channel Operators
Material & Texture | Objects | Command and Expression | Render Output |
Mantra Shaders | Utility Classes | Geometry Library | Image Library | Clip Library
Customizing UI | Questions & Answers

Copyright © 2007 Side Effects Software Inc.
477 Richmond Street West, Toronto, Ontario, Canada M5V 3E7