被抓物体身上,都要挂如下脚本:
有时候会遇到一个Bug,就是把手中的模型删掉之后,发现手势不能回去了,僵硬不动,出现问题就是,删除的物体没有调用强制脱手的方法
GameObject hand = grapObj.GetComponent<VRTK_InteractableObject>().GetGrabbingObject();
if (hand)
{
hand.GetComponent<VRTK_InteractGrab>().ForceRelease();
}
在测试场景中获取手势的位置和旋转值
下面是是涉及到的脚本:
InHandAnimationType.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class InHandAnimationType : MonoBehaviour, IHandAnimationBaseObject
{
[SerializeField]
private HandAnimationType aniType;
[SerializeField]
private Hand_UseAnimationFingerType usingFingerButtonType = Hand_UseAnimationFingerType.None;
public HandAnimationType type
{
get
{
return aniType;
}
}
public Hand_UseAnimationFingerType usingFingerType
{
get
{
return usingFingerButtonType;
}
}
}
VRTKExtend_LikeChildOfControllerGrabAttach.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using VRTK;
using VRTK.GrabAttachMechanics;
namespace VRTK_Extend
{
public class VRTKExtend_LikeChildOfControllerGrabAttach : VRTK_BaseGrabAttach
{
[Header("左手设置")]
public Vector3 positionInLeftHand;//被抓住时 相对于左手的位置
public Vector3 rotationInLeftHand;//被抓住时 相对于左手的旋转
[Header("右手设置")]
public Vector3 positionInRightHand;//被抓住时 相对于右手的位置
public Vector3 rotationInRightHand;//被抓住时 相对于右手的旋转
private Vector3 deltaPosition;//
private Vector3 deltaRotation;//
protected override void Initialise()
{
tracked = false;
climbable = false;
kinematic = true;
}
//控制器物体
protected GameObject controllerObj;
protected virtual void SetSnappedObjectPosition(GameObject obj)
{
controllerObj = grabbedObjectScript.GetGrabbingObject();
if (precisionGrab)
{
deltaPosition = obj.transform.position - controllerObj.transform.position;
//deltaPosition = controllerObj.transform.InverseTransformPoint(obj.transform.position);
deltaRotation = obj.transform.rotation.eulerAngles - controllerObj.transform.rotation.eulerAngles;
//deltaRotation = controllerObj.transform.rotation.eulerAngles - obj.transform.rotation.eulerAngles;
}
else
{
VRTK_ControllerReference controllerReference = VRTK_ControllerReference.GetControllerReference(controllerObj);
switch (controllerReference.hand)
{
case SDK_BaseController.ControllerHand.Left:
deltaPosition = positionInLeftHand;
deltaRotation = rotationInLeftHand;
break;
case SDK_BaseController.ControllerHand.Right:
deltaPosition = positionInRightHand;
deltaRotation = rotationInRightHand;
break;
case SDK_BaseController.ControllerHand.None:
deltaPosition = Vector3.zero; deltaRotation = Vector3.zero;
Debug.LogError("手柄类型未知");
break;
}
}
}
public override bool StartGrab(GameObject grabbingObject, GameObject givenGrabbedObject, Rigidbody givenControllerAttachPoint)
{
if (base.StartGrab(grabbingObject, givenGrabbedObject, givenControllerAttachPoint))
{
SetSnappedObjectPosition(givenGrabbedObject);
return true;
}
return false;
}
public override void ProcessUpdate()
{
if (grabbedObjectScript == null)
return;
grabbedObjectScript.transform.position = controllerObj.transform.position + controllerObj.transform.rotation * deltaPosition;
grabbedObjectScript.transform.rotation = controllerObj.transform.rotation * Quaternion.Euler(deltaRotation);
}
}
}
AvatarHandController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using VRTK;
public enum HandAnimationType
{
Xian,tttt,ffff
}
/// <summary>
/// 控制手部使用物体动画播放的按键类型
/// </summary>
public enum Hand_UseAnimationFingerType
{
None = -1,Thumb = 0,Index = 1,BottomThree = 3
}
/// <summary>
/// 抓取物体身上所携带的动画信息
/// </summary>
public interface IHandAnimationBaseObject
{
HandAnimationType type { get; }//动作的类型(播放动画的类型)
Hand_UseAnimationFingerType usingFingerType { get; }//控制使用物体动画播放的按键
}
/// <summary>
/// 手部动画控制器
/// </summary>
public class AvatarHandController : MonoBehaviour {
[Header("手部设置")]
[Tooltip("控制器类型")]
public SDK_BaseController.ControllerType controllerType;
[Tooltip("控制器事件来源,如果没有指定会自动寻找")]
public VRTK_ControllerEvents controllerEvents;
[Tooltip("触碰事件来源")]
public VRTK_InteractTouch interactTouch;
[Tooltip("抓取事件来源")]
public VRTK_InteractGrab interactGrab;
[Tooltip("使用事件来源")]
public VRTK_InteractUse interactUse;
//控制大拇指的按键
protected SDK_BaseController.ButtonTypes thumbAxisButton = SDK_BaseController.ButtonTypes.Touchpad;
//控制食指的按键
protected SDK_BaseController.ButtonTypes indexAxisButton = SDK_BaseController.ButtonTypes.Trigger;
//控制中指的按键
protected SDK_BaseController.ButtonTypes middleAxisButton = SDK_BaseController.ButtonTypes.MiddleFinger;
//控制无名指的按键
protected SDK_BaseController.ButtonTypes ringAxisButton = SDK_BaseController.ButtonTypes.RingFinger;
//控制小拇指的按键
protected SDK_BaseController.ButtonTypes pinkyAxisButton = SDK_BaseController.ButtonTypes.PinkyFinger;
//控制后三个手指的按键
protected SDK_BaseController.ButtonTypes threeFingerAxisButton = SDK_BaseController.ButtonTypes.Grip;
[Header("手指状态设置")]
public VRTK_ControllerEvents.AxisType thumbState = VRTK_ControllerEvents.AxisType.SenseAxis;
public VRTK_ControllerEvents.AxisType indexState = VRTK_ControllerEvents.AxisType.Axis;
public VRTK_ControllerEvents.AxisType middleState = VRTK_ControllerEvents.AxisType.Axis;
public VRTK_ControllerEvents.AxisType ringState = VRTK_ControllerEvents.AxisType.Axis;
public VRTK_ControllerEvents.AxisType pinkyState = VRTK_ControllerEvents.AxisType.Axis;
public VRTK_ControllerEvents.AxisType threeFingerState = VRTK_ControllerEvents.AxisType.Axis;
private VRTK_ControllerEvents.AxisType pointState = VRTK_ControllerEvents.AxisType.SenseAxis;
protected VRTK_ControllerReference controllerReference;
[Tooltip("手部动画控制器")]
protected Animator animator;
[Tooltip("是否根据控制器类型自动设置手指对应的按键类型")]
public bool autoSetFingersForControllerType;
#region 动画参数
private const string BASELAYER = "Base Layer";
private const string THUMBLAYER = "Thumb Layer";
private const string POINTLAYER = "Point Layer";
private int baseLayerIndex;
private int thumbLayerIndex;
private int pointLayerIndex;
private int flexParam;
private int pinchParam;
private const string FLEX = "Flex";
private const string PINCH = "Pinch";
#endregion 动画参数
protected virtual void OnEnable()
{
animator = GetComponent<Animator>();
controllerEvents = (controllerEvents != null ? controllerEvents : GetComponentInParent<VRTK_ControllerEvents>());
interactTouch = (interactTouch != null ? interactTouch : GetComponentInParent<VRTK_InteractTouch>());
interactUse = (interactUse != null ? interactUse : GetComponentInParent<VRTK_InteractUse>());
interactGrab = (interactGrab != null ? interactGrab : GetComponentInParent<VRTK_InteractGrab>());
controllerReference = VRTK_ControllerReference.GetControllerReference(controllerEvents.gameObject);
if (animator != null)
{
baseLayerIndex = animator.GetLayerIndex(BASELAYER);
thumbLayerIndex = animator.GetLayerIndex(THUMBLAYER);
pointLayerIndex = animator.GetLayerIndex(POINTLAYER);
flexParam = Animator.StringToHash(FLEX);
pinchParam = Animator.StringToHash(PINCH);
}
}
protected virtual void OnDisable()
{
UnsubscribeEvents();
controllerType = SDK_BaseController.ControllerType.Undefined;
}
protected virtual void Update()
{
if (controllerType == SDK_BaseController.ControllerType.Undefined)
DetectController();
else
UpdateHandAnmator();
}
/// <summary>
/// 统一注册事件
/// </summary>
protected virtual void SubscribeEvents()
{
if (controllerEvents != null)
{
SubscribeButtonAxisEvent(thumbAxisButton, thumbState, DoThumbAxisEvent);
SubscribeButtonAxisEvent(indexAxisButton, indexState, DoIndexAxisEvent);
SubscribeButtonAxisEvent(middleAxisButton, middleState, DoMiddleAxisEvent);
SubscribeButtonAxisEvent(ringAxisButton, ringState, DoRingAxisEvent);
SubscribeButtonAxisEvent(pinkyAxisButton, pinkyState, DoPinkyAxisEvent);
SubscribeButtonAxisEvent(threeFingerAxisButton, threeFingerState, DoThreeFingerAxisEvent);
SubscribeButtonAxisEvent(indexAxisButton, pointState, DoPointAxisEvent);
}
if (interactTouch != null)
{
interactTouch.ControllerTouchInteractableObject += DoControllerTouch;
interactTouch.ControllerUntouchInteractableObject += DoControllerUntouch;
}
if (interactGrab != null)
{
interactGrab.ControllerGrabInteractableObject += DoControllerGrab;
interactGrab.ControllerUngrabInteractableObject += DoControllerUngrab;
}
if (interactUse != null)
{
interactUse.ControllerUseInteractableObject += DoControllerUse;
interactUse.ControllerUnuseInteractableObject += DoControllerUnuse;
}
}
/// <summary>
/// 统一解除事件
/// </summary>
protected virtual void UnsubscribeEvents()
{
if (controllerEvents != null)
{
UnsubscribeButtonAxisEvent(thumbAxisButton, thumbState, DoThumbAxisEvent);
UnsubscribeButtonAxisEvent(indexAxisButton, indexState, DoIndexAxisEvent);
UnsubscribeButtonAxisEvent(middleAxisButton, middleState, DoMiddleAxisEvent);
UnsubscribeButtonAxisEvent(ringAxisButton, ringState, DoRingAxisEvent);
UnsubscribeButtonAxisEvent(pinkyAxisButton, pinkyState, DoPinkyAxisEvent);
UnsubscribeButtonAxisEvent(threeFingerAxisButton, threeFingerState, DoThreeFingerAxisEvent);
UnsubscribeButtonAxisEvent(indexAxisButton, pointState, DoPointAxisEvent);
}
if (interactTouch != null)
{
interactTouch.ControllerTouchInteractableObject -= DoControllerTouch;
interactTouch.ControllerUntouchInteractableObject -= DoControllerUntouch;
}
if (interactGrab != null)
{
interactGrab.ControllerGrabInteractableObject -= DoControllerGrab;
interactGrab.ControllerUngrabInteractableObject -= DoControllerUngrab;
}
if (interactUse != null)
{
interactUse.ControllerUseInteractableObject -= DoControllerUse;
interactUse.ControllerUnuseInteractableObject -= DoControllerUnuse;
}
}
protected virtual void SubscribeButtonAxisEvent(SDK_BaseController.ButtonTypes buttonType, VRTK_ControllerEvents.AxisType axisType, ControllerInteractionEventHandler eventHandler)
{
controllerEvents.SubscribeToAxisAliasEvent(buttonType, axisType, eventHandler);
}
protected virtual void UnsubscribeButtonAxisEvent(SDK_BaseController.ButtonTypes buttonType, VRTK_ControllerEvents.AxisType axisType, ControllerInteractionEventHandler eventHandler)
{
controllerEvents.UnsubscribeToAxisAliasEvent(buttonType, axisType, eventHandler);
}
//每个手指Axis缓存 0到4 依次代表每个手指
protected float[] fingerAxis = new float[6];
protected virtual void SetFingerAxisEvent(int fingerIndex, ControllerInteractionEventArgs e)
{
fingerAxis[fingerIndex] = e.buttonPressure;
}
protected virtual void DoThumbAxisEvent(object sender, ControllerInteractionEventArgs e)
{
SetFingerAxisEvent(0, e);
}
protected virtual void DoIndexAxisEvent(object sender, ControllerInteractionEventArgs e)
{
SetFingerAxisEvent(1, e);
//Debug.Log("IndexAxis" + e.buttonPressure);
}
protected virtual void DoMiddleAxisEvent(object sender, ControllerInteractionEventArgs e)
{
SetFingerAxisEvent(2, e);
}
protected virtual void DoRingAxisEvent(object sender, ControllerInteractionEventArgs e)
{
SetFingerAxisEvent(3, e);
}
protected virtual void DoPinkyAxisEvent(object sender, ControllerInteractionEventArgs e)
{
SetFingerAxisEvent(4, e);
}
protected virtual void DoThreeFingerAxisEvent(object sender, ControllerInteractionEventArgs e)
{
SetFingerAxisEvent(2, e);
SetFingerAxisEvent(3, e);
SetFingerAxisEvent(4, e);
}
protected virtual void DoPointAxisEvent(object sender, ControllerInteractionEventArgs e)
{
SetFingerAxisEvent(5, e);
//Debug.Log("PointAxis" + e.buttonPressure);
}
/// <summary>
/// 检测控制器
/// </summary>
protected virtual void DetectController()
{
controllerType = VRTK_DeviceFinder.GetCurrentControllerType(controllerReference);
if (controllerType != SDK_BaseController.ControllerType.Undefined)
{
if (autoSetFingersForControllerType)
{
switch (controllerType)
{
case SDK_BaseController.ControllerType.SteamVR_ViveWand:
case SDK_BaseController.ControllerType.SteamVR_WindowsMRController:
case SDK_BaseController.ControllerType.WindowsMR_MotionController:
thumbState = VRTK_ControllerEvents.AxisType.Digital;
indexState = VRTK_ControllerEvents.AxisType.Axis;
middleState = VRTK_ControllerEvents.AxisType.Digital;
ringState = VRTK_ControllerEvents.AxisType.Digital;
pinkyState = VRTK_ControllerEvents.AxisType.Digital;
threeFingerState = VRTK_ControllerEvents.AxisType.Digital;
break;
case SDK_BaseController.ControllerType.Oculus_OculusTouch:
case SDK_BaseController.ControllerType.SteamVR_OculusTouch:
thumbState = VRTK_ControllerEvents.AxisType.Digital;
indexState = VRTK_ControllerEvents.AxisType.Axis;
middleState = VRTK_ControllerEvents.AxisType.Digital;
ringState = VRTK_ControllerEvents.AxisType.Digital;
pinkyState = VRTK_ControllerEvents.AxisType.Digital;
threeFingerState = VRTK_ControllerEvents.AxisType.Axis;
break;
case SDK_BaseController.ControllerType.SteamVR_ValveKnuckles:
thumbState = VRTK_ControllerEvents.AxisType.Digital;
indexState = VRTK_ControllerEvents.AxisType.SenseAxis;
middleState = VRTK_ControllerEvents.AxisType.SenseAxis;
ringState = VRTK_ControllerEvents.AxisType.SenseAxis;
pinkyState = VRTK_ControllerEvents.AxisType.SenseAxis;
threeFingerState = VRTK_ControllerEvents.AxisType.SenseAxis;
threeFingerAxisButton = SDK_BaseController.ButtonTypes.StartMenu;
break;
default:
thumbState = VRTK_ControllerEvents.AxisType.Digital;
indexState = VRTK_ControllerEvents.AxisType.Digital;
middleState = VRTK_ControllerEvents.AxisType.Digital;
ringState = VRTK_ControllerEvents.AxisType.Digital;
pinkyState = VRTK_ControllerEvents.AxisType.Digital;
threeFingerState = VRTK_ControllerEvents.AxisType.Digital;
break;
}
}
UnsubscribeEvents();
SubscribeEvents();
}
}
/// <summary>
/// 触碰事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected virtual void DoControllerTouch(object sender, ObjectInteractEventArgs e)
{
}
/// <summary>
/// 脱离触碰事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected virtual void DoControllerUntouch(object sender, ObjectInteractEventArgs e)
{
}
/// <summary>
/// 使用事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected virtual void DoControllerUse(object sender, ObjectInteractEventArgs e)
{
}
/// <summary>
/// 松开使用 事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected virtual void DoControllerUnuse(object sender, ObjectInteractEventArgs e)
{
}
private IHandAnimationBaseObject currentHandAniObj;
/// <summary>
/// 抓取事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected virtual void DoControllerGrab(object sender, ObjectInteractEventArgs e)
{
if (!e.target)
return;
currentHandAniObj = e.target.GetComponent<IHandAnimationBaseObject>();
if (currentHandAniObj == null)
return;
animator.SetTrigger(currentHandAniObj.type.ToString());
animator.SetLayerWeight(thumbLayerIndex, 0);
animator.SetLayerWeight(pointLayerIndex, 0);
}
/// <summary>
/// 松开抓取事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected virtual void DoControllerUngrab(object sender, ObjectInteractEventArgs e)
{
if (currentHandAniObj != null)
{
animator.SetTrigger(currentHandAniObj.type.ToString());
animator.SetLayerWeight(thumbLayerIndex, 1 - fingerAxis[0]);
animator.SetLayerWeight(pointLayerIndex, 1 - fingerAxis[5]);
animator.SetFloat(flexParam, fingerAxis[3]);
animator.SetFloat(pinchParam, fingerAxis[1]);
currentHandAniObj = null;
}
}
/// <summary>
/// 更新动画
/// </summary>
protected virtual void UpdateHandAnmator()
{
if (currentHandAniObj == null)
{
animator.SetLayerWeight(thumbLayerIndex, 1 - fingerAxis[0]);
animator.SetLayerWeight(pointLayerIndex, 1 - fingerAxis[5]);
animator.SetFloat(flexParam, fingerAxis[3]);
animator.SetFloat(pinchParam, fingerAxis[1]);
}
else
{
if (currentHandAniObj.usingFingerType != Hand_UseAnimationFingerType.None)
{
animator.SetFloat(currentHandAniObj.type.ToString()+"Para", fingerAxis[(int)currentHandAniObj.usingFingerType]);
}
}
}
}