Files
Bachelor-Arbeit-Adrian-Haefner/Library/PackageCache/com.xreal.xr@ee75e1479685/Runtime/Scripts/Utility/XREALUtility.cs
adriadri6972 d3d9c5f833 upload project
2025-07-31 15:21:08 +02:00

268 lines
10 KiB
C#

using System;
using System.Collections;
using System.Linq;
using Unity.XR.CoreUtils;
using UnityEngine;
using UnityEngine.XR;
using UnityEngine.XR.Management;
using static UnityEngine.XR.XRDisplaySubsystem;
namespace Unity.XR.XREAL
{
public static class XREALUtility
{
public const string k_Identifier = "com.xreal.xr";
private static Camera mainCamera;
/// <summary>
/// Gets the main camera, which is either the XR Origin's camera or null if not found.
/// </summary>
public static Camera MainCamera
{
get
{
if (mainCamera == null)
{
XROrigin origin = FindAnyObjectByType<XROrigin>();
mainCamera = (origin != null) ? origin.Camera : null;
}
return mainCamera;
}
}
/// <summary>
/// Finds an object of the specified type in the scene.
/// </summary>
/// <typeparam name="T">The type of the object to find.</typeparam>
/// <returns>The object if found; otherwise, null.</returns>
public static T FindAnyObjectByType<T>() where T : UnityEngine.Object
{
#if UNITY_2023_1_OR_NEWER
return UnityEngine.Object.FindAnyObjectByType<T>();
#else
return UnityEngine.Object.FindObjectOfType<T>();
#endif
}
/// <summary>
/// Gets the currently active XR loader.
/// </summary>
/// <returns>The active XR loader, or null if no loader is active.</returns>
public static XRLoader GetActiveLoader()
{
if (XRGeneralSettings.Instance != null && XRGeneralSettings.Instance.Manager != null)
{
return XRGeneralSettings.Instance.Manager.activeLoader;
}
return null;
}
/// <summary>
/// Determines whether the XREAL XR loader is currently active.
/// </summary>
/// <returns>True if the XREAL XR loader is active; otherwise, false.</returns>
public static bool IsLoaderActive()
{
#if UNITY_EDITOR
var targetGroup = UnityEditor.BuildPipeline.GetBuildTargetGroup(UnityEditor.EditorUserBuildSettings.activeBuildTarget);
var settings = UnityEditor.XR.Management.XRGeneralSettingsPerBuildTarget.XRGeneralSettingsForBuildTarget(targetGroup);
return settings != null && settings.Manager.activeLoaders.OfType<XREALXRLoader>().Any();
#else
return GetActiveLoader() is XREALXRLoader;
#endif
}
/// <summary>
/// Gets the loaded subsystem of the specified type from the active loader.
/// </summary>
/// <typeparam name="T">The type of the subsystem to retrieve.</typeparam>
/// <returns>The loaded subsystem of the specified type, or null if not found.</returns>
public static T GetLoadedSubsystem<T>() where T : class, ISubsystem
{
XRLoader loader = GetActiveLoader();
if (loader != null)
{
return loader.GetLoadedSubsystem<T>();
}
return null;
}
/// <summary>
/// Retrieves the XR render parameter for the specified eye.
/// </summary>
/// <param name="eye">The eye index (0 for left, 1 for right).</param>
/// <param name="parameter">The render parameter for the specified eye.</param>
/// <returns>True if the render parameter is successfully retrieved; otherwise, false.</returns>
public static bool GetXRRenderParameter(int eye, out XRRenderParameter parameter)
{
parameter = new XRRenderParameter();
XRDisplaySubsystem displaySubsystem = GetLoadedSubsystem<XRDisplaySubsystem>();
if (displaySubsystem == null)
return false;
var passCount = displaySubsystem.GetRenderPassCount();
if (passCount == 0)
return false;
int passIndex = passCount == 2 && eye == 1 ? 1 : 0;
displaySubsystem.GetRenderPass(passIndex, out XRRenderPass renderPass);
var parameterCount = renderPass.GetRenderParameterCount();
if (parameterCount == 0)
return false;
int parameterIndex = parameterCount == 2 && eye == 1 ? 1 : 0;
renderPass.GetRenderParameter(MainCamera, parameterIndex, out parameter);
return true;
}
/// <summary>
/// Determines if the specified transform is a child of the main camera.
/// </summary>
/// <param name="transform">The transform to check.</param>
/// <returns>True if the transform is a child of the main camera; otherwise, false.</returns>
public static bool IsChildOfCamera(this Transform transform)
{
Transform cameraTransform = MainCamera.transform;
Transform current = transform;
while (current != null)
{
if (current == cameraTransform)
{
return true;
}
current = current.parent;
}
return false;
}
/// <summary>
/// Calculates the relative pose of the specified transform to the main camera.
/// </summary>
/// <param name="transform">The transform to calculate the relative pose for.</param>
/// <returns>The relative pose to the main camera.</returns>
public static Pose GetRelativePoseToCamera(this Transform transform)
{
Transform cameraTransform = MainCamera.transform;
Vector3 relativePosition = cameraTransform.InverseTransformPoint(transform.position);
Quaternion relativeRotation = Quaternion.Inverse(cameraTransform.rotation) * transform.rotation;
return new Pose(relativePosition, relativeRotation);
}
/// <summary>
/// Calculates the relative pose of the specified transform to the parent of the main camera.
/// </summary>
/// <param name="transform">The transform to calculate the relative pose for.</param>
/// <returns>The relative pose to the parent of the main camera.</returns>
public static Pose GetRelativePoseToCameraParent(this Transform transform)
{
Transform cameraTransform = MainCamera.transform;
if (cameraTransform.parent != null)
{
Vector3 relativePosition = cameraTransform.parent.InverseTransformPoint(transform.position);
Quaternion relativeRotation = Quaternion.Inverse(cameraTransform.parent.rotation) * transform.rotation;
return new Pose(relativePosition, relativeRotation);
}
else
{
return new Pose(transform.position, transform.rotation);
}
}
/// <summary>
/// Adds or retrieves the specified component from the GameObject.
/// </summary>
/// <typeparam name="T">The type of the component to add or retrieve.</typeparam>
/// <param name="gameObject">The GameObject to add or retrieve the component from.</param>
/// <returns>The component of type T.</returns>
public static T AddOrGetComponent<T>(this GameObject gameObject) where T : Component
{
if (gameObject.TryGetComponent(out T component))
{
return component;
}
else
{
return gameObject.AddComponent<T>();
}
}
/// <summary>
/// Adds or retrieves the specified component from the Component's GameObject.
/// </summary>
/// <typeparam name="T">The type of the component to add or retrieve.</typeparam>
/// <param name="component">The Component to add or retrieve the component from.</param>
/// <returns>The component of type T.</returns>
public static T AddOrGetComponent<T>(this Component component) where T : Component
{
return component.gameObject.AddOrGetComponent<T>();
}
/// <summary>
/// Starts a coroutine that continues until the specified predicate evaluates to true or the timeout expires.
/// </summary>
/// <param name="monoBehaviour">The MonoBehaviour that starts the coroutine.</param>
/// <param name="predicate">The condition to evaluate in the coroutine.</param>
/// <param name="timeoutSeconds">The maximum time to wait before exiting the coroutine.</param>
/// <returns>The Coroutine instance.</returns>
public static Coroutine StartCoroutineUntil(this MonoBehaviour monoBehaviour, Func<bool> predicate, float timeoutSeconds)
{
return monoBehaviour.StartCoroutine(WaitUntilCondition(predicate, timeoutSeconds));
}
/// <summary>
/// Waits until the specified condition is met or the timeout expires.
/// </summary>
/// <param name="predicate">The condition to evaluate in the coroutine.</param>
/// <param name="timeoutSeconds">The maximum time to wait before exiting the coroutine.</param>
/// <returns>Null when the condition is met or timeout expires.</returns>
private static IEnumerator WaitUntilCondition(Func<bool> predicate, float timeoutSeconds)
{
float startTime = Time.time;
while (!predicate())
{
if (Time.time - startTime > timeoutSeconds)
{
yield break;
}
yield return null;
}
}
#if UNITY_ANDROID
static AndroidJavaObject s_UnityActivity;
/// <summary>
/// Gets the current Unity activity in the Android environment.
/// </summary>
public static AndroidJavaObject UnityActivity
{
get
{
if (s_UnityActivity == null)
{
using AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
s_UnityActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
}
return s_UnityActivity;
}
}
/// <summary>
/// Runs the specified action on the Unity Android UI thread.
/// </summary>
/// <param name="action">The action to execute on the UI thread.</param>
public static void RunOnUiThread(Action action)
{
UnityActivity.Call("runOnUiThread", new AndroidJavaRunnable(action));
}
#endif
}
}