Feat : Wwise Integration
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
# Changelog
|
||||
|
||||
## Version 2025.1.6
|
||||
- Initial release
|
||||
- Wwise Motion haptics support for Meta Quest devices via OpenXR
|
||||
- Support for Android (Quest standalone) and Windows 64-bit (Quest Link)
|
||||
- XR_FB_haptic_pcm extension integration
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 70fdf7a14d7b70e4fa0cd9837d530e46
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,18 @@
|
||||
# License
|
||||
|
||||
/*******************************************************************************
|
||||
The content of this file includes portions of the proprietary AUDIOKINETIC Wwise
|
||||
Technology released in source code form as part of the game integration package.
|
||||
The content of this file may not be used without valid licenses to the AUDIOKINETIC
|
||||
Wwise Technology.
|
||||
Note that the use of the game engine is subject to the Unity Terms of Service
|
||||
at https://unity3d.com/legal/terms-of-service.
|
||||
|
||||
License Usage
|
||||
|
||||
Licensees holding valid licenses to the AUDIOKINETIC Wwise Technology may use
|
||||
this file in accordance with the end user license agreement provided with the
|
||||
software or, alternatively, in accordance with the terms contained
|
||||
in a written agreement between you and Audiokinetic Inc.
|
||||
Copyright (c) 2026 Audiokinetic Inc.
|
||||
*******************************************************************************/
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 78170b08336ddb14aa3f6aabc1719994
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,32 @@
|
||||
# Wwise Unity OpenXR Motion
|
||||
|
||||
This package adds support for Wwise Motion haptics on Meta Quest devices via OpenXR.
|
||||
|
||||
## Requirements
|
||||
|
||||
* Unity 2021.3 or later
|
||||
* Unity XR Plugin Management with OpenXR plugin >= 1.16.0
|
||||
* Wwise Unity Integration
|
||||
* Wwise Motion plugin
|
||||
|
||||
## Usage
|
||||
See [Unity Wwise Motion OpenXR Documentation]() for more information about how to use the package.
|
||||
|
||||
## Legal
|
||||
|
||||
/*******************************************************************************
|
||||
The content of this file includes portions of the proprietary AUDIOKINETIC Wwise
|
||||
Technology released in source code form as part of the game integration package.
|
||||
The content of this file may not be used without valid licenses to the AUDIOKINETIC
|
||||
Wwise Technology.
|
||||
Note that the use of the game engine is subject to the Unity Terms of Service
|
||||
at https://unity3d.com/legal/terms-of-service.
|
||||
|
||||
License Usage
|
||||
|
||||
Licensees holding valid licenses to the AUDIOKINETIC Wwise Technology may use
|
||||
this file in accordance with the end user license agreement provided with the
|
||||
software or, alternatively, in accordance with the terms contained
|
||||
in a written agreement between you and Audiokinetic Inc.
|
||||
Copyright (c) 2026 Audiokinetic Inc.
|
||||
*******************************************************************************/
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f17bbf5953ca4aa48bd6e9ceb022017e
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: af770b0b88b333846b96dbd1d7b9c6d1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "AK.Wwise.Unity.OpenXR",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"AK.Wwise.Unity.API",
|
||||
"AK.Wwise.Unity.MonoBehaviour",
|
||||
"Unity.XR.OpenXR",
|
||||
"Unity.InputSystem",
|
||||
"AK.Wwise.Unity.Logging"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Android",
|
||||
"Editor",
|
||||
"WindowsStandalone32",
|
||||
"WindowsStandalone64"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [
|
||||
"!UNITY_SERVER"
|
||||
],
|
||||
"versionDefines": [
|
||||
{
|
||||
"name": "com.unity.xr.openxr",
|
||||
"expression": "[1.16.1]",
|
||||
"define": "AK_ENABLE_OPENXR"
|
||||
}
|
||||
],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ecfa77477d417946b10ed76bcaf6775
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,107 @@
|
||||
/*******************************************************************************
|
||||
The content of this file includes portions of the proprietary AUDIOKINETIC Wwise
|
||||
Technology released in source code form as part of the game integration package.
|
||||
The content of this file may not be used without valid licenses to the AUDIOKINETIC
|
||||
Wwise Technology.
|
||||
Note that the use of the game engine is subject to the Unity Terms of Service
|
||||
at https://unity3d.com/legal/terms-of-service.
|
||||
|
||||
License Usage
|
||||
|
||||
Licensees holding valid licenses to the AUDIOKINETIC Wwise Technology may use
|
||||
this file in accordance with the end user license agreement provided with the
|
||||
software or, alternatively, in accordance with the terms contained
|
||||
in a written agreement between you and Audiokinetic Inc.
|
||||
Copyright (c) 2026 Audiokinetic Inc.
|
||||
*******************************************************************************/
|
||||
|
||||
#if AK_ENABLE_OPENXR
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using UnityEngine;
|
||||
using UnityEngine.XR.OpenXR.NativeTypes;
|
||||
|
||||
using AK.Wwise.Unity.Logging;
|
||||
|
||||
namespace AK.Wwise.Unity.OpenXR
|
||||
{
|
||||
/// <summary>
|
||||
/// P/Invoke bridge to native AkMotion OpenXR functions.
|
||||
/// Provides C# bindings to pass OpenXR function pointers and handles to the Wwise Motion plugin.
|
||||
/// </summary>
|
||||
public static class AkWwiseOpenXRMotionBridge
|
||||
{
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
private delegate XrResult XrGetInstanceProcAddrDelegate(ulong instance, IntPtr name, ref IntPtr function);
|
||||
|
||||
[DllImport("AkMotion", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern void AkMotionInitializeOpenXRFunctions(IntPtr xrResultToString, IntPtr xrEnumerateInstanceExtensionProperties, IntPtr xrStringToPath, IntPtr xrGetInstanceProcAddr, IntPtr xrApplyHapticFeedback);
|
||||
|
||||
[DllImport("AkMotion", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern void AkMotionSetOpenXRHapticAction(ulong xrInstance, ulong xrSession, ulong xrAction);
|
||||
|
||||
private static IntPtr GetOpenXRFunction(IntPtr xrGetInstanceProcAddr, ulong instance, string functionName)
|
||||
{
|
||||
var getProcAddr = Marshal.GetDelegateForFunctionPointer<XrGetInstanceProcAddrDelegate>(xrGetInstanceProcAddr);
|
||||
IntPtr functionPtr = IntPtr.Zero;
|
||||
IntPtr namePtr = Marshal.StringToHGlobalAnsi(functionName);
|
||||
|
||||
try
|
||||
{
|
||||
XrResult result = getProcAddr(instance, namePtr, ref functionPtr);
|
||||
if (result != XrResult.Success)
|
||||
{
|
||||
WwiseLogger.Warning($"[AkWwiseOpenXRMotionBridge] Failed to get function pointer for {functionName}: {result}");
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(namePtr);
|
||||
}
|
||||
|
||||
return functionPtr;
|
||||
}
|
||||
|
||||
// Initializes the Wwise Motion plugin with OpenXR function pointers and handles.
|
||||
// This must be called after OpenXR initialization and after the Wwise sound engine has loaded Init.bnk.
|
||||
public static bool Initialize(IntPtr xrGetInstanceProcAddr, ulong xrInstance, ulong xrSession, ulong xrAction)
|
||||
{
|
||||
if (xrGetInstanceProcAddr == IntPtr.Zero || xrInstance == 0 || xrSession == 0 || xrAction == 0)
|
||||
{
|
||||
WwiseLogger.Error("[AkWwiseOpenXRMotionBridge] Invalid parameters: all handles must be non-zero");
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
IntPtr xrResultToString = GetOpenXRFunction(xrGetInstanceProcAddr, xrInstance, "xrResultToString");
|
||||
IntPtr xrEnumerateInstanceExtensionProperties = GetOpenXRFunction(xrGetInstanceProcAddr, xrInstance, "xrEnumerateInstanceExtensionProperties");
|
||||
IntPtr xrStringToPath = GetOpenXRFunction(xrGetInstanceProcAddr, xrInstance, "xrStringToPath");
|
||||
IntPtr xrApplyHapticFeedback = GetOpenXRFunction(xrGetInstanceProcAddr, xrInstance, "xrApplyHapticFeedback");
|
||||
|
||||
if (xrResultToString == IntPtr.Zero || xrEnumerateInstanceExtensionProperties == IntPtr.Zero || xrStringToPath == IntPtr.Zero || xrApplyHapticFeedback == IntPtr.Zero)
|
||||
{
|
||||
WwiseLogger.Error("[AkWwiseOpenXRMotionBridge] Failed to retrieve required OpenXR function pointers");
|
||||
return false;
|
||||
}
|
||||
|
||||
AkMotionInitializeOpenXRFunctions(xrResultToString, xrEnumerateInstanceExtensionProperties, xrStringToPath, xrGetInstanceProcAddr, xrApplyHapticFeedback);
|
||||
WwiseLogger.Verbose("[AkWwiseOpenXRMotionBridge] Passed OpenXR function pointers to AkMotion");
|
||||
|
||||
AkMotionSetOpenXRHapticAction(xrInstance, xrSession, xrAction);
|
||||
WwiseLogger.Verbose("[AkWwiseOpenXRMotionBridge] Passed OpenXR handles to AkMotion");
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WwiseLogger.Error($"[AkWwiseOpenXRMotionBridge] Exception during initialization: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // AK_ENABLE_OPENXR
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: be344861e7aa3364f965a0f97037c58a
|
||||
@@ -0,0 +1,210 @@
|
||||
/*******************************************************************************
|
||||
The content of this file includes portions of the proprietary AUDIOKINETIC Wwise
|
||||
Technology released in source code form as part of the game integration package.
|
||||
The content of this file may not be used without valid licenses to the AUDIOKINETIC
|
||||
Wwise Technology.
|
||||
Note that the use of the game engine is subject to the Unity Terms of Service
|
||||
at https://unity3d.com/legal/terms-of-service.
|
||||
|
||||
License Usage
|
||||
|
||||
Licensees holding valid licenses to the AUDIOKINETIC Wwise Technology may use
|
||||
this file in accordance with the end user license agreement provided with the
|
||||
software or, alternatively, in accordance with the terms contained
|
||||
in a written agreement between you and Audiokinetic Inc.
|
||||
Copyright (c) 2026 Audiokinetic Inc.
|
||||
*******************************************************************************/
|
||||
|
||||
#if AK_ENABLE_OPENXR
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.XR.OpenXR;
|
||||
using UnityEngine.XR.OpenXR.Features;
|
||||
|
||||
using AK.Wwise.Unity.Logging;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEditor.XR.OpenXR.Features;
|
||||
#endif
|
||||
|
||||
namespace AK.Wwise.Unity.OpenXR
|
||||
{
|
||||
/// <summary>
|
||||
/// Enables Wwise Motion haptics support for Meta Quest devices via OpenXR.
|
||||
/// This feature bridges Unity's OpenXR plugin with the Wwise AkMotion plugin.
|
||||
/// </summary>
|
||||
#if UNITY_EDITOR
|
||||
[OpenXRFeature(
|
||||
UiName = "Wwise OpenXR Motion",
|
||||
BuildTargetGroups = new[] { BuildTargetGroup.Android, BuildTargetGroup.Standalone },
|
||||
Company = "Audiokinetic",
|
||||
Desc = "Wwise Motion haptics support via OpenXR for Meta Quest devices.",
|
||||
DocumentationLink = "https://www.audiokinetic.com/",
|
||||
OpenxrExtensionStrings = "XR_FB_haptic_pcm",
|
||||
Version = "1.0.0",
|
||||
FeatureId = featureId
|
||||
)]
|
||||
#endif
|
||||
public class AkWwiseOpenXRMotionFeature : OpenXRFeature
|
||||
{
|
||||
public const string featureId = "com.audiokinetic.wwise.openxr.motion";
|
||||
|
||||
// Event that fires when OpenXR Motion is initialized and ready.
|
||||
public static event System.Action OnOpenXRMotionInitialized;
|
||||
|
||||
private static bool s_isInitialized = false;
|
||||
public static bool IsInitialized => s_isInitialized;
|
||||
|
||||
// Unity creates one feature instance per BuildTargetGroup (Android, Standalone),
|
||||
// but only the active build target's instance receives OpenXR callbacks (OnInstanceCreate, OnSessionCreate).
|
||||
// We set s_instance in OnInstanceCreate() to identify which instance has valid OpenXR handles.
|
||||
private static AkWwiseOpenXRMotionFeature s_instance = null;
|
||||
|
||||
// OpenXR handles
|
||||
private ulong m_xrInstance = 0;
|
||||
private ulong m_xrSession = 0;
|
||||
private ulong m_xrHapticAction = 0;
|
||||
private System.IntPtr m_xrGetInstanceProcAddr = System.IntPtr.Zero;
|
||||
|
||||
public static AkWwiseOpenXRMotionFeature Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_instance == null)
|
||||
{
|
||||
s_instance = OpenXRSettings.Instance?.GetFeature<AkWwiseOpenXRMotionFeature>();
|
||||
}
|
||||
return s_instance;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
if (s_instance == this) // Only clear s_instance if we're the active instance
|
||||
{
|
||||
s_instance = null;
|
||||
}
|
||||
base.OnDisable();
|
||||
}
|
||||
|
||||
protected override System.IntPtr HookGetInstanceProcAddr(System.IntPtr func)
|
||||
{
|
||||
m_xrGetInstanceProcAddr = func;
|
||||
return base.HookGetInstanceProcAddr(func);
|
||||
}
|
||||
|
||||
// Called when an OpenXR instance is created. Captures the XrInstance handle.
|
||||
// Only called for the active build target's feature instance.
|
||||
protected override bool OnInstanceCreate(ulong xrInstance)
|
||||
{
|
||||
m_xrInstance = xrInstance;
|
||||
s_instance = this; // This instance is the active one - set as singleton
|
||||
return base.OnInstanceCreate(xrInstance);
|
||||
}
|
||||
|
||||
protected override void OnInstanceDestroy(ulong xrInstance)
|
||||
{
|
||||
m_xrInstance = 0;
|
||||
base.OnInstanceDestroy(xrInstance);
|
||||
}
|
||||
|
||||
// Called when an OpenXR session is created. Captures the XrSession handle.
|
||||
protected override void OnSessionCreate(ulong xrSession)
|
||||
{
|
||||
m_xrSession = xrSession;
|
||||
InputSystem.onAfterUpdate -= OnInputSystemAfterUpdate;
|
||||
InputSystem.onAfterUpdate += OnInputSystemAfterUpdate;
|
||||
base.OnSessionCreate(xrSession);
|
||||
}
|
||||
|
||||
protected override void OnSessionDestroy(ulong xrSession)
|
||||
{
|
||||
InputSystem.onAfterUpdate -= OnInputSystemAfterUpdate;
|
||||
m_xrSession = 0;
|
||||
m_xrHapticAction = 0;
|
||||
base.OnSessionDestroy(xrSession);
|
||||
}
|
||||
|
||||
// Will be called until the Input System's controller is ready. Then we unregister the callback.
|
||||
static void OnInputSystemAfterUpdate()
|
||||
{
|
||||
if (AkUnitySoundEngine.IsInitialized())
|
||||
{
|
||||
if (Instance && Instance.SetWwiseMotionOpenXREnvironment())
|
||||
{
|
||||
InputSystem.onAfterUpdate -= OnInputSystemAfterUpdate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This method fails if the Unity Input System is not ready and can be called again on the next frame.
|
||||
public bool SetWwiseMotionOpenXREnvironment()
|
||||
{
|
||||
if (m_xrInstance == 0 || m_xrSession == 0)
|
||||
{
|
||||
WwiseLogger.Error("[AkWwiseOpenXRMotionFeature] XrInstance or XrSession are invalid.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Getting the haptic action from any of the two controller is valid since it resolves to the same XrAction.
|
||||
if (!TryGetHapticActionHandle("<XRController>{LeftHand}/haptic") && !TryGetHapticActionHandle("<XRController>{RightHand}/haptic"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!AkWwiseOpenXRMotionBridge.Initialize(m_xrGetInstanceProcAddr, m_xrInstance, m_xrSession, m_xrHapticAction))
|
||||
{
|
||||
WwiseLogger.Error("[AkWwiseOpenXRMotionFeature] Failed to initialize AkMotion bridge");
|
||||
return false;
|
||||
}
|
||||
|
||||
WwiseLogger.Log("[AkWwiseOpenXRMotionFeature] Wwise Motion OpenXR integration initialized successfully!");
|
||||
s_isInitialized = true;
|
||||
|
||||
OnOpenXRMotionInitialized?.Invoke();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Retrieves the XrAction handle by piggybacking on the controller profile's existing haptic action.
|
||||
// It will return false silently while waiting for the Input System to bind controls.
|
||||
private bool TryGetHapticActionHandle(string bindingPath)
|
||||
{
|
||||
bool gotAction = false;
|
||||
|
||||
// This relies on a controller profile (e.g., Meta Quest Touch Pro Controller Profile) being enabled.
|
||||
// Note: Any of the hand bindings (LeftHand or RightHand) resolves to the controller profile's unified
|
||||
// haptic output, which automatically applies to both controllers. This is handled by the OpenXR runtime.
|
||||
var hapticAction = new UnityEngine.InputSystem.InputAction(
|
||||
name: "WwiseMotionHaptic",
|
||||
type: UnityEngine.InputSystem.InputActionType.PassThrough,
|
||||
binding: bindingPath
|
||||
);
|
||||
hapticAction.Enable();
|
||||
|
||||
// The control count can be 0 when Unity's Input System is not ready yet. This could happen because the controller profile
|
||||
// is not loaded, the controllers are not detected or action's path is not bound. We need to try again later.
|
||||
if (hapticAction.controls.Count > 0)
|
||||
{
|
||||
m_xrHapticAction = GetAction(hapticAction); // Get the native XrAction handle from Unity OpenXR
|
||||
|
||||
if (m_xrHapticAction != 0)
|
||||
{
|
||||
gotAction = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
WwiseLogger.Error("[AkWwiseOpenXRMotionFeature] Could not get XrAction with control bound.");
|
||||
}
|
||||
}
|
||||
|
||||
hapticAction.Disable(); // Does not need to be enabled once we have the XrAction handle.
|
||||
|
||||
return gotAction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // AK_ENABLE_OPENXR
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 61726edca15cc5c4d8faab9a8a3b58c0
|
||||
@@ -0,0 +1,92 @@
|
||||
/*******************************************************************************
|
||||
The content of this file includes portions of the proprietary AUDIOKINETIC Wwise
|
||||
Technology released in source code form as part of the game integration package.
|
||||
The content of this file may not be used without valid licenses to the AUDIOKINETIC
|
||||
Wwise Technology.
|
||||
Note that the use of the game engine is subject to the Unity Terms of Service
|
||||
at https://unity3d.com/legal/terms-of-service.
|
||||
|
||||
License Usage
|
||||
|
||||
Licensees holding valid licenses to the AUDIOKINETIC Wwise Technology may use
|
||||
this file in accordance with the end user license agreement provided with the
|
||||
software or, alternatively, in accordance with the terms contained
|
||||
in a written agreement between you and Audiokinetic Inc.
|
||||
Copyright (c) 2026 Audiokinetic Inc.
|
||||
*******************************************************************************/
|
||||
|
||||
#if AK_ENABLE_OPENXR
|
||||
|
||||
using AK.Wwise.Unity.Logging;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AK.Wwise.Unity.OpenXR
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper component that adds a Wwise Motion output when OpenXR integration is ready.
|
||||
///
|
||||
/// IMPORTANT: The Motion output must be added AFTER OpenXR is fully initialized for the
|
||||
/// OpenXR Motion sink to be selected. This component handles the correct timing by subscribing
|
||||
/// to AkWwiseOpenXRMotionFeature.OnOpenXRMotionInitialized.
|
||||
///
|
||||
/// Usage: Attach this component to any persistent GameObject.
|
||||
/// It will automatically add the Motion output at the correct time and remove it on destroy.
|
||||
///
|
||||
/// For custom implementations, subscribe to AkWwiseOpenXRMotionFeature.OnOpenXRMotionInitialized
|
||||
/// and call AkUnitySoundEngine.AddOutput(new AkOutputSettings("Motion"), out deviceId) in your handler.
|
||||
/// </summary>
|
||||
[AddComponentMenu("Wwise/Motion Output")]
|
||||
public class AkWwiseOpenXRMotionOutput : MonoBehaviour
|
||||
{
|
||||
private ulong m_motionOutputDeviceId = AkUnitySoundEngine.AK_INVALID_OUTPUT_DEVICE_ID;
|
||||
|
||||
[Tooltip("The name of the Motion shareset in your Wwise project.")]
|
||||
public string MotionSharesetName = "Motion";
|
||||
|
||||
void Start()
|
||||
{
|
||||
// Check if already initialized (in case initialization happened before Start)
|
||||
if (AkWwiseOpenXRMotionFeature.IsInitialized)
|
||||
{
|
||||
AddMotionOutput();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Subscribe to the event
|
||||
AkWwiseOpenXRMotionFeature.OnOpenXRMotionInitialized += AddMotionOutput;
|
||||
}
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
// Always unsubscribe to avoid memory leaks
|
||||
AkWwiseOpenXRMotionFeature.OnOpenXRMotionInitialized -= AddMotionOutput;
|
||||
|
||||
if (m_motionOutputDeviceId != AkUnitySoundEngine.AK_INVALID_OUTPUT_DEVICE_ID)
|
||||
{
|
||||
AkUnitySoundEngine.RemoveOutput(m_motionOutputDeviceId);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddMotionOutput()
|
||||
{
|
||||
// Unsubscribe immediately since we only want this called once
|
||||
AkWwiseOpenXRMotionFeature.OnOpenXRMotionInitialized -= AddMotionOutput;
|
||||
|
||||
if (m_motionOutputDeviceId != AkUnitySoundEngine.AK_INVALID_OUTPUT_DEVICE_ID)
|
||||
return; // Already added
|
||||
|
||||
var outputSettings = new AkOutputSettings(MotionSharesetName);
|
||||
if (AkUnitySoundEngine.AddOutput(outputSettings, out m_motionOutputDeviceId) == AKRESULT.AK_Success)
|
||||
{
|
||||
WwiseLogger.Verbose($"[AkWwiseOpenXRMotionOutput] Successfully added Motion output device (ID: {m_motionOutputDeviceId})");
|
||||
}
|
||||
else
|
||||
{
|
||||
WwiseLogger.Error("[AkWwiseOpenXRMotionOutput] Failed to add Motion output.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // AK_ENABLE_OPENXR
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5819149c005dfa34f94c12dfc34a6b47
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "com.audiokinetic.wwise.openxr",
|
||||
"version": "2025.1.6",
|
||||
"displayName": "Wwise Unity OpenXR Motion",
|
||||
"description": "Wwise Motion haptics support via OpenXR for Meta Quest devices",
|
||||
"unity": "2021.3",
|
||||
"unityRelease": "32f1",
|
||||
"dependencies": {
|
||||
"com.unity.xr.openxr": "1.16.1"
|
||||
},
|
||||
"keywords": [
|
||||
"Wwise",
|
||||
"wwise",
|
||||
"audiokinetic",
|
||||
"ak",
|
||||
"Audiokinetic",
|
||||
"OpenXR",
|
||||
"openxr",
|
||||
"motion",
|
||||
"haptics",
|
||||
"VR"
|
||||
],
|
||||
"author": {
|
||||
"name": "Audiokinetic Inc.",
|
||||
"email": "info@audiokinetic.com",
|
||||
"url": "https://www.audiokinetic.com"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5cd93a947f5a8df4f8485913873ca753
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user