docs.unity3d.com
Search Results for

    Show / Hide Table of Contents

    Integrate OpenXR features

    OpenXR is an extensible API that you can extend with new features. To facilitate this within the Unity ecosystem, the Unity OpenXR provider supports a feature extension mechanism.

    Important

    This section of the OpenXR package documentation is for developers integrating the OpenXR features provided by an XR device. If you are developing an XR application, refer to Feature Management for information about how to enable features provided by the XR packages you have installed in your project. App developers typically don't create features or feature groups.

    Define a feature

    Unity OpenXR features are defined and executed in C#. C# can call to a custom native plug-in if desired. The feature can live somewhere in the user's project or in a package, and it can include any Assets that a normal Unity project would use.

    A feature must override the OpenXRFeature ScriptableObject class. There are several methods that you can override on the OpenXRFeature class in order to do things like intercepting native OpenXR calls, obtaining the xrInstance and xrSession handles, starting Unity subsystems, etc.

    A feature can add public fields for user configuration at build time. Unity renders these fields via a PropertyDrawer in the feature UI, and you can override them. Your feature can access any of the set values at runtime.

    A feature must also provide an OpenXRFeature attribute when running in the Editor.

    #if UNITY_EDITOR
    using UnityEditor;
    using UnityEngine;
    using UnityEngine.XR.OpenXR;
    using UnityEngine.XR.OpenXR.Features;
    
    namespace UnityEngine.XR.OpenXR.CodeSamples.Editor.Tests
    {
        public class InterceptCreateSessionFeatureExample : OpenXRFeature
        {
            /// <summary>
            /// The feature id string. Provides a well known id for
            /// referencing the feature.
            /// </summary>
            public const string featureId =
                "com.unity.openxr.feature.example.intercept";
        }
    }
    #endif
    

    Unity uses this information at build time, either to build the Player or to display it to the user in the UI.

    Defining a feature group

    Unity OpenXR allows you to define a feature group you can use to organize a group of features.

    Declare a feature group through the definition of one or more OpenXRFeatureSetAttribute declarations in your code. You can place the attribute anywhere because the feature group functionality only depends on the attribute existing and not on the actual class it's declared on.

    #if UNITY_EDITOR
    using UnityEditor.XR.OpenXR.Features;
    using UnityEngine;
    using UnityEngine.XR.OpenXR;
    
    namespace UnityEngine.XR.OpenXR.CodeSamples.Editor.Tests
    {
        [OpenXRFeatureSet(
            FeatureIds = new string[] {
                "EyeGazeInteraction.featureId",
                "KHRSimpleControllerProfile.featureId",
                "com.mycompany.myprovider.mynewfeature",
            },
            UiName = "Feature_Set_Name",
            Description = "Feature group that allows for setting up the best " +
                          "environment for My Company's hardware.",
            FeatureSetId = "com.mycompany.myprovider.mynewfeaturegroup",
            SupportedBuildTargets = new UnityEditor.BuildTargetGroup[] {
                UnityEditor.BuildTargetGroup.Standalone,
                UnityEditor.BuildTargetGroup.Android
            }
        )]
        public class FeatureSetDefinitionExample {}
    }
    #endif
    

    Enabling OpenXR spec extension strings

    Unity attempts to enable any extension strings listed in OpenXRFeatureAttribute.OpenxrExtensionStrings (separated via spaces) on startup. Your feature can check the enabled extensions to determine if the requested extension was enabled (via OpenXRRuntime.IsExtensionEnabled).

    using UnityEngine;
    using UnityEngine.XR.OpenXR;
    using UnityEngine.XR.OpenXR.Features;
    
    namespace UnityEngine.XR.OpenXR.CodeSamples.Editor.Tests
    {
        public class OnInstanceCreateExtensionCheckExample : OpenXRFeature
        {
            protected override bool OnInstanceCreate(ulong xrInstance)
            {
                if (!OpenXRRuntime.IsExtensionEnabled("XR_UNITY_mock_driver"))
                {
                    Debug.LogWarning("XR_UNITY_mock_driver is not enabled, " +
                                     "disabling Mock Driver.");
                    return false;
                }
                if (OpenXRRuntime.GetExtensionVersion("XR_UNITY_mock_driver") < 100)
                    return false;
                return true;
            }
        }
    }
    

    OpenXRFeature call order

    The OpenXRFeature class has a number of methods that your method can override. Implement overrides to get called at specific points in the OpenXR application lifecycle.

    Bootstrapping

    HookGetInstanceProcAddr

    This is the first callback invoked, giving your feature the ability to hook native OpenXR functions.

    Initialize

    OnInstanceCreate => OnSystemChange => OnSubsystemCreate => OnSessionCreate

    The initialize sequence allows features to initialize Unity subsystems in the Loader callbacks and execute them when specific OpenXR resources are created or queried.

    Start

    OnFormFactorChange => OnEnvironmentBlendModeChange => OnViewConfigurationTypeChange => OnSessionBegin => OnAppSpaceChange => OnSubsystemStart

    The Start sequence allows features to start Unity subsystems in the Loader callbacks and execute them when the session is created.

    Game loop

    Several: OnSessionStateChange

    OnSessionBegin

    Maybe: OnSessionEnd

    Callbacks during the game loop can react to session state changes.

    Stop

    OnSubsystemStop => OnSessionEnd

    Shut down

    OnSessionExiting => OnSubsystemDestroy => OnAppSpaceChange => OnSessionDestroy => OnInstanceDestroy

    Build Time Processing

    A feature can inject some logic into the Unity build process in order to do things like modify the manifest.

    Typically, you can do this by implementing the following interfaces:

    • IPreprocessBuildWithReport
    • IPostprocessBuildWithReport
    • IPostGenerateGradleAndroidProject

    Features should not implement these classes, but should instead implement OpenXRFeatureBuildHooks, which only provide callbacks when the feature is enabled. For more information, refer to the [OpenXRFeatureBuildHooks(UnityEditor.XR.OpenXR.Features.OpenXRFeatureBuildHooks) class.

    Build time validation

    If your feature has project setup requirements or suggestions that require user acceptance, implement GetValidationChecks. Features can add to a list of validation rules which Unity evaluates at build time. If any validation rule fails, Unity displays a dialog asking you to fix the error before proceeding. Unity can also presents warning through the same mechanism. It's important to note which build target the rules apply to.

    Example:

    using System.Collections.Generic;
    using UnityEditor;
    using UnityEditor.Build;
    using UnityEditor.Build.Reporting;
    using UnityEngine;
    using UnityEngine.XR.OpenXR;
    using UnityEngine.XR.OpenXR.Features;
    
    namespace UnityEngine.XR.OpenXR.CodeSamples.Editor.Tests
    {
    #if UNITY_EDITOR
        public class BuildTimeValidationExample : OpenXRFeature
        {
            protected override void GetValidationChecks(
                List<OpenXRFeature.ValidationRule> results,
                BuildTargetGroup targetGroup)
            {
                if (targetGroup == BuildTargetGroup.WSA)
                {
                    results.Add(new ValidationRule(this)
                    {
                        message = "Eye Gaze requires the Gaze Input capability.",
                        error = false,
                        checkPredicate = () =>
                            PlayerSettings.WSA.GetCapability(
                                PlayerSettings.WSACapability.GazeInput
                            ),
                        fixIt = () =>
                            PlayerSettings.WSA.SetCapability(
                                PlayerSettings.WSACapability.GazeInput,
                                true
                            )
                    });
                }
            }
        }
    #endif
    }
    

    feature-validation

    Custom Loader library

    The Unity OpenXR package always ships with the latest Khronos OpenXR loader library at the time the package is released. In some cases, your OpenXR feature might require a more recent version of the standard loader library or a custom loader library. To facilitate this, you can include a loader library in your package and specify the appropriate values for your feature's OpenXRFeatureAttribute properties.

    Use openxr_loader as the base file name your custom loader library. Modify this base name according to the native library naming conventions for each platform build target (for example, uselibopenxr_loader.so on Android). Place the library in the same directory or a subdirectory relative to the C# script that extends the OpenXRFeature class to define your feature. When the feature is enabled in a Unity project, Unity evaluates whether to include your custom loader library in an application build instead of the default loader library.

    To use a custom loader library for a feature, set the following OpenXRFeature properties:

    Property Value
    CustomRuntimeLoaderBuildTargets Assign a list of BuildTargets for which your custom loader library should be used. If your feature doesn't use a custom loader library, you don't need to assign a value to CustomRuntimeLoaderBuildTargets (you can also set it to null or an empty list).
    CustomRuntimeLoaderVersion Set the version of the Khronos OpenXR API that the custom loader supports. If you don't specify an OpenXR API version, then Unity always uses your custom loader when this feature is enabled, unless another enabled feature also specifies a custom loader without declaring an OpenXR API version. Refer to Loader library selection for information about how such conflicts are resolved.
    TargetOpenXRApiVersion Set the version of the Khronos OpenXR API that the application should target when it deploys. This is distinct from CustomRuntimeLoaderVersion, and is only used for determining the version of the OpenXR API that is used at runtime, and has no bearing on the OpenXR loader library which is included.
    Note

    If your custom loader library requires the same OpenXR API version as the default Khronos loader in this Unity OpenXR package, the build uses the default loader instead of your custom one.

    Loader library selection

    The Unity build always uses the default loader library from the Unity OpenXR package, unless an enabled feature declares a custom loader library with a higher CustomRuntimeLoaderVersion than the API version supported by the loader included in the Unity package. This resolution method lets your feature use a newer loader library at the time you publish your feature, while letting an update of the Unity OpenXR package supersede it in a future release.

    If two enabled features declare custom loader libraries and the same CustomRuntimeLoaderVersion value, then the loader for the feature with the highest Priority is used.

    For backward compatibility, the loader library for a feature that doesn't specify a value for CustomRuntimeLoaderVersion, overrides any other loaders, including the default loader from the Unity OpenXR package.

    Important

    You should always specify a value for CustomRuntimeLoaderVersion. If an application developer enables more than one feature that declares a custom loader library for a BuildTarget without also specifying an OpenXR API version in the CustomRuntimeLoaderVersion field, then their builds will fail.

    Feature native libraries

    Any native libraries included in the same directory or a subdirectory of your feature will only be included in the built Player if your feature is enabled.

    Feature use cases

    Intercepting OpenXR function calls

    To intercept OpenXR function calls, override OpenXRFeature.HookGetInstanceProcAddr. Returning a different function pointer allows intercepting any OpenXR method. For an example, see the Intercept Feature sample.

    Calling OpenXR functions from a feature

    To call an OpenXR function within a feature you first need to retrieve a pointer to the function. To do this use the OpenXRFeature.xrGetInstanceProcAddr function pointer to request a pointer to the function you want to call. Using OpenXRFeature.xrGetInstanceProcAddr to retrieve the function pointer ensures that any intercepted calls set up by features using OpenXRFeature.HookGetInstanceProcAddr will be included.

    Providing a Unity subsystem implementation

    OpenXRFeature provides several XR Loader callbacks where you can manage the lifecycle of Unity subsystems. For an example meshing subsystem feature, see the Meshing Subsystem Feature sample.

    Note that a UnitySubsystemsManifest.json file is required in order for Unity to discover any subsystems you define. At the moment, there are several restrictions around this file:

    • It must be only 1 subfolder deep in the project or package.
    • The native library it refers to must be only 1-2 subfolders deeper than the UnitySubsystemsManfiest.json file.
    In This Article
    Back to top
    Copyright © 2025 Unity Technologies — Trademarks and terms of use
    • Legal
    • Privacy Policy
    • Cookie Policy
    • Do Not Sell or Share My Personal Information
    • Your Privacy Choices (Cookie Settings)