Interhaptics SDK for Unity 1.6
Loading...
Searching...
No Matches
UnityXRHapticAbstraction.cs
Go to the documentation of this file.
1/* ​
2* Copyright (c) 2023 Go Touch VR SAS. All rights reserved. ​
3* ​
4*/
5
7{
8
9 internal static class UnityXRHapticAbstraction
10 {
11
12 internal static void VibrateBoth(float seconds, double[] amplitude)
13 {
14 seconds = UnityEngine.Mathf.Max(UnityEngine.Time.fixedDeltaTime, seconds);
15 System.Collections.Generic.List<UnityEngine.XR.XRNodeState> nodeStates = new System.Collections.Generic.List<UnityEngine.XR.XRNodeState>();
16 UnityEngine.XR.InputTracking.GetNodeStates(nodeStates);
17 foreach (UnityEngine.XR.XRNodeState nodeState in nodeStates)
18 {
19 if (nodeState.nodeType == UnityEngine.XR.XRNode.LeftHand)
20 {
21 VibrateLeft(seconds, amplitude);
22 }
23 else if (nodeState.nodeType == UnityEngine.XR.XRNode.RightHand)
24 {
25 VibrateRight(seconds, amplitude);
26 }
27 }
28 }
29
30 internal static bool VibrateLeft(float seconds, double[] amplitude)
31 {
32 seconds = UnityEngine.Mathf.Max(UnityEngine.Time.fixedDeltaTime, seconds);
33 return VibrateXRNode(seconds, UnityEngine.XR.XRNode.LeftHand, amplitude);
34 }
35
36 internal static bool VibrateRight(float seconds, double[] amplitude)
37 {
38 seconds = UnityEngine.Mathf.Max(UnityEngine.Time.fixedDeltaTime, seconds);
39 return VibrateXRNode(seconds, UnityEngine.XR.XRNode.RightHand, amplitude);
40 }
41
49 internal static bool VibrateXRNode(float seconds, UnityEngine.XR.XRNode node, double[] amplitude)
50 {
51 UnityEngine.XR.HapticCapabilities caps = new UnityEngine.XR.HapticCapabilities();
52 if (!UnityEngine.XR.InputDevices.GetDeviceAtXRNode(node).TryGetHapticCapabilities(out caps))
53 {
54 UnityEngine.Debug.LogWarning("HAR ERROR!: " + node.ToString() + " doesn't support haptic feedback or not connected to your system!");
55 return false;
56 }
57
58 if (caps.supportsBuffer)
59 {
60 byte[] clip = { };
61#if UNITY_EDITOR||UNITY_STANDALONE_WIN
62 return UnityEngine.XR.InputDevices.GetDeviceAtXRNode(node).SendHapticImpulse(0, (float)PulseFromBuffer(amplitude), seconds);
63#else
64 return GenerateHapticClip(seconds, node, ref clip, amplitude) ? UnityEngine.XR.InputDevices.GetDeviceAtXRNode(node).SendHapticBuffer(0, clip) : false;
65#endif
66 }
67 else if (caps.supportsImpulse)
68 {
69 return UnityEngine.XR.InputDevices.GetDeviceAtXRNode(node).SendHapticImpulse(0, (float)PulseFromBuffer(amplitude), seconds);
70 }
71 else
72 {
73 UnityEngine.Debug.LogWarning("HAR ERROR!: " + node.ToString() + " doesn't support buffer or impulse!");
74 return false;
75 }
76 }
77
78 internal static double PulseFromBuffer(double[] _buffer)
79 {
80 if ((_buffer == null) || (_buffer.Length == 0))
81 {
82 return 0;
83 }
84
85 double result = 0;
86 for (int i = 0; i < _buffer.Length; i++)
87 {
88 result += _buffer[i];
89 }
90
91 return UnityEngine.Mathf.Clamp((float)(result / _buffer.Length), 0, 1);
92 }
93
94
95 //Generates a haptic clip of the proper size from an input buffer
96 internal static bool GenerateHapticClip(float seconds, UnityEngine.XR.XRNode node, ref byte[] clip, double[] amplitudes)
97 {
98 UnityEngine.XR.HapticCapabilities caps = new UnityEngine.XR.HapticCapabilities();
99
100 if (!UnityEngine.XR.InputDevices.GetDeviceAtXRNode(node).TryGetHapticCapabilities(out caps))
101 {
102 return false;
103 }
104
105 //create clips with proper size
106 int clipCount = (int)((double)caps.bufferFrequencyHz * seconds);
107 clip = new byte[clipCount];
108
109 if (clip.Length <= 0)
110 {
111 return false;
112 }
113
114 if (clip.Length == 1)
115 {
116 clip[0] = (byte)(PulseFromBuffer(amplitudes) * (double)byte.MaxValue);
117 }
118 else
119 {
120 double i = 0;
121 int j = 0;
122
123 //fill clip with smoothed values
124 for (i = 0, j = 0; UnityEngine.Mathf.CeilToInt((float)i) < amplitudes.Length && j < clip.Length; i += (amplitudes.Length - 1.0f) / (clip.Length - 1.0f), j++)
125 {
126 double a = amplitudes[UnityEngine.Mathf.FloorToInt((float)i)]
127 + (j * (amplitudes.Length - 1.0f) / (clip.Length - 1.0f) - UnityEngine.Mathf.FloorToInt((float)i))
128 * (amplitudes[UnityEngine.Mathf.CeilToInt((float)i)] - amplitudes[UnityEngine.Mathf.FloorToInt((float)i)]);
129 clip[j] = (byte)(a * (double)byte.MaxValue);
130 }
131 }
132
133 return true;
134 }
135 }
136}