Skip to main content
Version: 20 Mar 2024

Focus Distance / Stereo Convergence

This article provides guidelines for improving content registration in the world. Content registration, commonly referred to as pixel stick, is important for a good user experience. There are several factors to consider, especially in more dynamic or resource intensive applications where following these guidelines becomes crucial.

Understanding Stabilization in Magic Leap 2

The Magic Leap 2 offers developers precise control over stabilization. Setting the Focus Distance influences the perceived stability of objects within the scene. Objects positioned closer to this distance appear more stable, while those further away exhibit increased movement. If the incorrect focus distance is used, the edges of objects outside the focus distance may appear to shiver or jitter.

Best Practices

  • Simple Content: For images or videos, align the Focus Distance with the object's depth.
  • Multiple Depths: When content spans various depths, prioritize setting the distance to the object in focus.
    • Utilize eye tracking or ray-casting techniques to determine the focal point.
    • If a focus point cannot be definitively identified, opt for either the furthest object or the average depth of objects in view.
  • Dynamic Adjustment: Continuously update the Focus Distance every frame to maintain alignment with the object that should appear most stable.

Things to Avoid

  • User Intersection: Refrain from setting the stabilization depth to intersect with the user's body, as this can lead to visual instability.
  • Too Narrow Focus Distance: Objects outside of the focus distance appear to be more jittery than objects that are closer than the specified distance.

Gaze Based Focus Point

The focus point can be derived from the user's gaze. To make the implementation easy, we created a unity package that uses a Physics RayCast to detect which object the user is looking at.

note

This package does not take into account objects such as canvases that do not have a collider.

Configuring the Asset

  1. Download the Unity Package.
  2. Import the Unity Package into your project ( Assets > Import New Package > Custom Package... ).
  3. Once imported, navigate to the Assets/StereoConvergenceDetector folder and add the Stereo Convergence Detector prefab into your scene.
  4. Enable the Eye Tracking permission in the project settings.
  5. Activate the OpenXR Eye Tracking Interaction profile.

Additional Options

This StereoConvergenceDetector has several options for determining focus distance:

  • Using the eye gaze to target the SphereCast.
  • Using head-pose and sphere casting down camera forward.

The default option works best as long as your objects contain colliders. The component also allows you to debug the ray-cast and hit point to help troubleshoot your application.

Custom Focus Point Calculation

Developers can adjust the focus distance using a custom calculation.

The script below uses the same logic to calculate the focus distance as on the Magic Leap Camera component but does not depend on the component to be present.

using UnityEngine;
using UnityEngine.XR.OpenXR;
using UnityEngine.XR.OpenXR.Features.MagicLeapSupport;

public class SetCustomFocusDistance : MonoBehaviour
{
public Transform FocusTarget;

private Camera camera;
private MagicLeapRenderingExtensionsFeature renderFeature;

private void Start()
{
camera = Camera.main;
renderFeature = OpenXRSettings.Instance.GetFeature<MagicLeapRenderingExtensionsFeature>();
if (camera == null || renderFeature == null || renderFeature.enabled == false)
{
Debug.LogError("Focus Distance cannot be set. Disabling script. " +
"Ensure all requirements are met : \n" +
$"Camera is present : {camera !=null} \n" +
$"Render Feature is present : {renderFeature != null} \n" +
$"Render Feature is enabled : {(renderFeature !=null? renderFeature.enabled: renderFeature)}");
enabled = false;
}
}

void LateUpdate()
{
camera.stereoConvergence = CalculateFocusDistance();

if (renderFeature == null)
return;

renderFeature.FocusDistance = camera.stereoConvergence;
}

private float CalculateFocusDistance()
{
// Get Focus Distance and log warnings if not within the allowed value bounds.
float focusDistance = camera.stereoConvergence;
if (FocusTarget != null)
{
// From Unity documentation:
// Note that camera space matches OpenGL convention: camera's forward is the negative Z axis.
// This is different from Unity's convention, where forward is the positive Z axis.
Vector3 worldForward = new Vector3(0.0f, 0.0f, -1.0f);
Vector3 camForward = camera.cameraToWorldMatrix.MultiplyVector(worldForward);
camForward = camForward.normalized;

// We are only interested in the focus object's distance to the camera forward tangent plane.
focusDistance = Vector3.Dot(FocusTarget.position - transform.position, camForward);
}

float nearClip = camera.nearClipPlane;
if (focusDistance < nearClip)
{
focusDistance = nearClip;
}

return focusDistance;
}
}

Send Focus Distance to Magic Leap

If you are working to improve video capture, it may be useful to send Magic Leap the focus distance. You can do that with the following lines of code:

var renderFeature = OpenXRSettings.InstanceGetFeature<MagicLeapRenderingExtensionsFeature>();
mainCamera.stereoConvergence = 100f;
renderFeature.FocusDistance = mainCamera.stereoConvergence;

Next Steps

Improve Content Stability Overview

Learn more about how Magic Leap's focus distance improves the appearance of content stability.