258 lines
9.4 KiB
C#
258 lines
9.4 KiB
C#
|
// Copyright 2017 Google Inc. All rights reserved.
|
|||
|
//
|
|||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
// you may not use this file except in compliance with the License.
|
|||
|
// You may obtain a copy of the License at
|
|||
|
//
|
|||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
//
|
|||
|
// Unless required by applicable law or agreed to in writing, software
|
|||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
// See the License for the specific language governing permissions and
|
|||
|
// limitations under the License.
|
|||
|
|
|||
|
// Modified by Unity from original:
|
|||
|
// https://github.com/googlevr/daydream-elements/blob/master/Assets/DaydreamElements/Elements/ArmModels/Scripts/ArmModels/TransitionArmModel.cs
|
|||
|
|
|||
|
using System;
|
|||
|
using System.Collections;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Runtime.CompilerServices;
|
|||
|
using UnityEngine;
|
|||
|
using UnityEngine.Events;
|
|||
|
|
|||
|
#if ENABLE_VR || ENABLE_AR
|
|||
|
using UnityEngine.Experimental.XR.Interaction;
|
|||
|
using UnityEngine.SpatialTracking;
|
|||
|
|
|||
|
[assembly: InternalsVisibleTo("UnityEditor.XR.LegacyInputHelpers")]
|
|||
|
|
|||
|
namespace UnityEngine.XR.LegacyInputHelpers
|
|||
|
{
|
|||
|
[Serializable]
|
|||
|
public class ArmModelTransition
|
|||
|
{
|
|||
|
[SerializeField]
|
|||
|
String m_KeyName;
|
|||
|
/// <summary>
|
|||
|
/// the string name that will be used to trigger a transition
|
|||
|
/// </summary>
|
|||
|
public string transitionKeyName
|
|||
|
{
|
|||
|
get { return m_KeyName; }
|
|||
|
set { m_KeyName = value; }
|
|||
|
}
|
|||
|
|
|||
|
[SerializeField]
|
|||
|
ArmModel m_ArmModel;
|
|||
|
/// <summary>
|
|||
|
/// the arm model that will be transitioned to on receiving this event.
|
|||
|
/// </summary>
|
|||
|
public ArmModel armModel
|
|||
|
{
|
|||
|
get { return m_ArmModel; }
|
|||
|
set { m_ArmModel = value; }
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public class TransitionArmModel : ArmModel
|
|||
|
{
|
|||
|
[SerializeField]
|
|||
|
ArmModel m_CurrentArmModelComponent = null;
|
|||
|
/// <summary>
|
|||
|
/// This field contains the current active arm model that will be used as the input to the tracked pose driver which is
|
|||
|
/// using the transitional arm model.
|
|||
|
/// </summary>
|
|||
|
public ArmModel currentArmModelComponent
|
|||
|
{
|
|||
|
get { return m_CurrentArmModelComponent; }
|
|||
|
set { m_CurrentArmModelComponent = value; }
|
|||
|
}
|
|||
|
|
|||
|
[SerializeField]
|
|||
|
public List<ArmModelTransition> m_ArmModelTransitions = new List<ArmModelTransition>();
|
|||
|
|
|||
|
/// Max number of active transitions that can be going on at one time.
|
|||
|
/// Transitions are only completed when the controller rotates, so if TransitionToArmModel
|
|||
|
/// is called several times without the controller moving, the number of active transitions can
|
|||
|
/// add up.
|
|||
|
private const int MAX_ACTIVE_TRANSITIONS = 10;
|
|||
|
|
|||
|
/// When transitioning to a new arm model, drop any old transitions that have barely begun.
|
|||
|
private const float DROP_TRANSITION_THRESHOLD = 0.035f;
|
|||
|
|
|||
|
/// Threshold for clamping transitions that have been completed.
|
|||
|
private const float LERP_CLAMP_THRESHOLD = 0.95f;
|
|||
|
|
|||
|
/// Minimum amount of angular velocity on the controller before transitioning occurs.
|
|||
|
private const float MIN_ANGULAR_VELOCITY = 0.2f;
|
|||
|
|
|||
|
/// Unit less weight for how much the angular velocity impacts the transition.
|
|||
|
private const float ANGULAR_VELOCITY_DIVISOR = 45.0f;
|
|||
|
|
|||
|
internal struct ArmModelBlendData
|
|||
|
{
|
|||
|
public ArmModel armModel;
|
|||
|
public float currentBlendAmount;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
internal List<ArmModelBlendData> armModelBlendData = new List<ArmModelBlendData>(MAX_ACTIVE_TRANSITIONS);
|
|||
|
ArmModelBlendData currentBlendingArmModel;
|
|||
|
|
|||
|
public bool Queue(string key)
|
|||
|
{
|
|||
|
// attempt to find the arm model to blend to using the supplied key.
|
|||
|
foreach(var am in m_ArmModelTransitions)
|
|||
|
{
|
|||
|
if(am.transitionKeyName == key)
|
|||
|
{
|
|||
|
Queue(am.armModel);
|
|||
|
return true;
|
|||
|
}
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
public void Queue(ArmModel newArmModel)
|
|||
|
{
|
|||
|
if(newArmModel == null)
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
if(m_CurrentArmModelComponent == null)
|
|||
|
{
|
|||
|
m_CurrentArmModelComponent = newArmModel;
|
|||
|
}
|
|||
|
|
|||
|
RemoveJustStartingTransitions();
|
|||
|
if (armModelBlendData.Count == MAX_ACTIVE_TRANSITIONS)
|
|||
|
{
|
|||
|
RemoveOldestTransition();
|
|||
|
}
|
|||
|
|
|||
|
var ambd = new ArmModelBlendData();
|
|||
|
ambd.armModel = newArmModel;
|
|||
|
ambd.currentBlendAmount = 0.0f;
|
|||
|
|
|||
|
armModelBlendData.Add(ambd);
|
|||
|
}
|
|||
|
|
|||
|
void RemoveJustStartingTransitions()
|
|||
|
{
|
|||
|
for( int i = 0; i < armModelBlendData.Count; ++i)
|
|||
|
{
|
|||
|
ArmModelBlendData ambd = armModelBlendData[i];
|
|||
|
if (ambd.currentBlendAmount < DROP_TRANSITION_THRESHOLD)
|
|||
|
{
|
|||
|
armModelBlendData.RemoveAt(i);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void RemoveOldestTransition()
|
|||
|
{
|
|||
|
armModelBlendData.RemoveAt(0);
|
|||
|
}
|
|||
|
|
|||
|
public override PoseDataFlags GetPoseFromProvider(out Pose output)
|
|||
|
{
|
|||
|
if (UpdateBlends())
|
|||
|
{
|
|||
|
output = finalPose;
|
|||
|
return PoseDataFlags.Position | PoseDataFlags.Rotation;
|
|||
|
}
|
|||
|
output = Pose.identity;
|
|||
|
return PoseDataFlags.NoData;
|
|||
|
}
|
|||
|
|
|||
|
bool UpdateBlends()
|
|||
|
{
|
|||
|
if (currentArmModelComponent == null)
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
if (m_CurrentArmModelComponent.OnControllerInputUpdated())
|
|||
|
{
|
|||
|
|
|||
|
m_NeckPosition = m_CurrentArmModelComponent.neckPosition;
|
|||
|
m_ElbowPosition = m_CurrentArmModelComponent.elbowPosition;
|
|||
|
m_WristPosition = m_CurrentArmModelComponent.wristPosition;
|
|||
|
m_ControllerPosition = m_CurrentArmModelComponent.controllerPosition;
|
|||
|
|
|||
|
m_ElbowRotation = m_CurrentArmModelComponent.elbowRotation;
|
|||
|
m_WristRotation = m_CurrentArmModelComponent.wristRotation;
|
|||
|
m_ControllerRotation = m_CurrentArmModelComponent.controllerRotation;
|
|||
|
|
|||
|
#if UNITY_EDITOR
|
|||
|
m_TorsoDirection = m_CurrentArmModelComponent.torsoDirection;
|
|||
|
m_TorsoRotation = m_CurrentArmModelComponent.torsoRotation;
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
Vector3 angVel;
|
|||
|
if (TryGetAngularVelocity(poseSource, out angVel) && armModelBlendData.Count > 0)
|
|||
|
{
|
|||
|
|
|||
|
float angularVelocity = angVel.magnitude;
|
|||
|
float lerpValue = Mathf.Clamp(((angularVelocity) - MIN_ANGULAR_VELOCITY) / ANGULAR_VELOCITY_DIVISOR, 0.0f, 0.1f);
|
|||
|
|
|||
|
for (int i = 0; i < armModelBlendData.Count; ++i)
|
|||
|
{
|
|||
|
ArmModelBlendData ambd = armModelBlendData[i];
|
|||
|
ambd.currentBlendAmount = Mathf.Lerp(ambd.currentBlendAmount, 1.0f, lerpValue);
|
|||
|
if (ambd.currentBlendAmount > LERP_CLAMP_THRESHOLD)
|
|||
|
{
|
|||
|
ambd.currentBlendAmount = 1.0f;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ambd.armModel.OnControllerInputUpdated();
|
|||
|
|
|||
|
m_NeckPosition = Vector3.Slerp(neckPosition, ambd.armModel.neckPosition, ambd.currentBlendAmount);
|
|||
|
m_ElbowPosition = Vector3.Slerp(elbowPosition, ambd.armModel.elbowPosition, ambd.currentBlendAmount);
|
|||
|
m_WristPosition = Vector3.Slerp(wristPosition, ambd.armModel.wristPosition, ambd.currentBlendAmount);
|
|||
|
m_ControllerPosition = Vector3.Slerp(controllerPosition, ambd.armModel.controllerPosition, ambd.currentBlendAmount);
|
|||
|
|
|||
|
m_ElbowRotation = Quaternion.Slerp(elbowRotation, ambd.armModel.elbowRotation, ambd.currentBlendAmount);
|
|||
|
m_WristRotation = Quaternion.Slerp(wristRotation, ambd.armModel.wristRotation, ambd.currentBlendAmount);
|
|||
|
m_ControllerRotation = Quaternion.Slerp(controllerRotation, ambd.armModel.controllerRotation, ambd.currentBlendAmount);
|
|||
|
|
|||
|
}
|
|||
|
// write back.
|
|||
|
armModelBlendData[i] = ambd;
|
|||
|
|
|||
|
if (ambd.currentBlendAmount >= 1.0f)
|
|||
|
{
|
|||
|
m_CurrentArmModelComponent = ambd.armModel;
|
|||
|
armModelBlendData.RemoveRange(0, i + 1);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else if (armModelBlendData.Count > 0)
|
|||
|
{
|
|||
|
Debug.LogErrorFormat(this.gameObject, "Unable to get angular acceleration for node");
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
finalPose = new Pose(controllerPosition, controllerRotation);
|
|||
|
return true;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#if UNITY_EDITOR
|
|||
|
internal List<ArmModelBlendData> GetActiveBlends()
|
|||
|
{
|
|||
|
return armModelBlendData;
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#endif
|