2021년 4학년 1학기 기업연계프로젝트2 컴퓨터소프트웨어공학과 <원광투어팀> 팀장 : 송유진 팀원 : 김나영, 이경희, 한유진
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.
 
 
 
 
 

328 lines
13 KiB

//========= Copyright 2016-2020, HTC Corporation. All rights reserved. ===========
#pragma warning disable 0618
#if UNITY_2017_1_OR_NEWER
using HTC.UnityPlugin.Utility;
using System.Collections.Generic;
using UnityEngine;
#if UNITY_2017_2_OR_NEWER
using UnityEngine.XR;
#else
using UnityEngine.VR;
using XRSettings = UnityEngine.VR.VRSettings;
using XRDevice = UnityEngine.VR.VRDevice;
using XRNodeState = UnityEngine.VR.VRNodeState;
using XRNode = UnityEngine.VR.VRNode;
#endif
#endif
namespace HTC.UnityPlugin.VRModuleManagement
{
public sealed partial class UnityEngineVRModule : VRModule.ModuleBase
{
#if UNITY_2017_1_OR_NEWER && !UNITY_2020_1_OR_NEWER
private static readonly VRModuleDeviceClass[] s_nodeType2DeviceClass;
private uint m_leftIndex = INVALID_DEVICE_INDEX;
private uint m_rightIndex = INVALID_DEVICE_INDEX;
private List<XRNodeState> m_nodeStateList = new List<XRNodeState>();
private Dictionary<ulong, uint> m_node2Index = new Dictionary<ulong, uint>();
private ulong[] m_index2nodeID;
private bool[] m_index2nodeValidity;
private bool[] m_index2nodeTouched;
private TrackingSpaceType m_prevTrackingSpace;
static UnityEngineVRModule()
{
s_nodeType2DeviceClass = new VRModuleDeviceClass[EnumUtils.GetMaxValue(typeof(XRNode)) + 1];
for (int i = 0; i < s_nodeType2DeviceClass.Length; ++i) { s_nodeType2DeviceClass[i] = VRModuleDeviceClass.Invalid; }
s_nodeType2DeviceClass[(int)XRNode.Head] = VRModuleDeviceClass.HMD;
s_nodeType2DeviceClass[(int)XRNode.RightHand] = VRModuleDeviceClass.Controller;
s_nodeType2DeviceClass[(int)XRNode.LeftHand] = VRModuleDeviceClass.Controller;
s_nodeType2DeviceClass[(int)XRNode.GameController] = VRModuleDeviceClass.Controller;
s_nodeType2DeviceClass[(int)XRNode.HardwareTracker] = VRModuleDeviceClass.GenericTracker;
s_nodeType2DeviceClass[(int)XRNode.TrackingReference] = VRModuleDeviceClass.TrackingReference;
}
public override void OnActivated()
{
m_prevTrackingSpace = XRDevice.GetTrackingSpaceType();
UpdateTrackingSpaceType();
EnsureDeviceStateLength(16);
m_index2nodeID = new ulong[GetDeviceStateLength()];
m_index2nodeValidity = new bool[GetDeviceStateLength()];
m_index2nodeTouched = new bool[GetDeviceStateLength()];
}
public override void OnDeactivated()
{
m_rightIndex = INVALID_DEVICE_INDEX;
m_leftIndex = INVALID_DEVICE_INDEX;
RemoveAllValidNodes();
XRDevice.SetTrackingSpaceType(m_prevTrackingSpace);
}
public override uint GetLeftControllerDeviceIndex() { return m_leftIndex; }
public override uint GetRightControllerDeviceIndex() { return m_rightIndex; }
public override void UpdateTrackingSpaceType()
{
switch (VRModule.trackingSpaceType)
{
case VRModuleTrackingSpaceType.Stationary:
XRDevice.SetTrackingSpaceType(TrackingSpaceType.Stationary);
break;
case VRModuleTrackingSpaceType.RoomScale:
#if UNITY_2019_2_OR_NEWER && !UNITY_2019_3_OR_NEWER
var prev_trackingOrigin = XRDevice.trackingOriginMode;
XRDevice.SetTrackingSpaceType(TrackingSpaceType.RoomScale);
if (prev_trackingOrigin == XRDevice.trackingOriginMode)
{
XRDevice.SetTrackingSpaceType(TrackingSpaceType.Stationary);
}
#else
XRDevice.SetTrackingSpaceType(TrackingSpaceType.RoomScale);
#endif
break;
}
}
private bool IsTrackingDeviceNode(XRNodeState nodeState)
{
switch (nodeState.nodeType)
{
case XRNode.Head:
case XRNode.RightHand:
case XRNode.LeftHand:
case XRNode.GameController:
case XRNode.HardwareTracker:
case XRNode.TrackingReference:
return true;
default:
return false;
}
}
private bool TryGetAndTouchNodeDeviceIndex(XRNodeState nodeState, out uint deviceIndex)
{
// only tracking certain type of node (some nodes share same uniqueID)
if (!IsTrackingDeviceNode(nodeState)) { deviceIndex = INVALID_DEVICE_INDEX; return false; }
//Debug.Log(Time.frameCount + " TryGetNodeDeviceIndex " + nodeState.nodeType + " tracked=" + nodeState.tracked + " id=" + nodeState.uniqueID + " name=" + (InputTracking.GetNodeName(nodeState.uniqueID) ?? string.Empty));
if (!m_node2Index.TryGetValue(nodeState.uniqueID, out deviceIndex))
{
// FIXME: 0ul is invalid id?
if (nodeState.uniqueID == 0ul) { return false; }
var validIndexFound = false;
if (nodeState.nodeType == XRNode.Head)
{
if (m_index2nodeValidity[0])
{
//Debug.LogWarning("[" + Time.frameCount + "] Multiple Head node found! drop node id:" + nodeState.uniqueID.ToString("X8") + " type:" + nodeState.nodeType + " name:" + InputTracking.GetNodeName(nodeState.uniqueID) + " tracked=" + nodeState.tracked);
deviceIndex = INVALID_DEVICE_INDEX;
return false;
}
validIndexFound = true;
m_index2nodeID[0] = nodeState.uniqueID;
m_index2nodeValidity[0] = true;
m_node2Index.Add(nodeState.uniqueID, 0u);
deviceIndex = 0;
}
else
{
for (uint i = 1u, imax = (uint)m_index2nodeValidity.Length; i < imax; ++i)
{
if (!m_index2nodeValidity[i])
{
validIndexFound = true;
m_index2nodeID[i] = nodeState.uniqueID;
m_index2nodeValidity[i] = true;
m_node2Index.Add(nodeState.uniqueID, i);
deviceIndex = i;
break;
}
}
}
if (!validIndexFound)
{
Debug.LogWarning("[" + Time.frameCount + "] XRNode added, but device index out of range, drop the node id:" + nodeState.uniqueID.ToString("X8") + " type:" + nodeState.nodeType + " name:" + InputTracking.GetNodeName(nodeState.uniqueID) + " tracked=" + nodeState.tracked);
deviceIndex = INVALID_DEVICE_INDEX;
return false;
}
//Debug.Log("[" + Time.frameCount + "] Add node device index [" + deviceIndex + "] id=" + nodeState.uniqueID.ToString("X8") + " type=" + nodeState.nodeType + " tracked=" + nodeState.tracked);
}
m_index2nodeTouched[deviceIndex] = true;
return true;
}
private void TrimUntouchedNodes(System.Action<uint> onTrimmed)
{
for (uint i = 0u, imax = (uint)m_index2nodeValidity.Length; i < imax; ++i)
{
if (!m_index2nodeTouched[i])
{
if (m_index2nodeValidity[i])
{
m_node2Index.Remove(m_index2nodeID[i]);
//m_index2nodeID[i] = 0;
m_index2nodeValidity[i] = false;
onTrimmed(i);
}
}
else
{
Debug.Assert(m_index2nodeValidity[i]);
m_index2nodeTouched[i] = false;
}
}
}
private void RemoveAllValidNodes()
{
for (int i = 0, imax = m_index2nodeValidity.Length; i < imax; ++i)
{
if (m_index2nodeValidity[i])
{
m_node2Index.Remove(m_index2nodeID[i]);
m_index2nodeID[i] = 0;
m_index2nodeValidity[i] = false;
m_index2nodeTouched[i] = false;
}
}
}
public override void BeforeRenderUpdate()
{
var roleChanged = false;
var rightIndex = INVALID_DEVICE_INDEX;
var leftIndex = INVALID_DEVICE_INDEX;
FlushDeviceState();
if (XRSettings.isDeviceActive && XRDevice.isPresent)
{
InputTracking.GetNodeStates(m_nodeStateList);
}
for (int i = 0, imax = m_nodeStateList.Count; i < imax; ++i)
{
uint deviceIndex;
if (!TryGetAndTouchNodeDeviceIndex(m_nodeStateList[i], out deviceIndex)) { continue; }
switch (m_nodeStateList[i].nodeType)
{
case XRNode.RightHand: rightIndex = deviceIndex; break;
case XRNode.LeftHand: leftIndex = deviceIndex; break;
}
IVRModuleDeviceState prevState;
IVRModuleDeviceStateRW currState;
EnsureValidDeviceState(deviceIndex, out prevState, out currState);
if (m_rightIndex != rightIndex || m_leftIndex != leftIndex)
{
m_rightIndex = rightIndex;
m_leftIndex = leftIndex;
roleChanged = true;
}
if (!prevState.isConnected)
{
currState.isConnected = true;
currState.deviceClass = s_nodeType2DeviceClass[(int)m_nodeStateList[i].nodeType];
// FIXME: getting wrong name in Unity 2017.1f1
//currDeviceState.serialNumber = InputTracking.GetNodeName(m_nodeStateList[i].uniqueID) ?? string.Empty;
//Debug.Log("connected " + InputTracking.GetNodeName(m_nodeStateList[i].uniqueID));
if (!XRDevice.model.Equals("None"))
{
currState.serialNumber = XRDevice.model + " " + m_nodeStateList[i].uniqueID.ToString("X8");
currState.modelNumber = XRDevice.model + " " + m_nodeStateList[i].nodeType;
currState.renderModelName = XRDevice.model + " " + m_nodeStateList[i].nodeType;
}
else
{
currState.serialNumber = XRSettings.loadedDeviceName + " " + m_nodeStateList[i].uniqueID.ToString("X8");
currState.modelNumber = XRSettings.loadedDeviceName + " " + m_nodeStateList[i].nodeType;
currState.renderModelName = XRSettings.loadedDeviceName + " " + m_nodeStateList[i].nodeType;
}
SetupKnownDeviceModel(currState);
}
// update device status
currState.isPoseValid = m_nodeStateList[i].tracked;
var velocity = default(Vector3);
if (m_nodeStateList[i].TryGetVelocity(out velocity)) { currState.velocity = velocity; }
var position = default(Vector3);
if (m_nodeStateList[i].TryGetPosition(out position)) { currState.position = position; }
var rotation = default(Quaternion);
if (m_nodeStateList[i].TryGetRotation(out rotation)) { currState.rotation = rotation; }
#if UNITY_2017_2_OR_NEWER
var angularVelocity = default(Vector3);
if (m_nodeStateList[i].TryGetAngularVelocity(out angularVelocity)) { currState.angularVelocity = angularVelocity; }
#endif
}
m_nodeStateList.Clear();
// update right hand input
if (VRModule.IsValidDeviceIndex(rightIndex))
{
IVRModuleDeviceState rightPrevState;
IVRModuleDeviceStateRW rightCurrState;
EnsureValidDeviceState(rightIndex, out rightPrevState, out rightCurrState);
UpdateRightControllerInput(rightPrevState, rightCurrState);
}
//// update left hand input
if (VRModule.IsValidDeviceIndex(leftIndex))
{
IVRModuleDeviceState leftPrevState;
IVRModuleDeviceStateRW leftCurrState;
EnsureValidDeviceState(leftIndex, out leftPrevState, out leftCurrState);
UpdateLeftControllerInput(leftPrevState, leftCurrState);
}
TrimUntouchedNodes(trimmedIndex =>
{
IVRModuleDeviceState ps;
IVRModuleDeviceStateRW cs;
if (TryGetValidDeviceState(trimmedIndex, out ps, out cs))
{
cs.Reset();
}
});
ProcessConnectedDeviceChanged();
if (roleChanged)
{
InvokeControllerRoleChangedEvent();
}
ProcessDevicePoseChanged();
ProcessDeviceInputChanged();
}
#endif
}
}