Assuming your current centre is e.g. wherever the mouse cursor currently is, for ease of understanding...
For each source pixel:
pushVector, a vector passing through the centre and the source pixel position.
- Store its magnitude as
distanceFromCentre, then normalise the vector.
- Apply some function used to produce
pushMagnitude from length
distanceFromCentre. This should result in 0 for any pixel that lies on the lens' radius (
lensRradius), and a large amount for any pixel which is very close to the centre (
0). The function used to map
pushMagnitude is up to you, but I suspect a tangent function would give a spherical look.
pushVector; plot your source pixel colour here.
You need to map your input range for
tan, correctly. As you know,
tan maps to 0 at 0 degrees and infinity at 90 degrees. This refers to the edge of your circle and the centre, respectively: While a pixel exactly on the radius does not shift at all, any vector exactly at the centre of the lens could not be pushed outward in any given direction (i.e. we could not choose a
pushVector for it), hence infinity. This means that you need to remap your
distanceFromCentre which ordinarily lies in range
0->r to a new range
A pixel / fragment shader can be used for this; sometimes it is easier to get a feel for the basic algorithm in something like Processing or Flash first, and then translate it into a shader kernel... just a thought.
Remember that you do not have to process the whole screen, only the bounding box that will contain your lens-effect radius.
** Pseudocode **
distanceFromCentre = pushVector.magnitude(); //range to 0->1 for ease of manipulation
fractionDistanceFromCentre = distanceFromCentre / lensRadius;
fractionDistanceFromRadius = 1 - fractionDistanceFromCentre; //reverse the mapping
pushMagnitude = tan(fractionDistanceFromRadius * PI / 2); //radians; or 90 degrees
pushVector *= pushMagnitude;
plotPosition = centre + pushVector;
plotAt(plotPosition); //draw the pixel at it's final position.