I'm trying to replicate effect from Adobe After Effects called "Optics Compensation". I think it is similar to Lens Distortion. But the formulas that are used there do not fit. This effect have a few options to manipulate.This effect has several parameters to change.
- Center
- FOV. aka Field Of View. Value from 0 to 180 degrees.
- FOV Orientation (Horizontal, Vertical, Diagonal)
In this video i animated the FOV value from 0 to 180 degrees; Center = 540,960
Also image example:
It's looks like Barrel distortion or Fisheye distortion.
I tried different formulas. For example "Lens correction model"
But I don't understand how to calculate all these parameters with only FOV and center value.
Does anyone know how to achieve this effect? What formulas should be used? Everywhere it is described how to fix "Lens Distortion". But how to apply such an effect on the picture?
After some Research I found Mathworks implementation for Barrel Transformation. 
Code
[xi,yi] = meshgrid(1:ncols,1:nrows);
xt = xi - ncols/2;
yt = yi - nrows/2;
[theta,r] = cart2pol(xt,yt);
a = 1; % Try varying the amplitude of the cubic term.
rmax = max(r(:));
s1 = r + r.^3*(a/rmax.^2);
[ut,vt] = pol2cart(theta,s1);
ui = ut + ncols/2;
vi = vt + nrows/2;
ifcn = @(c) [ui(:) vi(:)];
tform = geometricTransform2d(ifcn);
I_barrel = imwarp(I,tform,FillValues=fill);
imshow(I_barrel)
My implementation in apple metal
fragment float4 opticsCompensationFragment(metalpetal::VertexOut vertexIn [[ stage_in ]],
texture2d<float, access::sample> inputTexture [[ texture(0) ]],
sampler inputTextureSampler [[ sampler(0) ]]) {
float2 center = float2(0.5, 0.5);
// Shift the origin to the center of the image
float2 st = vertexIn.textureCoordinate - center;
// Convert the Cartesian x- and y-coordinates to cylindrical angle (theta) and radius (r) coordinates
float theta = sqrt(st.x * st.x + st.y * st.y);
float r = atan2(st.y, st.x);
// Try varying the amplitude of the cubic term.
float a = 0.1;
// add a cubic term to r so that r changes nonlinearly with distance from the center pixel.
float s1 = r + (r*r*r)*(a/(r*r));
// Convert back to the Cartesian coordinate system. Shift the origin back
float ut = theta * cos(s1) + center.x;
float vt = theta * sin(s1) + center.y;
return inputTexture.sample(inputTextureSampler, float2(ut, vt));
}
but my result is not like this.
The only difference is that in the code in Mathworks they use meshwarp, but i am trying to implement this using only fragment shader. What could be wrong in my code?


