アドカレ
KENTOのひとりアドカレ8日目の記事です。
https://qiita.com/advent-calendar/2025/kento
環境情報
| ツール/SDK | バージョン |
|---|---|
| Unity | 6000.0.62f1 |
| Meta XR Core SDK | 81.0.0 |
| Open XR Plugin | 1.16.0 |
| XR Interaction Toolkit | 3.0.9 |
| XR Hands | 1.7.1 |
事前準備は以下の通りです。
- 【Meta Quest】しばらく触ってないうちにMeta XR SDKがOpenXRベースになっていたので改めて整理
- 【Meta Quest】XR Interaction Toolkitを導入する
- 【Meta Quest】パススルー設定方法
XR Device SimulatorとLinkの競合
XR Device Simulatorをオンにした状態でLinkに接続して動作確認しようとすると、互いのトラッキングシステムが競合し、正常な挙動となりません。
解決策
基本動作はシミュレーターを有効とし、Link接続時のみシミュレーターをオフにする仕様を目指しました。
まず、必要な情報としてはLink接続状態かどうかの情報です。これは、以下のコードで取得できました。
using UnityEngine;
using UnityEngine.XR.OpenXR;
public static class MetaQuestLinkChecker
{
/// <summary>
/// Link使用中かどうか。
/// RuntimeName が Empty → 非 Link
/// Empty 以外 → Link
/// </summary>
public static bool IsLink => !string.IsNullOrEmpty(_runtimeName);
private static string _runtimeName;
#if UNITY_EDITOR [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
private static void Initialize()
{
_runtimeName = OpenXRRuntime.name;
Debug.Log($"[AutoActivateDeviceSimulator] Initialized: RuntimeName='{_runtimeName}', IsLink={IsLink}");
}
#endif
}
次に、IsLinkに応じたXR Device Simulatorの無効化です。ただ、これが少し面倒で、以下パスに設定ファイルが配置してあるのですが、肝心のオン/オフ制御用パラメータはinternalで定義されており、外部からの動的な変更を想定したつくりではありませんでした。
Assets/XRI/Settings/Resources/XRDeviceSimulatorSettings.asset
using Unity.XR.CoreUtils;
using UnityEngine.XR.Interaction.Toolkit.Utilities;
namespace UnityEngine.XR.Interaction.Toolkit.Inputs.Simulation
{
/// <summary>
/// Configuration class for XR Device Simulator which
/// stores settings related to automatic instantiation.
/// </summary>
[ScriptableSettingsPath(ProjectPath.k_XRInteractionSettingsFolder)]
class XRDeviceSimulatorSettings : ScriptableSettings<XRDeviceSimulatorSettings>
{
[SerializeField]
bool m_AutomaticallyInstantiateSimulatorPrefab;
/// <summary>
/// Setting this value to <see langword="true"/> will tell the <see cref="XRDeviceSimulatorLoader"/> to look for and automatically
/// add the <see cref="simulatorPrefab"/> to the current scene if it does not already exist.
/// </summary>
internal bool automaticallyInstantiateSimulatorPrefab
{
get => m_AutomaticallyInstantiateSimulatorPrefab;
set => m_AutomaticallyInstantiateSimulatorPrefab = value;
}
[SerializeField]
bool m_AutomaticallyInstantiateInEditorOnly = true;
/// <summary>
/// Enable to only automatically instantiate the <see cref="simulatorPrefab"/> if the application is running inside the Unity Editor,
/// preventing it from automatically appearing in standalone builds. Disable to allow the simulator to be created in standalone builds.
/// </summary>
/// <remarks>
/// Setting this value to <see langword="true"/> will limit the <see cref="XRDeviceSimulatorLoader"/> to
/// only automatically instantiate the <see cref="simulatorPrefab"/> if the application is running inside the Unity Editor.
/// This property is only used if <see cref="automaticallyInstantiateSimulatorPrefab"/> is enabled.
/// </remarks>
internal bool automaticallyInstantiateInEditorOnly
{
get => m_AutomaticallyInstantiateInEditorOnly;
set => m_AutomaticallyInstantiateInEditorOnly = value;
}
[SerializeField]
GameObject m_SimulatorPrefab;
/// <summary>
/// This is the prefab to instantiate when <see cref="automaticallyInstantiateSimulatorPrefab"/> is set to <see langword="true"/>.
/// </summary>
internal GameObject simulatorPrefab
{
get => m_SimulatorPrefab;
set => m_SimulatorPrefab = value;
}
}
}
よって、パラメータの動的変更は諦めて、シーン上のシミュレーターをシーンロード直後に破棄する方針を採用しました。
#if UNITY_EDITOR
using UnityEngine;
using UnityEngine.XR.Interaction.Toolkit.Inputs.Simulation;
public class AutoActivateDeviceSimulator : MonoBehaviour
{
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
private static void DestroySimulatorOnLink()
{
if (MetaQuestLinkChecker.IsLink && XRDeviceSimulator.instance)
{
Destroy(XRDeviceSimulator.instance.gameObject);
Debug.Log("[AutoActivateDeviceSimulator] Link Runtime detected. XR Device Simulator instance destroyed.");
}
}
}
#endif
これらのコードにより、非Link接続時にはシミュレーターが利用され、Link接続時には自動的にシミュレーターの無効化を行うという構造を実現できました。
おまけ
Linkの接続状態を取得できるのは他の箇所でも活躍しました。
以前の記事で、コントローラーの位置がずれる問題に触れましたが、シミュレーター上ではその不具合が再現しないため、今どの環境で動いているのか場合分けが必要でした。
【参考リンク】:【Meta Quest】XR Interaction Toolkitを導入する
MetaQuestLinkCheckerを用いれば、以下のように解決可能です。
using UnityEngine;
public class FixControllerTransform : MonoBehaviour
{
private void Awake()
{
var fixEuler = new Vector3(0,180,180);
var originalEuler = new Vector3(0,180,0);
#if UNITY_EDITOR
transform.localEulerAngles = MetaQuestLinkChecker.IsLink ? fixEuler : originalEuler;
#else
transform.localEulerAngles = fixEuler;
#endif
}
}