Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question Representing Lens Distortion coordinates in 2D I with my custom lens shader - What am I doing wrong?

Discussion in 'Image Effects' started by kankeus, Feb 9, 2021.

  1. kankeus

    kankeus

    Joined:
    Dec 3, 2013
    Posts:
    12
    Hi,

    I am experimenting with something lens and UI related and I have a 'strange' problem:



    Scenario:

    - I have a grid/checkerboard (black/blue) in 3D space to visualize the lens distortion.
    - I want to represent the distortion in 2D space (Canvas) by converting the checkerboard from world space to canvas (red grid).

    The checkerboard and the red grid should match each other.

    I have done this by using the same distortion algorithm with my shader and the C# script that generates the red UI grid.

    The 2D representation of the camera is working great without my shader, but when I enable the shader, it works as if it is inverted (as seen in the gif above).
    I have simplified the shader algorithm to show the problem easier here.

    The shader logic:



    Code (CSharp):
    1.         float2 GetSimpleDistortion(float2 uv) {
    2.             float2 center = float2(0.5, 0.5); // Center of the screen
    3.             float2 d = uv - center; // Distance vector from center
    4.             float r = sqrt(d.x * d.x + d.y * d.y); // Distance from center (hypothenusa)
    5.             float2 newuv = float2(0.0, 0.0);
    6.  
    7.             newuv.x = uv.x + d.x * r * r * _simpleK; // move away from the center
    8.             newuv.y = uv.y + d.y * r * r * _simpleK;
    9.  
    10.             return newuv;
    11.         }
    12.  
    13.  
    14.  
    15.  
    16.         float4 LensEffectFragmentProgram(PostProcessVaryings input) : SV_Target
    17.         {
    18.             UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
    19.  
    20.             float2 uv = UnityStereoTransformScreenSpaceTex(input.texcoord);
    21.             uv = GetSimpleDistortion(uv);
    22.             float4 color = LOAD_TEXTURE2D_X(_MainTex, uv * _ScreenSize.xy);
    23.  
    24.             return color;
    25.         }


    And then in my C# script, I am distorting the red UI grid with the same algorithm:


    Code (CSharp):
    1.         private Vector2 GetSimpleLensDistortion(Vector3 viewPort, MQMLensEffect _lensEffect)
    2.         {
    3.             Vector2 uv = new Vector2(viewPort.x, viewPort.y);
    4.  
    5.             Vector2 center = new Vector2(0.5f, 0.5f); // Center of the screen
    6.             Vector2 d = uv - center; // Distance vector from center
    7.             float r = Mathf.Sqrt(d.x * d.x + d.y * d.y); // Distance from center (hypothenusa)
    8.             Vector2 newuv = Vector2.zero;
    9.  
    10.             newuv.x = uv.x + d.x * r * r * _lensEffect.simpleK.value; // move away from the center
    11.             newuv.y = uv.y + d.y * r * r * _lensEffect.simpleK.value;
    12.  
    13.             return newuv;
    14.         }


    And this is how I move the UI grid:
    Code (CSharp):
    1.          for (int x = 0; x < sizex; x++)
    2.          {
    3.              for (int y = 0; y < sizey; y++)
    4.              {
    5.                  Vector3 viewport = cam.WorldToViewportPoint(grid3d_points[x,y].position);
    6.                  Vector2 uv = GetSimpleLensDistortion(viewport, _lensEffect);
    7.                  var newViewport = new Vector3(uv.x, uv.y, viewport.z);
    8.                  var canvas_pos =  Vector3.Scale(newViewport, canvasRect.sizeDelta);
    9.                  screen_handles[x,y].anchoredPosition = new Vector2(canvas_pos.x, canvas_pos.y);
    10.             }
    11.         }
    I doing this by converting the 3D grid points to viewport coordinates - which I think should correspond with the shader's UV-coordinates? - and then to canvas coordinates. But somehow they don't match.

    The only variable controlling the distortion is a float 'simpleK' - if simpleK == 0, there is no distortion and the grids match perfectly.
    It feels like it is working almost, but inverted - as in I am watching the effect from 'behind' or something.
    And actually, if I invert the simpleK (simpleK = -simpleK) variable only in the C# script, it almost works, but with little bit strange scaling.

    Here is an gif showing what happens if simpleK = -simpleK in the C# script:




    So the final question is:

    What am I missing in my 2D calculations? Something related to camera frustum or some simple factor or what? I am lost.

    Help, please.
     
    Last edited: Feb 9, 2021
  2. kankeus

    kankeus

    Joined:
    Dec 3, 2013
    Posts:
    12
    Last edited: Feb 9, 2021
  3. kankeus

    kankeus

    Joined:
    Dec 3, 2013
    Posts:
    12
    Bump.