NatronGitHub / Natron

Open-source video compositing software. Node-graph based. Similar in functionalities to Adobe After Effects and Nuke by The Foundry.
http://NatronGitHub.github.io
GNU General Public License v2.0
4.7k stars 342 forks source link

(Feature): Optics Compensation Effect. #926

Closed alyfreym closed 1 year ago

alyfreym commented 1 year ago

Make sure to follow our issue report guidelines

Provide a description of your feature request

Hi guys. A lot of transition effects use this effect Called Optics Compensation from Adobe After effects. After many attempts to recreate this effect, nothing works for me. I did something similar but it is doesn't work similar My Code in OpenGL attribute vec3 in_Position; // (x,y,z) attribute vec4 in_Colour; // (r,g,b,a) attribute vec2 in_TextureCoord; // (u,v)

varying vec2 v_vPosition; varying vec2 v_vTexcoord; varying vec4 v_vColour;

` void main() { gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * vec4(in_Position, 1.0);

v_vColour = in_Colour;
v_vTexcoord = in_TextureCoord;
v_vPosition = in_Position.xy;

}

########### FRAGMENT SHADER ############

varying vec2 v_vPosition; varying vec2 v_vTexcoord; varying vec4 v_vColour;

uniform vec2 u_resolution; uniform vec2 u_center; uniform float u_fov; uniform bool u_reverse; uniform float u_border_smoothness; uniform int u_fov_orientation;

uniform float u_test;

void main() { vec2 uv = v_vPosition / u_resolution;

// Calculate direction vector and length
vec2 dir = (uv - u_center);
float r = length(dir);

// Reverse FOV
float fov = u_fov;
if (!u_reverse) fov *= -1.0;

// FOV orientation
/*if (u_fov_orientation == 0) {
    // Horizontal orientation
    //fov *= (u_resolution.y / u_resolution.x);
} else
if (u_fov_orientation == 1) {
    // Vertical orientation
    fov /= (u_resolution.y / u_resolution.x);
} else
if (u_fov_orientation == 2) {
    // Diagonal orientation
    fov *= length(u_resolution) / u_resolution.x; // Pythagorean
}*/

// Convert field of view to radians
float fov_radians = tan(radians(fov) / 2.0); // 180

// Distortion coefficients
float k1 = fov_radians;
float k2 = 0.0;
float k3 = 0.0;
float k4 = 0.0;

// Calculate the distortion using polynomial function
// source: https://docs.nvidia.com/vpi/algo_ldc.html#algo_ldc_polynomial
//float radius = r / (1.0 + k1 * r + k2 * pow(r, 2.0) + k2 * pow(r, 4.0) + k3 * pow(r, 6.0) + k4 * pow(r, 8.0));
float radius = r / (1.0 + k1 * pow(r, 2.0) + k2 * pow(r, 4.0) + k3 * pow(r, 6.0) + k4 * pow(r, 8.0));

// Calculate angle and adjust UV based on distortion
float theta = atan(dir.y, dir.x);
uv = u_center + radius * vec2(cos(theta), sin(theta));

// Texture
vec4 col = texture2D(gm_BaseTexture, uv);

// mask
float smt = u_border_smoothness * 0.5;
col.rgb *= smoothstep(-smt, smt, uv.x*(1.0-uv.x)) *
       smoothstep(-smt, smt, uv.y*(1.0-uv.y)) * step(0.0, radius);

// final color
gl_FragColor = col;

}`

Below my example with FOV 120 example_my

In After effects you can choose FOV from 0 to 180 degrees. FOV Orientation (Horizontal, Vertical, Diagonal) Below animation with FOV from 0 to 180 And Orientation Horizontal.

https://github.com/NatronGitHub/Natron/assets/29518174/7468f554-7635-40f0-afb0-e3098b348703

Is this a realistically implementable feature?

Can you contribute in creating this feature?

Additional details

Any idea how to implement this effect? Thanks for advice

And im trying reverse engineering this effect but because after effects using CPU for all effect it is very strange to understand from assembler what algorithm using

devernay commented 1 year ago

They seem to have a single distortion parameter called "fov", so it's not classical Brown Conrady distortion (k1 K2 etc) Take a look at what I called the "fov model" in Devernay & Faugeras 2001 "straight lines have to be straight". Maybe an Adobe engineer got it from this paper...

alyfreym commented 1 year ago

They seem to have a single distortion parameter called "fov", so it's not classical Brown Conrady distortion (k1 K2 etc) Take a look at what I called the "fov model" in Devernay & Faugeras 2001 "straight lines have to be straight". Maybe an Adobe engineer got it from this paper...

Thanks, I will try FOV model distortion.

alyfreym commented 1 year ago

They seem to have a single distortion parameter called "fov", so it's not classical Brown Conrady distortion (k1 K2 etc) Take a look at what I called the "fov model" in Devernay & Faugeras 2001 "straight lines have to be straight". Maybe an Adobe engineer got it from this paper...

Hi, I changed my algorithm. Looks like this method doesn't apply scale like in After Effects. My example. FOV = 120

`func transform(uv: simd_float2) -> simd_float2 { // Devernay-Faugeras FOV let FOV: Float = Float(fov.radians);

let direction  = (uv - u_center)

let ru        = simd_length(direction) // undistored radius.

let rd = 1.0 / FOV * atan(2.0 * ru * tan(FOV / 2.0))

let theta = atan2(direction.y, direction.x);

let x     = cos(theta) // Convert to Cartesian

let y     = sin(theta) // Convert to Cartesian

return u_center + simd_float2(x, y) * rd

}`

My Result IMG_EFDA6FE24AD0-1

After Effects with the same FOV RESUL_120_FOV

Formula

Screenshot 2023-10-07 at 15 25 27

Aka FOV Model.

Looks like when the value (FOV) increases, scaling is applied Maybe I need orthographic projection with FOV and apply in to my distortion method? Changing camera focus plane relative FOV.

alyfreym commented 1 year ago

Not possible.