Wednesday 7 March 2012

A simple shader

I wrote this shader a few days ago, but didn't want to write about it until I was able to demonstrate it working, which I did in yesterday's post. Now that's done I can describe the shader it used in more detail. It's a very simple shader, that desaturates whatever it's applied to on a scale between 0 (no effect) and 1 (greyscale).


I wrote it for this blog, but it's likely I will use it or one based on it in the future. It could be used at the end of a game or when a game is paused to indicate the game has stopped while still showing gameplay or the game state, or could be used as part of a fade-out between levels.

It consists of three main parts.


The first part, the header, describes the to a tool that uses it such as the Pixel Bender Toolkit. As far as I can tell it is ignored by Flash.


The second part is the parameter block, where inputs are listed. This shader has only one parameter, fAmplitude, which is accessed using ActionScript as described yesterday. The additional fields are used in the Pixel Bender but are not that important in Flash where the value is set by ActionScript. The input and output are mandatory and correspond to the source image data (whatever the filter is applied to) and the output pixel for the shader operation.


The third part is the code of the shader. This consists of a function evaluatePixel which runs on every pixel of the output image, using the whole of the input image, the coordinates of the output pixel and any parameters as input. This shader generates the output pixel from the same pixel of the input image using sampleLinear but in general it could use any pixel or pixels, even from additional image sources.


The code is simple and commented, so I will not try and describe it further. The Pixel Bender Toolkit comes with a comprehensive reference, while the language is very straightforward and intuitive compared to ActionScript.


This example barely scratches the surface of what's possible with shaders. A shader can perform much more complex calculations that distort, blur or apply other complex effects, all running on the GPU so with minimal impact on game code. Some samples come with the Pixel Bender Toolkit, others are here.


Once you've created a filter save it as a text file with a 'pbk' extension then load it into Pixel Bender Toolkit to test it, tweak it and export it to a .pbj file. In addition to using the web files can be converted to Base64, at least on a Mac, using a command line like the following:


openssl base64 -in Desaturate.pbj -out Desaturate.b64

The shader source:


<languageVersion: 1.0;> 

// desaturate: make an image greyscale
kernel desaturate
<   namespace : "Q";
    vendor : "JWB Software";
    version : 2;
    description : "desaturate"; >
{
// an input parameter which specifies the magnitude of the effect
    parameter float fAmplitude
    <
        minValue:float(0.0);
        maxValue:float(1.0);
        defaultValue:float(0.5);
    >;
    
    input image4 oImage;
    output float4 outputColor;


    // evaluatePixel(): The function of the filter that does the 
    //                  processing of the image. It is called once 
    //                  for each pixel of the output image.
    void
    evaluatePixel()
    {   
        // get the source pixel
        float4 sampleColor = sampleLinear(oImage, outCoord());


        // generate a greyscale value: note the weightings
        float fGrey = 0.3 * sampleColor.r + 0.59 * sampleColor.g + 0.11 * sampleColor.b;


        // make a 4vector out of it
        float4 vGrey = float4(fGrey, fGrey, fGrey, 1.0);


        // blend the source and greyscale colours and write it out
        outputColor = (1.0 - fAmplitude) * sampleColor + fAmplitude * vGrey;
    }
}


No comments:

Post a Comment