You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
274 lines
15 KiB
274 lines
15 KiB
3 years ago
|
using HTC.UnityPlugin.Utility;
|
||
|
using HTC.UnityPlugin.Vive;
|
||
|
using UnityEngine;
|
||
|
#if VIU_WAVEVR && UNITY_ANDROID
|
||
|
using wvr;
|
||
|
#endif
|
||
|
|
||
|
namespace HTC.UnityPlugin.VRModuleManagement
|
||
|
{
|
||
|
public sealed class WaveVRModule : VRModule.ModuleBase
|
||
|
{
|
||
|
#if VIU_WAVEVR && UNITY_ANDROID
|
||
|
private const uint HMD_INDEX = 0;
|
||
|
private const uint RIGHT_INDEX = 1;
|
||
|
private const uint LEFT_INDEX = 2;
|
||
|
private const uint DEVICE_COUNT = 3;
|
||
|
private const uint INPUT_TYPE = (uint)(WVR_InputType.WVR_InputType_Button | WVR_InputType.WVR_InputType_Touch | WVR_InputType.WVR_InputType_Analog);
|
||
|
|
||
|
public static readonly Vector3 DEFAULT_NECK_POSITION = new Vector3(0.0f, -0.15f, 0.0f);
|
||
|
public static readonly Vector3 DEFAULT_ELBOW_REST_POSITION = new Vector3(0.195f, -0.5f, 0.005f);
|
||
|
public static readonly Vector3 DEFAULT_WRIST_REST_POSITION = new Vector3(0.0f, 0.0f, 0.25f);
|
||
|
public static readonly Vector3 DEFAULT_CONTROLLER_REST_POSITION = new Vector3(0.0f, 0.0f, 0.05f);
|
||
|
public static readonly Vector3 DEFAULT_ARM_EXTENSION_OFFSET = new Vector3(-0.13f, 0.14f, 0.08f);
|
||
|
public static readonly Vector3 RIGHT_ARM_MULTIPLIER = new Vector3(1f, 1f, 1f);
|
||
|
public static readonly Vector3 LEFT_ARM_MULTIPLIER = new Vector3(1f, 1f, 1f);
|
||
|
public const float DEFAULT_ELBOW_BEND_RATIO = 0.6f;
|
||
|
public const float MIN_EXTENSION_ANGLE = 7.0f;
|
||
|
public const float MAX_EXTENSION_ANGLE = 60.0f;
|
||
|
public const float EXTENSION_WEIGHT = 0.4f;
|
||
|
|
||
|
private Vector3 handedMultiplier;
|
||
|
|
||
|
private WVR_DeviceType[] m_deviceTypes = new WVR_DeviceType[]
|
||
|
{
|
||
|
WVR_DeviceType.WVR_DeviceType_HMD,
|
||
|
WVR_DeviceType.WVR_DeviceType_Controller_Right,
|
||
|
WVR_DeviceType.WVR_DeviceType_Controller_Left,
|
||
|
};
|
||
|
private WVR_DevicePosePair_t[] m_poses = new WVR_DevicePosePair_t[DEVICE_COUNT]; // HMD, R, L controllers.
|
||
|
private WVR_AnalogState_t[] m_analogStates = new WVR_AnalogState_t[2];
|
||
|
|
||
|
public override bool ShouldActiveModule()
|
||
|
{
|
||
|
return !Application.isEditor && VIUSettings.activateWaveVRModule;
|
||
|
}
|
||
|
|
||
|
public override void OnActivated()
|
||
|
{
|
||
|
var instance = Object.FindObjectOfType<WaveVR_Init>();
|
||
|
if (instance == null)
|
||
|
{
|
||
|
VRModule.Instance.gameObject.AddComponent<WaveVR_Init>();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override void OnDeactivated() { }
|
||
|
|
||
|
public override uint GetRightControllerDeviceIndex() { return RIGHT_INDEX; }
|
||
|
|
||
|
public override uint GetLeftControllerDeviceIndex() { return LEFT_INDEX; }
|
||
|
|
||
|
public override void UpdateDeviceState(IVRModuleDeviceState[] prevState, IVRModuleDeviceStateRW[] currState)
|
||
|
{
|
||
|
if (WaveVR.Instance == null) { return; }
|
||
|
|
||
|
WVR_PoseOriginModel poseOrigin;
|
||
|
switch (VRModule.trackingSpaceType)
|
||
|
{
|
||
|
case VRModuleTrackingSpaceType.RoomScale:
|
||
|
{ poseOrigin = WVR_PoseOriginModel.WVR_PoseOriginModel_OriginOnGround; break; }
|
||
|
case VRModuleTrackingSpaceType.Stationary:
|
||
|
default:
|
||
|
{ poseOrigin = WVR_PoseOriginModel.WVR_PoseOriginModel_OriginOnHead; break; }
|
||
|
}
|
||
|
|
||
|
IVRModuleDeviceStateRW headState = null;
|
||
|
IVRModuleDeviceStateRW rightState = null;
|
||
|
IVRModuleDeviceStateRW leftState = null;
|
||
|
|
||
|
Interop.WVR_GetSyncPose(poseOrigin, m_poses, DEVICE_COUNT);
|
||
|
|
||
|
for (int i = 0; i < DEVICE_COUNT; ++i)
|
||
|
{
|
||
|
var deviceType = m_poses[i].type;
|
||
|
var devicePose = m_poses[i].pose;
|
||
|
|
||
|
if (deviceType == m_deviceTypes[i])
|
||
|
{
|
||
|
currState[i].isConnected = true;
|
||
|
if (deviceType == WVR_DeviceType.WVR_DeviceType_HMD)
|
||
|
{
|
||
|
currState[i].deviceClass = VRModuleDeviceClass.HMD;
|
||
|
currState[i].deviceModel = VRModuleDeviceModel.ViveFocusHMD;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
currState[i].deviceClass = VRModuleDeviceClass.Controller;
|
||
|
currState[i].deviceModel = VRModuleDeviceModel.ViveFocusFinch;
|
||
|
}
|
||
|
|
||
|
var rigidTransform = new WaveVR_Utils.RigidTransform(devicePose.PoseMatrix);
|
||
|
|
||
|
currState[i].isPoseValid = devicePose.IsValidPose;
|
||
|
currState[i].isOutOfRange = false;
|
||
|
currState[i].isCalibrating = false;
|
||
|
currState[i].isUninitialized = false;
|
||
|
|
||
|
currState[i].velocity = new Vector3(devicePose.Velocity.v0, devicePose.Velocity.v1, -devicePose.Velocity.v2);
|
||
|
currState[i].angularVelocity = new Vector3(-devicePose.AngularVelocity.v0, -devicePose.AngularVelocity.v1, devicePose.AngularVelocity.v2);
|
||
|
|
||
|
currState[i].position = rigidTransform.pos;
|
||
|
currState[i].rotation = rigidTransform.rot;
|
||
|
|
||
|
switch (deviceType)
|
||
|
{
|
||
|
case WVR_DeviceType.WVR_DeviceType_HMD:
|
||
|
headState = currState[i];
|
||
|
break;
|
||
|
case WVR_DeviceType.WVR_DeviceType_Controller_Right:
|
||
|
rightState = currState[i];
|
||
|
break;
|
||
|
case WVR_DeviceType.WVR_DeviceType_Controller_Left:
|
||
|
leftState = currState[i];
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
uint buttons = 0;
|
||
|
uint touches = 0;
|
||
|
|
||
|
// FIXME: What does WVR_GetInputTypeCount means?
|
||
|
//var analogCount = Interop.WVR_GetInputTypeCount(deviceType, WVR_InputType.WVR_InputType_Analog);
|
||
|
//if (m_analogStates == null || m_analogStates.Length < analogCount) { m_analogStates = new WVR_AnalogState_t[analogCount]; }
|
||
|
|
||
|
#if VIU_WAVEVR_2_0_32_OR_NEWER
|
||
|
if (Interop.WVR_GetInputDeviceState(deviceType, INPUT_TYPE, ref buttons, ref touches, m_analogStates, (uint)m_analogStates.Length))
|
||
|
#else
|
||
|
if (Interop.WVR_GetInputDeviceState(deviceType, INPUT_TYPE, ref buttons, ref touches, m_analogStates, m_analogStates.Length))
|
||
|
#endif
|
||
|
{
|
||
|
const uint dpadMask =
|
||
|
(1 << (int)(WVR_InputId.WVR_InputId_Alias1_Touchpad)) |
|
||
|
(1 << (int)(WVR_InputId.WVR_InputId_Alias1_DPad_Left)) |
|
||
|
(1 << (int)(WVR_InputId.WVR_InputId_Alias1_DPad_Up)) |
|
||
|
(1 << (int)(WVR_InputId.WVR_InputId_Alias1_DPad_Right)) |
|
||
|
(1 << (int)(WVR_InputId.WVR_InputId_Alias1_DPad_Down));
|
||
|
|
||
|
const uint triggerBumperMask =
|
||
|
(1 << (int)(WVR_InputId.WVR_InputId_Alias1_Trigger)) |
|
||
|
(1 << (int)(WVR_InputId.WVR_InputId_Alias1_Bumper));
|
||
|
|
||
|
currState[i].SetButtonPress(VRModuleRawButton.System, (buttons & (1 << (int)WVR_InputId.WVR_InputId_Alias1_System)) != 0u);
|
||
|
currState[i].SetButtonPress(VRModuleRawButton.ApplicationMenu, (buttons & (1 << (int)WVR_InputId.WVR_InputId_Alias1_Menu)) != 0u);
|
||
|
currState[i].SetButtonPress(VRModuleRawButton.Touchpad, (buttons & dpadMask) != 0u);
|
||
|
currState[i].SetButtonPress(VRModuleRawButton.Trigger, (buttons & triggerBumperMask) != 0u);
|
||
|
currState[i].SetButtonPress(VRModuleRawButton.Grip, (buttons & (1 << (int)WVR_InputId.WVR_InputId_Alias1_Grip)) != 0u);
|
||
|
currState[i].SetButtonPress(VRModuleRawButton.DPadLeft, (buttons & (1 << (int)WVR_InputId.WVR_InputId_Alias1_DPad_Left)) != 0u);
|
||
|
currState[i].SetButtonPress(VRModuleRawButton.DPadUp, (buttons & (1 << (int)WVR_InputId.WVR_InputId_Alias1_DPad_Up)) != 0u);
|
||
|
currState[i].SetButtonPress(VRModuleRawButton.DPadRight, (buttons & (1 << (int)WVR_InputId.WVR_InputId_Alias1_DPad_Right)) != 0u);
|
||
|
currState[i].SetButtonPress(VRModuleRawButton.DPadDown, (buttons & (1 << (int)WVR_InputId.WVR_InputId_Alias1_DPad_Down)) != 0u);
|
||
|
|
||
|
currState[i].SetButtonTouch(VRModuleRawButton.System, (touches & (1 << (int)WVR_InputId.WVR_InputId_Alias1_System)) != 0u);
|
||
|
currState[i].SetButtonTouch(VRModuleRawButton.ApplicationMenu, (touches & (1 << (int)WVR_InputId.WVR_InputId_Alias1_Menu)) != 0u);
|
||
|
currState[i].SetButtonTouch(VRModuleRawButton.Touchpad, (touches & dpadMask) != 0u);
|
||
|
currState[i].SetButtonTouch(VRModuleRawButton.Trigger, (touches & triggerBumperMask) != 0u);
|
||
|
currState[i].SetButtonTouch(VRModuleRawButton.Grip, (touches & (1 << (int)WVR_InputId.WVR_InputId_Alias1_Grip)) != 0u);
|
||
|
currState[i].SetButtonTouch(VRModuleRawButton.DPadLeft, (touches & (1 << (int)WVR_InputId.WVR_InputId_Alias1_DPad_Left)) != 0u);
|
||
|
currState[i].SetButtonTouch(VRModuleRawButton.DPadUp, (touches & (1 << (int)WVR_InputId.WVR_InputId_Alias1_DPad_Up)) != 0u);
|
||
|
currState[i].SetButtonTouch(VRModuleRawButton.DPadRight, (touches & (1 << (int)WVR_InputId.WVR_InputId_Alias1_DPad_Right)) != 0u);
|
||
|
currState[i].SetButtonTouch(VRModuleRawButton.DPadDown, (touches & (1 << (int)WVR_InputId.WVR_InputId_Alias1_DPad_Down)) != 0u);
|
||
|
|
||
|
for (int j = 0, jmax = m_analogStates.Length; j < jmax; ++j)
|
||
|
{
|
||
|
switch (m_analogStates[j].id)
|
||
|
{
|
||
|
case WVR_InputId.WVR_InputId_Alias1_Trigger:
|
||
|
if (m_analogStates[j].type == WVR_AnalogType.WVR_AnalogType_Trigger)
|
||
|
{
|
||
|
currState[i].SetAxisValue(VRModuleRawAxis.Trigger, m_analogStates[j].axis.x);
|
||
|
}
|
||
|
break;
|
||
|
case WVR_InputId.WVR_InputId_Alias1_Touchpad:
|
||
|
if (m_analogStates[j].type == WVR_AnalogType.WVR_AnalogType_TouchPad && currState[i].GetButtonTouch(VRModuleRawButton.Touchpad))
|
||
|
{
|
||
|
currState[i].SetAxisValue(VRModuleRawAxis.TouchpadX, m_analogStates[j].axis.x);
|
||
|
currState[i].SetAxisValue(VRModuleRawAxis.TouchpadY, m_analogStates[j].axis.y);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
currState[i].SetAxisValue(VRModuleRawAxis.TouchpadX, 0f);
|
||
|
currState[i].SetAxisValue(VRModuleRawAxis.TouchpadY, 0f);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
currState[i].buttonPressed = 0u;
|
||
|
currState[i].buttonTouched = 0u;
|
||
|
for (int j = 0, jmax = currState[i].axisValue.Length; j < jmax; ++j) { currState[i].axisValue[j] = 0f; }
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (prevState[i].isConnected)
|
||
|
{
|
||
|
currState[i].Reset();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// add right arm
|
||
|
if (rightState != null && rightState.isConnected && rightState.position == Vector3.zero)
|
||
|
{
|
||
|
rightState.position = GetControllerPositionWithVirtualArm(GetNeckPose(headState.pose), rightState.rotation, RIGHT_ARM_MULTIPLIER);
|
||
|
}
|
||
|
|
||
|
// add left arm
|
||
|
if (leftState != null && leftState.isConnected && leftState.position == Vector3.zero)
|
||
|
{
|
||
|
leftState.position = GetControllerPositionWithVirtualArm(GetNeckPose(headState.pose), leftState.rotation, LEFT_ARM_MULTIPLIER);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static RigidPose GetNeckPose(RigidPose headPose)
|
||
|
{
|
||
|
var headForward = headPose.forward;
|
||
|
return new RigidPose(headPose.pos + DEFAULT_NECK_POSITION, Quaternion.FromToRotation(Vector3.forward, new Vector3(headForward.x, 0f, headForward.z)));
|
||
|
}
|
||
|
|
||
|
private static float GetExtensionRatio(Vector3 v)
|
||
|
{
|
||
|
var xAngle = 90f - Vector3.Angle(v, Vector3.up);
|
||
|
return Mathf.Clamp01(Mathf.InverseLerp(MIN_EXTENSION_ANGLE, MAX_EXTENSION_ANGLE, xAngle));
|
||
|
}
|
||
|
|
||
|
private static Quaternion GetLerpRotation(Quaternion xyRotation, float extensionRatio)
|
||
|
{
|
||
|
float totalAngle = Quaternion.Angle(xyRotation, Quaternion.identity);
|
||
|
float lerpSuppresion = 1.0f - Mathf.Pow(totalAngle / 180.0f, 6.0f);
|
||
|
float inverseElbowBendRatio = 1.0f - DEFAULT_ELBOW_BEND_RATIO;
|
||
|
float lerpValue = inverseElbowBendRatio + DEFAULT_ELBOW_BEND_RATIO * extensionRatio * EXTENSION_WEIGHT;
|
||
|
lerpValue *= lerpSuppresion;
|
||
|
return Quaternion.Lerp(Quaternion.identity, xyRotation, lerpValue);
|
||
|
}
|
||
|
|
||
|
private static Vector3 GetControllerPositionWithVirtualArm(RigidPose neckPose, Quaternion ctrlRot, Vector3 sideMultiplier)
|
||
|
{
|
||
|
var localCtrlForward = (Quaternion.Inverse(neckPose.rot) * ctrlRot) * Vector3.forward;
|
||
|
var localCtrlXYRot = Quaternion.FromToRotation(Vector3.forward, localCtrlForward);
|
||
|
var extensionRatio = GetExtensionRatio(localCtrlForward);
|
||
|
var lerpRotation = GetLerpRotation(localCtrlXYRot, extensionRatio);
|
||
|
|
||
|
var elbowPose = new RigidPose(
|
||
|
Vector3.Scale(DEFAULT_ELBOW_REST_POSITION, sideMultiplier) + Vector3.Scale(DEFAULT_ARM_EXTENSION_OFFSET, sideMultiplier) * extensionRatio,
|
||
|
Quaternion.Inverse(lerpRotation) * localCtrlXYRot);
|
||
|
var wristPose = new RigidPose(
|
||
|
Vector3.Scale(DEFAULT_WRIST_REST_POSITION, sideMultiplier),
|
||
|
lerpRotation);
|
||
|
var palmPose = new RigidPose(
|
||
|
Vector3.Scale(DEFAULT_CONTROLLER_REST_POSITION, sideMultiplier),
|
||
|
Quaternion.identity);
|
||
|
|
||
|
var finalCtrlPose = neckPose * elbowPose * wristPose * palmPose;
|
||
|
return finalCtrlPose.pos;
|
||
|
}
|
||
|
|
||
|
public override void TriggerViveControllerHaptic(uint deviceIndex, ushort durationMicroSec = 500)
|
||
|
{
|
||
|
Interop.WVR_TriggerVibrator(m_deviceTypes[deviceIndex], WVR_InputId.WVR_InputId_Alias1_Touchpad, durationMicroSec);
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
}
|