A series of image filtering shaders can be grouped and applied sequentially to an image. To do so, add each shader to an IDLgrFilterChain object, which is a specialized type of container designed to hold IDLgrShader objects or objects that subclass from IDLgrShader. Then associate the IDLgrFilterChain object with the IDLgrImage object using the SHADER property. When the scene is drawn, the image data is modified by each shader program according to container order. The output from the first shader is processed by each subsequent shader until all shader programs have been applied. IDL then draws the result to the window.

Note: This functionality requires support for GLSL frame buffer object extension in addition to the standard hardware support required by IDLgrShader. See the IDLgrWindow::GetDeviceInfo methods’s FRAMEBUFFER_OBJECT_EXTENSION keyword for details).

The following example creates an IDLgrFilterChain object and lets you add and remove individual IDLgrShaderConvol3 objects, which provide the ability to apply sharpening, smoothing, and edge detection convolution filters to an image. Like the IDLgrShaderBytscl object, the pre-defined IDLgrShaderConvol3 object includes a software fallback that is automatically used when there is not sufficient hardware support for shader operations.

See Filter Chain Example for more information and additional examples.

Example Code

See shader_filterchain_doc__define.pro, located in the examples/doc/shaders subdirectory of the IDL distribution, for the complete, working example. Run the example by entering obj=OBJ_NEW('shader_filterchain_doc') at the IDL command prompt or view the file in an IDL Editor window by entering .EDIT shader_filterchain_doc__define.pro.

Basic Filter Chain Shader Object Class

The shader_filterchain_doc object class inherits from IDLgrFilterChain, which inherits container manipulation methods from IDL_Container, but also includes the FORCE_FILTER method common to IDLgrShader. This means that you can test any software based alternative code provided in a shader’s Filter method as described in “Providing a Software Alternative to Shaders”. Since this example uses the pre-defined IDLgrShaderConvol3 object, there is no need to specify vertex or fragment programs since these are inherent to the object definition.

In addition to the typical object definition code, this example creates instances of the four types of pre-defined convolution filters and stores them in an object array:

oIdentity = OBJ_NEW("IDLgrShaderConvol3", KERNEL=0)
oSmooth = OBJ_NEW("IDLgrShaderConvol3", KERNEL=1)
oSharpen = OBJ_NEW("IDLgrShaderConvol3", KERNEL=2)
oEdge = OBJ_NEW("IDLgrShaderConvol3", KERNEL=3)
objarray = [oIdentity, oSmooth, oSharpen, oEdge]

Since an unmodified image is loaded first, make sure the identity convolution filter is the only item in the filter chain object (self in the following lines). Then associate the IDLgrFilterChain object with the image using the SHADER property.

self->Add, oIdentity
oImage->SetProperty, SHADER=self

In this program, you can select among four check boxes to apply varying combinations of convolution filters to a grayscale image. Each time you select a different check box, the list of shaders are removed from the IDLgrFilterChain container and then the selected items are re-added.

; Remove all items from the collection and add back
; selected shaders.
self->Remove, /ALL
selected = WHERE(value EQ 1)
IF N_ELEMENTS(selected) GT 1 || selected NE -1 THEN BEGIN
  self->Add, (*pstate).objarray[where (value EQ 1)]
; Update base and covolution factors for all
; selected shaders.
shaderObjs=self->Get(/ALL, COUNT=count)
FOR i =0, count-1 DO BEGIN
    BASE_BLEND_FACTOR=(*pState).basefactor, $
; Draw.
(*pState).oWindow->Draw, (*pState).oView

Note: Shaders are applied in container order. You could use different user interface controls to provide a way to apply shaders in a specific order instead of using check boxes.