BITFALL/Assets/Plugins/CW/PaintIn3D/Examples/Scripts/P3dVrManager.cs

481 lines
14 KiB
C#

using UnityEngine;
using UnityEngine.XR;
using System.Collections.Generic;
using CW.Common;
namespace PaintIn3D
{
/// <summary>This component attached the current GameObject to a tracked hand.</summary>
[HelpURL(P3dCommon.HelpUrlPrefix + "P3dVrManager")]
[AddComponentMenu(P3dCommon.ComponentMenuPrefix + "VR Manager")]
public class P3dVrManager : MonoBehaviour
{
class SimulatedState
{
public XRNode Node;
public bool Set;
public Vector3 Position;
public Quaternion Rotation = Quaternion.identity;
public SimulatedState(XRNode newNode)
{
Node = newNode;
}
}
/// <summary>This key allows you to reset the VR orientation.</summary>
//public KeyCode RecenterKey { set { recenterKey = value; } get { return recenterKey; } } [SerializeField] private KeyCode recenterKey = KeyCode.Space;
/// <summary>The default distance in world space a hand must be to grab a tool.</summary>
public float GrabDistance { set { grabDistance = value; } get { return grabDistance; } } [SerializeField] private float grabDistance = 0.3f;
/// <summary>This key allows you to simulate a left hand VR trigger.</summary>
public KeyCode SimulatedLeftTrigger { set { simulatedLeftTrigger = value; } get { return simulatedLeftTrigger; } } [SerializeField] private KeyCode simulatedLeftTrigger = KeyCode.Mouse0;
/// <summary>This key allows you to simulate a left hand VR grip.</summary>
public KeyCode SimulatedLeftGrip { set { simulatedLeftGrip = value; } get { return simulatedLeftGrip; } } [SerializeField] private KeyCode simulatedLeftGrip = KeyCode.LeftControl;
/// <summary>This key allows you to simulate a right hand VR trigger.</summary>
public KeyCode SimulatedRightTrigger { set { simulatedRightTrigger = value; } get { return simulatedRightTrigger; } } [SerializeField] private KeyCode simulatedRightTrigger = KeyCode.Mouse1;
/// <summary>This key allows you to simulate a right hand VR grip.</summary>
public KeyCode SimulatedRightGrip { set { simulatedRightGrip = value; } get { return simulatedRightGrip; } } [SerializeField] private KeyCode simulatedRightGrip = KeyCode.RightControl;
/// <summary>When simulating a VR tool, it will be offset by this Euler rotation.</summary>
public Vector3 SimulatedTilt { set { simulatedTilt = value; } get { return simulatedTilt; } } [SerializeField] private Vector3 simulatedTilt = new Vector3(0.0f, -15.0f, 0.0f);
/// <summary>When simulating a VR tool, it will be offset by this local position.</summary>
public Vector3 SimulatedOffset { set { simulatedOffset = value; } get { return simulatedOffset; } } [SerializeField] private Vector3 simulatedOffset = new Vector3(0.0f, 0.0f, -0.2f);
/// <summary>When simulating a VR tool, it will be moved away from the hit surface by this.</summary>
public float SimulatedDistanceMax { set { simulatedReach = value; } get { return simulatedReach; } } [SerializeField] private float simulatedReach = 1.0f;
/// <summary>The simulated left VR eye will be offset this much.</summary>
public Vector3 SimulatedEyeOffset { set { simulatedEyeOffset = value; } get { return simulatedEyeOffset; } } [SerializeField] private Vector3 simulatedEyeOffset = new Vector3(-0.0325f, 0.0f, 0.0f);
/// <summary>When simulating a VR tool, this will control how much the hit surface normal influences the tool rotation.</summary>
public float SimulatedNormalInfluence { set { simulatedNormalInfluence = value; } get { return simulatedNormalInfluence; } } [Range(0.0f, 1.0f)] [SerializeField] private float simulatedNormalInfluence = 0.25f;
private SimulatedState[] simulatedStates = new SimulatedState[]
{
new SimulatedState(XRNode.LeftEye),
new SimulatedState(XRNode.RightEye),
new SimulatedState(XRNode.CenterEye),
new SimulatedState(XRNode.Head),
new SimulatedState(XRNode.LeftHand),
new SimulatedState(XRNode.RightHand)
};
private float hitDistance;
private Quaternion hitRotation = Quaternion.identity;
public bool LeftTrigger;
public bool RightTrigger;
public bool LeftGrip;
public bool RightGrip;
public bool PrevLeftTrigger;
public bool PrevRightTrigger;
public bool PrevLeftGrip;
public bool PrevRightGrip;
private static List<XRNodeState> states = new List<XRNodeState>();
private static List<P3dVrTool> tempTools = new List<P3dVrTool>();
/// <summary>This stores all active and enabled instances in the open scenes.</summary>
public static LinkedList<P3dVrManager> Instances { get { return instances; } } private static LinkedList<P3dVrManager> instances = new LinkedList<P3dVrManager>(); private LinkedListNode<P3dVrManager> instancesNode;
public bool IsSimulation
{
get
{
return XRSettings.enabled == false;
}
}
#if ENABLE_INPUT_SYSTEM && __INPUTSYSTEM__
public void SetRightTrigger(UnityEngine.InputSystem.InputAction.CallbackContext context)
{
RightTrigger = context.ReadValueAsButton();
}
public void SetLeftTrigger(UnityEngine.InputSystem.InputAction.CallbackContext context)
{
LeftTrigger = context.ReadValueAsButton();
}
public void SetLeftGrip(UnityEngine.InputSystem.InputAction.CallbackContext context)
{
LeftGrip = context.ReadValueAsButton();
}
public void SetRightGrip(UnityEngine.InputSystem.InputAction.CallbackContext context)
{
RightGrip = context.ReadValueAsButton();
}
#endif
public void SetRightTrigger(bool value)
{
RightTrigger = value;
}
public void SetLeftTrigger(bool value)
{
LeftTrigger = value;
}
public void SetLeftGrip(bool value)
{
LeftGrip = value;
}
public void SetRightGrip(bool value)
{
RightGrip = value;
}
public bool GetTrigger(XRNode node)
{
switch (node)
{
case XRNode.LeftHand: return LeftTrigger == true;
case XRNode.RightHand: return RightTrigger == true;
}
return false;
}
public bool GetTriggerPressed(XRNode node)
{
switch (node)
{
case XRNode.LeftHand: return LeftTrigger == true && PrevLeftTrigger == false;
case XRNode.RightHand: return RightTrigger == true && PrevRightTrigger == false;
}
return false;
}
public bool GetTriggerReleased(XRNode node)
{
switch (node)
{
case XRNode.LeftHand: return LeftTrigger == false && PrevLeftTrigger == true;
case XRNode.RightHand: return RightTrigger == false && PrevRightTrigger == true;
}
return false;
}
public bool GetGrip(XRNode node)
{
switch (node)
{
case XRNode.LeftHand: return LeftGrip == true;
case XRNode.RightHand: return RightGrip == true;
}
return false;
}
public bool GetGripPressed(XRNode node)
{
switch (node)
{
case XRNode.LeftHand: return LeftGrip == true && PrevLeftGrip == false;
case XRNode.RightHand: return RightGrip == true && PrevRightGrip == false;
}
return false;
}
public bool GetGripReleased(XRNode node)
{
switch (node)
{
case XRNode.LeftHand: return LeftGrip == false && PrevLeftGrip == true;
case XRNode.RightHand: return RightGrip == false && PrevRightGrip == true;
}
return false;
}
public XRNode GetClosestNode(Vector3 point, float maximumDistance)
{
var bestNode = (XRNode)(-1);
var bestDistance = maximumDistance;
var position = default(Vector3);
if (TryGetPosition(XRNode.LeftHand, ref position) == true)
{
var distance = Vector3.Distance(point, position);
if (distance < bestDistance)
{
bestDistance = distance;
bestNode = XRNode.LeftHand;
}
}
if (TryGetPosition(XRNode.RightHand, ref position) == true)
{
var distance = Vector3.Distance(point, position);
if (distance < bestDistance)
{
bestDistance = distance;
bestNode = XRNode.RightHand;
}
}
return bestNode;
}
private void SetSimulatedState(XRNode node, Vector3 position, Quaternion rotation)
{
foreach (var simulatedState in simulatedStates)
{
if (simulatedState.Node == node)
{
simulatedState.Set = true;
simulatedState.Position = position;
simulatedState.Rotation = rotation;
return;
}
}
}
public bool TryGetPosition(XRNode node, ref Vector3 position)
{
if (IsSimulation == true)
{
foreach (var simulatedState in simulatedStates)
{
if (simulatedState.Node == node)
{
if (simulatedState.Set == false)
{
return false;
}
position = simulatedState.Position;
return true;
}
}
}
else
{
InputTracking.GetNodeStates(states);
foreach (var state in states)
{
if (state.nodeType == node)
{
return state.TryGetPosition(out position);
}
}
}
return false;
}
public bool TryGetRotation(XRNode node, ref Quaternion rotation)
{
if (IsSimulation == true)
{
foreach (var simulatedState in simulatedStates)
{
if (simulatedState.Node == node)
{
if (simulatedState.Set == false)
{
return false;
}
rotation = simulatedState.Rotation;
return true;
}
}
}
else
{
InputTracking.GetNodeStates(states);
foreach (var state in states)
{
if (state.nodeType == node)
{
return state.TryGetRotation(out rotation);
}
}
}
return false;
}
protected virtual void OnEnable()
{
instancesNode = instances.AddLast(this);
}
protected virtual void OnDisable()
{
instances.Remove(instancesNode); instancesNode = null;
}
protected virtual void Start()
{
//Recenter();
hitDistance = simulatedReach * 0.25f;
}
protected virtual void Update()
{
if (IsSimulation == true)
{
LeftTrigger = CwInput.GetKeyIsHeld(simulatedLeftTrigger);
LeftGrip = CwInput.GetKeyIsHeld(simulatedLeftGrip);
RightTrigger = CwInput.GetKeyIsHeld(simulatedRightTrigger);
RightGrip = CwInput.GetKeyIsHeld(simulatedRightGrip);
if (CwInputManager.PointOverGui(CwInput.GetMousePosition()) == true)
{
LeftTrigger = false;
LeftGrip = false;
RightTrigger = false;
RightGrip = false;
}
}
//if (CwInputManager.IsDown(recenterKey) == true)
//{
// Recenter();
//}
}
protected virtual void LateUpdate()
{
var camera = CwHelper.GetCamera(null);
if (camera != null)
{
var ray = camera.ScreenPointToRay(CwInput.GetMousePosition());
var hit = default(RaycastHit);
var cam = camera.transform.rotation;
if (Physics.Raycast(ray, out hit, simulatedReach) == true)
{
hitDistance = hit.distance;
hitRotation = Quaternion.Inverse(cam) * Quaternion.LookRotation(-hit.normal);
}
var leftHandRot = Quaternion.Slerp(cam, cam * hitRotation, simulatedNormalInfluence) * Quaternion.Euler(simulatedTilt.x, -simulatedTilt.y, simulatedTilt.z);
var leftHandPos = ray.GetPoint(hitDistance) + leftHandRot * new Vector3(simulatedOffset.x, simulatedOffset.y, simulatedOffset.z);
SetSimulatedState(XRNode.LeftHand, leftHandPos, leftHandRot);
var rightHandRot = Quaternion.Slerp(cam, cam * hitRotation, simulatedNormalInfluence) * Quaternion.Euler(simulatedTilt.x, simulatedTilt.y, simulatedTilt.z);
var rightHandPos = ray.GetPoint(hitDistance) + rightHandRot * new Vector3(simulatedOffset.x, -simulatedOffset.y, simulatedOffset.z);
SetSimulatedState(XRNode.RightHand, rightHandPos, rightHandRot);
SetSimulatedState(XRNode.Head, camera.transform.position, camera.transform.rotation);
SetSimulatedState(XRNode.CenterEye, camera.transform.position, camera.transform.rotation);
SetSimulatedState(XRNode.LeftEye, camera.transform.TransformPoint(simulatedEyeOffset.x, simulatedEyeOffset.y, simulatedEyeOffset.z), camera.transform.rotation);
SetSimulatedState(XRNode.RightEye, camera.transform.TransformPoint(-simulatedEyeOffset.x, simulatedEyeOffset.y, simulatedEyeOffset.z), camera.transform.rotation);
}
for (var i = 0; i <= 8; i++)
{
UpdateTools((XRNode)i);
}
PrevLeftTrigger = LeftTrigger;
PrevLeftGrip = LeftGrip;
PrevRightTrigger = RightTrigger;
PrevRightGrip = RightGrip;
}
private void UpdateTools(XRNode node)
{
P3dVrTool.GetTools(node, ref tempTools);
foreach (var tool in tempTools)
{
if (tool != null && tool.Node == node)
{
tool.UpdateGripped(this);
}
}
}
//[ContextMenu("Recenter")]
//public void Recenter()
//{
// if (XRSettings.enabled == true)
// {
// InputTracking.Recenter();
// }
//}
}
}
#if UNITY_EDITOR
namespace PaintIn3D
{
using UnityEditor;
using TARGET = P3dVrManager;
[CanEditMultipleObjects]
[CustomEditor(typeof(TARGET))]
public class P3dVrManager_Editor : CwEditor
{
protected override void OnInspector()
{
TARGET tgt; TARGET[] tgts; GetTargets(out tgt, out tgts);
if (Application.isPlaying == true && XRSettings.enabled == false)
{
Warning("VR is disabled in your project settings, so simulated fingers will be used. If you have a VR device then you can enable it.");
}
//Draw("recenterKey", "This key allows you to reset the VR orientation.");
Draw("grabDistance", "The default distance in world space a hand must be to grab a tool.");
Separator();
Draw("simulatedLeftTrigger", "This key allows you to simulate a left hand VR trigger.");
Draw("simulatedLeftGrip", "This key allows you to simulate a left hand VR grip.");
Draw("simulatedRightTrigger", "This key allows you to simulate a right hand VR trigger.");
Draw("simulatedRightGrip", "This key allows you to simulate a right hand VR grip.");
Separator();
Draw("simulatedTilt", "When simulating a VR tool, it will be offset by this Euler rotation.");
Draw("simulatedOffset", "When simulating a VR tool, it will be offset by this local position.");
Draw("simulatedReach", "When simulating a VR tool, it will be moved away from the hit surface by this.");
Draw("simulatedEyeOffset", "The simulated left VR eye will be offset this much.");
Draw("simulatedNormalInfluence", "When simulating a VR tool, this will control how much the hit surface normal influences the tool rotation.");
Separator();
BeginDisabled();
EditorGUILayout.Toggle("Left Trigger", tgt.LeftTrigger);
EditorGUILayout.Toggle("Left Grip", tgt.LeftGrip);
EditorGUILayout.Toggle("Right Trigger", tgt.RightTrigger);
EditorGUILayout.Toggle("Right Grip", tgt.RightGrip);
EndDisabled();
}
}
}
#endif