Updated: 17/11/2011
First up here is the demo:
click here
Controls:
Mouse to move camera
Mouse wheel to zoom
Space bar to toggle mouse movement
check box to turn the post processing on or off
number 0-9 on keyboard to try some preloaded filters (emboss, blur, edge detection etc…)
slider to control the sample offset
you can enter your own values into the matrix if you like, but be nice as there isn’t any error checking
let me know if it works for you!
will need flash player 11 to view
get flash player
video of it running if the demo fails:
So what is a convolution filter and how does it work?
Basically a convolution filter (with regards to images) is where for each pixel to be sampled, a set of surrounding pixels is also sampled. The influence of the surrounding pixels is controlled by a matrix.
i.e.
[0,0,0,
0,1,0,
0,0,0]
The current pixel is represented by the middle value.
The 1st value in the matrix is a sample taken from the pixel North-West of the current pixel
2nd is North
3rd is North-East
4th is East
…
i.e.
[NW, N, NE,
W , x, E
SW , S, SE]
x = the current pixel
so the positions in the matrix determine where the samples come from and the values in the matrix determine their influence.
in the matrix
[0,0,0,
0,1,0,
0,0,0]
all the surrounding pixels will have no (0) influence on the output
with the following matrix
[1,1,1,
1,1,1,
1,1,1]
they all have equal weighting effectively blurring the image
various effects can be achieved by using difference weight combinations such as edge detection and sharpening.
How to do it with the AGAL helper:
simply call:
AGAL.convolve(output, sample, texture, uv, offset, matrix)+
where output is the destination register
where sample is a temporary register for storing the modified uvs
where texture is the texture to sample from
where uv is the current uv coord of the sample (usually passed from the vertex shader)
where offset* is the value to offset the samples by (you will need to calculate this with something like 1/viewportWidth)
where matrix** is the convolution matrix
*at the moment the same offset is used for x and y when in reality there should be two (one for each axis) will add this in at a later date as it hasn’t caused an issue so far.
**
sample code to upload a matrix of 9 values from a vector of numbers called “_filter” into fragment constant 0 – 2:
context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, Vector.<Number>([_filter[0],_filter[1],_filter[2], 1])); context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 1, Vector.<Number>([_filter[3],_filter[4],_filter[5], 1])); context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 2, Vector.<Number>([_filter[6],_filter[7],_filter[8], 1])); |
for this to work properly you should normalise you matrix so that the sum of the values in your matrix == 1.
here is some code to do that:
var sum:Number = 0; for(var i:int = 0 ; i < _filter.length; i++) { sum += _filter[i]; } for(i = 0 ; i < _filter.length; i++) { if(_filter[i] != 0 && sum != 0)_filter[i] /= sum; } |
this would turn the matrix
[1,1,1,
1,1,1,
1,1,1]
into
[1/9,1/9,1/9,
1/9,1/9,1/9,
1/9,1/9,1/9]
good luck 🙂