PixelFilterHandler
PixelFilterInterface

Availability LightWave 6.0 | Component Layout, Modeler | Header  lwfilter.h

Pixel filters apply image processing effects to individual pixels in the rendered image.

Pixel filters look like image filters at first glance, but they differ in several significant ways. Pixel filters can modify any of the buffers, not just the red, green, blue and alpha values, and they have access to the raytracing functions. They're applied during rendering, before antialiasing and motion blur, so their effects are automatically accumulated by Layout for antialiasing and motion blur purposes.

Unlike image filters, which have access to the entire image and are called once per frame, pixel filters only evaluate, and only have access to, a single pixel sample at a time, and they can be called multiple times per pixel during the rendering of a frame.

Handler Activation Function

   XCALL_( int ) MyPixelFilter( long version, GlobalFunc *global,
      LWPixelFilterHandler *local, void *serverData );

The local argument to a pixel filter's activation function is an LWPixelFilterHandler.

   typedef struct st_LWPixelFilterHandler {
      LWInstanceFuncs *inst;
      LWItemFuncs     *item;
      LWRenderFuncs   *rend;
      void            (*evaluate) (LWInstance, const LWPixelAccess *);
      unsigned int    (*flags)    (LWInstance);
   } LWPixelFilterHandler;

The first three members of this structure are the standard handler functions. In addition to these, a pixel filter provides an evaluation function and a flags function.

The context argument to the inst->create function is a pointer to an integer containing context flags. If the LWFCF_PREPROCESS flag is set, the instance is being created for an image other than the rendered output, and buffers other than the RGBA of the image won't be available.

A pixel filter can be activated by both Layout and Modeler. When activated by Modeler, the LWItemFuncs pointer in the local data is NULL. Be sure to test for this before filling in the useItems and changeID fields. Note too that if your pixel filter relies on Layout-only globals, those won't be available when Modeler calls your callbacks.

evaluate( instance, access )
This is where the pixel filter does its work. For each frame, the filter is given access to the red, green, blue and alpha values of each pixel sample, along with any other pixel data requested by the flags function. The access structure, described below, provides pixel information and functions for examining the buffers and writing new values.
flags( instance )
Returns an int that tells the renderer which buffers the pixel filter will examine and/or modify and whether the evaluation function will call one of the raytracing functions in the access structure. The return value contains bitfields combined using bitwise-or. See the image filter page for a list of the buffer codes. In addition to these, the LWPFF_RAYTRACE flag indicates that the evaluation function will call the raytracing functions.

Interface Activation Function

   XCALL_( int ) MyInterface( long version, GlobalFunc *global,
      LWInterface *local, void *serverData );

This is the standard interface activation for handlers.

Pixel Access

The pixel access structure passed to the evaluation function contains the pixel coordinates for the sample, functions for getting and setting pixel values, and the raytracing functions. Because the sampling of the output image is adaptive, pixel positions may be evaluated in any order, multiple times, or not at all. The evaluation function must call setRGBA for every pixel it evaluates, even if the filter doesn't modify the pixel.

   typedef struct st_LWPixelAccess {
      double            sx, sy;
      void             (*getVal)  (int type, int num, float *);
      void             (*setRGBA) (const float[4]);
      void             (*setVal)  (int type, int num, float *);
      LWIlluminateFunc *illuminate;
      LWRayTraceFunc   *rayTrace;
      LWRayCastFunc    *rayCast;
      LWRayShadeFunc   *rayShade;
   } LWPixelAccess;
sx, sy
Image coordinates of the sample, in pixel units. These will often contain fractional values.
getVal( type, buflen, buf )
Get a pixel value from one of the buffers. If the buffer type is invalid or a type not requested by the flags function, the pixel value returned in buf is undefined. See the image filter page for the list of buffer types. buflen is the number of contiguous values to return. For most buffers, this number will be 1, but the RGB buffers can be retrieved all at once. With a type of LWBUF_RAW_RED, for example, the number can be up to 3 to get RAW_RED, RAW_GREEN and RAW_BLUE, and for LWBUF_RED it can be up to 4, for the RGBA values.
setRGBA( rgba )
The RGBA (red, green, blue and alpha) output of the pixel filter. This must be called even if the filter doesn't modify the values.
setVal( type, buflen, buf )
Write a value to one of the buffers.
lit = illuminate( lightID, position, direction, color )
len = rayTrace( position, direction, color )
len = rayCast( position, direction )
len = rayShade( position, direction, shaderAccess )
These functions trace rays into the scene. See the raytracing functions page for details. You can only use these if the return value of your flags function includes the LWPFF_RAYTRACE flag.

Example

The zcomp sample includes a pixel filter that composites the render with an image sequence using the LWBUF_DEPTH buffer. zcomp compares the depth at each pixel with the corresponding depth in the image to be composited, and substitutes the image pixel if it's nearer in z order to the camera.

The mandfilt sample turns LightWave into a Mandelbrot set renderer. Unlike most real pixel filters, it simply overwrites the pixel values with its own output, so it should be run in an empty scene. But it does demonstrate how pixel filter output is antialiased and adaptively sampled by LightWave.