Search Unity

  1. Read here for Unity's latest plans on OpenXR.
    Dismiss Notice

Resolved Get actual camera field of view in AR?

Discussion in 'AR' started by AxonGenesis, Mar 19, 2021.

  1. AxonGenesis

    AxonGenesis

    Joined:
    Jun 24, 2016
    Posts:
    26
    I need to get the camera's FOV in my AR app however the Camera.fieldOfView parameter is incorrect and remains at whatever value is set in the Unity editor, regardless of the actual FOV on the device. I understand that AR takes over the camera matrix. I am not trying to change it, just need the real FOV value to calculate screen relative placements. I've reviewed this other thread and tried a number of different methods for calculating the FOV with no solution found yet.

    Code (CSharp):
    1.  
    2. Debug.Log("Camera.fieldOfView:" + Camera.fieldOfView);
    3. // Always the same (incorrect) value set in the editor, not the actual FOV rendered
    4.  
    5. // FOV calculated from projection matrix is also incorrect and results
    6. // in same value as above
    7. float t = Camera.projectionMatrix.m11;
    8. float fov = Mathf.Atan(1.0f / t) * 2.0f * Mathf.Rad2Deg;
    9. float z = 0.5f / Mathf.Tan(fov * 0.5f * Mathf.Deg2Rad);
    10. transform.localPosition = new Vector3(0f, 0f, z);
    11.  
    12.  
    13. // The screen width and scale do correctly report the device's screen resolution
    14. Debug.Log("Screen.width:" + Screen.width + " height:" + Screen.height);
    15.  
    16. // The following is from the Vuforia, but alas does not work either
    17. Ray ray = Camera.main.ScreenPointToRay(new Vector3(Screen.width / 2.0f, Screen.height, 0));
    18. float angle = Vector3.Angle(Camera.main.transform.forward, ray.direction);
    19. fov = angle * 2.0f;
    20. Debug.Log("fov:" + fov);
    21.  
    22. // I've also tried placing 3D objects in screen space, but the
    23. // ScreenToWorldPoint calculation is incorrect based again on the wrong FOV,
    24. // not the actual FOV being displayed
    25. Vector3 start = Camera.ScreenToWorldPoint(new Vector3(0f, 0f, z));
    26. Vector3 end = Camera.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, z));
    27. StartMarker.transform.position = start;
    28. EndMarker.transform.position = end;
    29. }
    30.  
    Any ideas?
     
  2. danUnity

    danUnity

    Joined:
    Apr 28, 2015
    Posts:
    216
  3. AxonGenesis

    AxonGenesis

    Joined:
    Jun 24, 2016
    Posts:
    26
    Thanks for the suggestions! I originally had the above code running upon Start but tried it during LateUpdate instead and got the same result. All three of the methods for calculating the FOV return the same value, which is whatever value is assigned to the camera in the Editor.

    I looked at XRCameraConfiguration which in itself didn't provide the answer but lead me to look at XRCameraSubsystem where I found the XR projection matrix and found the solution!

    Below is the method I'm using and it works as expected on the device. Because the camera subsystem doesn't start up right away, it tries repeatedly until it succeeds. CameraManager is a reference to ARCameraManager in the scene. ARCameraManager also has a frameReceived event, though I opted to do it this way instead.

    Code (CSharp):
    1.  
    2. void Update()
    3. {
    4.     if (!HasFOV) {
    5.         XRCameraParams cameraParams = new XRCameraParams {
    6.             zNear = Camera.nearClipPlane,
    7.             zFar = Camera.farClipPlane,
    8.             screenWidth = Screen.width,
    9.             screenHeight = Screen.height,
    10.             screenOrientation = Screen.orientation
    11.         };
    12.  
    13.         XRCameraFrame cameraFrame;
    14.         if (CameraManager.subsystem.TryGetLatestFrame(cameraParams, out cameraFrame)) {
    15.             t = cameraFrame.projectionMatrix.m11;
    16.             fov = Mathf.Atan(1.0f / t) * 2.0f * Mathf.Rad2Deg;
    17.             Debug.Log("AR matrix fov:" + fov);
    18.             HasFOV = true;
    19.         }
    20.         else {
    21.             Debug.Log("AR matrix fov: FAILED");
    22.             HasFOV = false;
    23.         }
    24.     }
    25. }
    26.  
     
  4. danUnity

    danUnity

    Joined:
    Apr 28, 2015
    Posts:
    216
    Ah great! Glad to know I could help in some way I guess haha

    Maybe using the FrameReceived would be better to make sure you get the first frame that is handled by the CameraManager otherwise before that you can't get the camera projection matrix right? At least not the right camera projection matrix.

    But glad that worked out!
     
  5. KirillKuzyk

    KirillKuzyk

    Joined:
    Nov 4, 2013
    Posts:
    759
    This feature is available starting from AR Foundation 4.1.3:
    https://docs.unity3d.com/Packages/c...4.1/changelog/CHANGELOG.html#413---2021-01-05
     
    danUnity likes this.
  6. danUnity

    danUnity

    Joined:
    Apr 28, 2015
    Posts:
    216
unityunity