Skip to content

Instantly share code, notes, and snippets.

@erikaderstedt
Created July 11, 2016 15:57
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save erikaderstedt/a4eba3d7f311d7aa7f0cd967d14058c7 to your computer and use it in GitHub Desktop.
Save erikaderstedt/a4eba3d7f311d7aa7f0cd967d14058c7 to your computer and use it in GitHub Desktop.
Core Image kernel for the Genie effect
//
// ASGenieKernel.cikernel
//
// (c) Aderstedt Software AB 2008.
// Erik Aderstedt 2008-09-05.
//
kernel vec4 ASGenieKernel(sampler src, float t, float D, float ytarget, float scale)
{
// Given a point (destCoord) we are tasked to find its colour.
// We do it by finding a source point (takeFrom) and take its
// colour. If no source point can be found, we return the
// colour (0.0,0.0,0.0,0.0).
// Given a point in the original image, where do we end up?
// A transformation from takeFrom -> destCoord.
// At t = 0: destCoord = takeFrom.
// At t = 1: destCoord = (takeFrom - ytarget)*D/ymax + ytarget
// At t = t: destCoord = takeFrom*(1-t) + t*((takeFrom - ytarget)*D/ymax + ytarget)
// = takeFrom*(1-t+t*D/ymax) + t*ytarget-t*ytarget*D/ymax
// = takeFrom*(1-t*(1-D/ymax)) + t*ytarget*(1-D/ymax)
// -> takeFrom.y = (destCoord.y - t*ytarget*(1-D/ymax))/(1-t*(1-D/ymax))
// destCoord.y = ymax, D = 0.04*ymax, t = 0.5 -> (ymax - 0.5*ytarget*0.96)/(1-0.5*0.96). ymax = 1, ytarget = 0.5 -> 0.75/0.5 -> 1.5.
// If takeFrom.y is out of bounds, we set the alpha to 0 and return immediately.
//
// Use an envelope function. From 1 to 0. (1-tan((x/xmax * pi/2) - pi/4))/2.
// Multiply the t value with that in the expression above.
// For t > 1 we also transform the x coordinate using a simple linear transformation.
// At t > 1 the y shape is fixed, so we set t = 1 before applying the envelope (but after
// applying the transformation).
vec2 takeFrom; // In destination coordinates.
vec2 original = samplerCoord(src);
vec2 size;
float g, t2, a;
vec4 c;
size = samplerSize(src);
original = vec2(original.x / scale, original.y / scale);
t2 = compare(t-1.0,t,1.0);
takeFrom.x = original.x + compare(t-1.0,0.0,1.0)*size.x*(t-1.0);
a = compare(takeFrom.x, 0.0, 1.0);
a = compare(a-0.5,0.0,compare(takeFrom.x-size.x, 1.0, 0.0));
// Apply an envelope. This is where non-linearity is introduced.
t2 = t2 * (1.0 - tan_(1.57*original.x/size.x - 0.78539))*0.5;
g = 1.0 - D / size.y;
takeFrom.y = (original.y - t2*ytarget*g)/(1.0-t2*g);
a = compare(a-0.5,0.0,compare(takeFrom.y, 0.0, 1.0));
a = compare(a-0.5,0.0,compare(takeFrom.y-size.y, 1.0, 0.0));
takeFrom.x = compare(takeFrom.x, 0.0, takeFrom.x);
takeFrom.x = compare(takeFrom.x-size.x, takeFrom.x, 0.0);
takeFrom.y = compare(takeFrom.y, 0.0, takeFrom.y);
takeFrom.y = compare(takeFrom.y-size.y, takeFrom.y, 0.0);
takeFrom = vec2(takeFrom.x*scale, takeFrom.y*scale);
c = sample(src, takeFrom);
c.w = a;
return c;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment