欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

使用手柄抓取物体(Unity / SteamVr / Htc Vive)

程序员文章站 2022-06-25 16:10:04
导入SteamVr插件,然后将Interactable脚本和Core脚本挂载到需要抓取的物体上即可加载SteamVr插件点击左上方的商店,进入商店页面在商店页面的搜索框中搜索SteamVr,找到下图所示插件,点击下载导入即可在导入SteamVr插件后,可能经常会有弹窗提醒,点击接受即可交互脚本InteractableInteractable脚本在导入的SteamVr插件中就有,路径如下图代码//======= Copyright (c) Valve Corporation, All r...

导入SteamVr插件,然后将Interactable脚本和Core脚本挂载到需要抓取的物体上即可

加载SteamVr插件

点击左上方的商店,进入商店页面
使用手柄抓取物体(Unity / SteamVr / Htc Vive)

在商店页面的搜索框中搜索SteamVr,找到下图所示插件,点击下载导入即可
使用手柄抓取物体(Unity / SteamVr / Htc Vive)
在导入SteamVr插件后,可能经常会有弹窗提醒,点击接受即可

交互脚本Interactable

Interactable脚本在导入的SteamVr插件中就有,路径如下图
使用手柄抓取物体(Unity / SteamVr / Htc Vive)

代码

//======= Copyright (c) Valve Corporation, All rights reserved. ===============
//
// Purpose: This object will get hover events and can be attached to the hands
//
//=============================================================================

using UnityEngine;
using UnityEngine.Events;
using System.Collections;
using System.Collections.Generic;

namespace Valve.VR.InteractionSystem
{
    //-------------------------------------------------------------------------
    public class Interactable : MonoBehaviour
    {
        [Tooltip("Activates an action set on attach and deactivates on detach")]
        public SteamVR_ActionSet activateActionSetOnAttach;

        [Tooltip("Hide the whole hand on attachment and show on detach")]
        public bool hideHandOnAttach = true;

        [Tooltip("Hide the skeleton part of the hand on attachment and show on detach")]
        public bool hideSkeletonOnAttach = false;

        [Tooltip("Hide the controller part of the hand on attachment and show on detach")]
        public bool hideControllerOnAttach = false;

        [Tooltip("The integer in the animator to trigger on pickup. 0 for none")]
        public int handAnimationOnPickup = 0;

        [Tooltip("The range of motion to set on the skeleton. None for no change.")]
        public SkeletalMotionRangeChange setRangeOfMotionOnPickup = SkeletalMotionRangeChange.None;

        public delegate void OnAttachedToHandDelegate(Hand hand);
        public delegate void OnDetachedFromHandDelegate(Hand hand);

        public event OnAttachedToHandDelegate onAttachedToHand;
        public event OnDetachedFromHandDelegate onDetachedFromHand;


        [Tooltip("Specify whether you want to snap to the hand's object attachment point, or just the raw hand")]
        public bool useHandObjectAttachmentPoint = true;

        public bool attachEaseIn = false;
        [HideInInspector]
        public AnimationCurve snapAttachEaseInCurve = AnimationCurve.EaseInOut(0.0f, 0.0f, 1.0f, 1.0f);
        public float snapAttachEaseInTime = 0.15f;

        public bool snapAttachEaseInCompleted = false;


        // [Tooltip("The skeleton pose to apply when grabbing. Can only set this or handFollowTransform.")]
        [HideInInspector]
        public SteamVR_Skeleton_Poser skeletonPoser;

        [Tooltip("Should the rendered hand lock on to and follow the object")]
        public bool handFollowTransform= true;


        [Tooltip("Set whether or not you want this interactible to highlight when hovering over it")]
        public bool highlightOnHover = true;
        protected MeshRenderer[] highlightRenderers;
        protected MeshRenderer[] existingRenderers;
        protected GameObject highlightHolder;
        protected SkinnedMeshRenderer[] highlightSkinnedRenderers;
        protected SkinnedMeshRenderer[] existingSkinnedRenderers;
        protected static Material highlightMat;
        [Tooltip("An array of child gameObjects to not render a highlight for. Things like transparent parts, vfx, etc.")]
        public GameObject[] hideHighlight;

        [Tooltip("Higher is better")]
        public int hoverPriority = 0;

        [System.NonSerialized]
        public Hand attachedToHand;

        [System.NonSerialized]
        public List<Hand> hoveringHands = new List<Hand>();
        public Hand hoveringHand
        {
            get
            {
                if (hoveringHands.Count > 0)
                    return hoveringHands[0];
                return null;
            }
        }


        public bool isDestroying { get; protected set; }
        public bool isHovering { get; protected set; }
        public bool wasHovering { get; protected set; }


        private void Awake()
        {
            skeletonPoser = GetComponent<SteamVR_Skeleton_Poser>();
        }

        protected virtual void Start()
        {
            if (highlightMat == null)
#if UNITY_URP
                highlightMat = (Material)Resources.Load("SteamVR_HoverHighlight_URP", typeof(Material));
#else
                highlightMat = (Material)Resources.Load("SteamVR_HoverHighlight", typeof(Material));
#endif

            if (highlightMat == null)
                Debug.LogError("<b>[SteamVR Interaction]</b> Hover Highlight Material is missing. Please create a material named 'SteamVR_HoverHighlight' and place it in a Resources folder", this);

            if (skeletonPoser != null)
            {
                if (useHandObjectAttachmentPoint)
                {
                    //Debug.LogWarning("<b>[SteamVR Interaction]</b> SkeletonPose and useHandObjectAttachmentPoint both set at the same time. Ignoring useHandObjectAttachmentPoint.");
                    useHandObjectAttachmentPoint = false;
                }
            }
        }

        protected virtual bool ShouldIgnoreHighlight(Component component)
        {
            return ShouldIgnore(component.gameObject);
        }

        protected virtual bool ShouldIgnore(GameObject check)
        {
            for (int ignoreIndex = 0; ignoreIndex < hideHighlight.Length; ignoreIndex++)
            {
                if (check == hideHighlight[ignoreIndex])
                    return true;
            }

            return false;
        }

        protected virtual void CreateHighlightRenderers()
        {
            existingSkinnedRenderers = this.GetComponentsInChildren<SkinnedMeshRenderer>(true);
            highlightHolder = new GameObject("Highlighter");
            highlightSkinnedRenderers = new SkinnedMeshRenderer[existingSkinnedRenderers.Length];

            for (int skinnedIndex = 0; skinnedIndex < existingSkinnedRenderers.Length; skinnedIndex++)
            {
                SkinnedMeshRenderer existingSkinned = existingSkinnedRenderers[skinnedIndex];

                if (ShouldIgnoreHighlight(existingSkinned))
                    continue;

                GameObject newSkinnedHolder = new GameObject("SkinnedHolder");
                newSkinnedHolder.transform.parent = highlightHolder.transform;
                SkinnedMeshRenderer newSkinned = newSkinnedHolder.AddComponent<SkinnedMeshRenderer>();
                Material[] materials = new Material[existingSkinned.sharedMaterials.Length];
                for (int materialIndex = 0; materialIndex < materials.Length; materialIndex++)
                {
                    materials[materialIndex] = highlightMat;
                }

                newSkinned.sharedMaterials = materials;
                newSkinned.sharedMesh = existingSkinned.sharedMesh;
                newSkinned.rootBone = existingSkinned.rootBone;
                newSkinned.updateWhenOffscreen = existingSkinned.updateWhenOffscreen;
                newSkinned.bones = existingSkinned.bones;

                highlightSkinnedRenderers[skinnedIndex] = newSkinned;
            }

            MeshFilter[] existingFilters = this.GetComponentsInChildren<MeshFilter>(true);
            existingRenderers = new MeshRenderer[existingFilters.Length];
            highlightRenderers = new MeshRenderer[existingFilters.Length];

            for (int filterIndex = 0; filterIndex < existingFilters.Length; filterIndex++)
            {
                MeshFilter existingFilter = existingFilters[filterIndex];
                MeshRenderer existingRenderer = existingFilter.GetComponent<MeshRenderer>();

                if (existingFilter == null || existingRenderer == null || ShouldIgnoreHighlight(existingFilter))
                    continue;

                GameObject newFilterHolder = new GameObject("FilterHolder");
                newFilterHolder.transform.parent = highlightHolder.transform;
                MeshFilter newFilter = newFilterHolder.AddComponent<MeshFilter>();
                newFilter.sharedMesh = existingFilter.sharedMesh;
                MeshRenderer newRenderer = newFilterHolder.AddComponent<MeshRenderer>();

                Material[] materials = new Material[existingRenderer.sharedMaterials.Length];
                for (int materialIndex = 0; materialIndex < materials.Length; materialIndex++)
                {
                    materials[materialIndex] = highlightMat;
                }
                newRenderer.sharedMaterials = materials;

                highlightRenderers[filterIndex] = newRenderer;
                existingRenderers[filterIndex] = existingRenderer;
            }
        }

        protected virtual void UpdateHighlightRenderers()
        {
            if (highlightHolder == null)
                return;

            for (int skinnedIndex = 0; skinnedIndex < existingSkinnedRenderers.Length; skinnedIndex++)
            {
                SkinnedMeshRenderer existingSkinned = existingSkinnedRenderers[skinnedIndex];
                SkinnedMeshRenderer highlightSkinned = highlightSkinnedRenderers[skinnedIndex];

                if (existingSkinned != null && highlightSkinned != null && attachedToHand == false)
                {
                    highlightSkinned.transform.position = existingSkinned.transform.position;
                    highlightSkinned.transform.rotation = existingSkinned.transform.rotation;
                    highlightSkinned.transform.localScale = existingSkinned.transform.lossyScale;
                    highlightSkinned.localBounds = existingSkinned.localBounds;
                    highlightSkinned.enabled = isHovering && existingSkinned.enabled && existingSkinned.gameObject.activeInHierarchy;

                    int blendShapeCount = existingSkinned.sharedMesh.blendShapeCount;
                    for (int blendShapeIndex = 0; blendShapeIndex < blendShapeCount; blendShapeIndex++)
                    {
                        highlightSkinned.SetBlendShapeWeight(blendShapeIndex, existingSkinned.GetBlendShapeWeight(blendShapeIndex));
                    }
                }
                else if (highlightSkinned != null)
                    highlightSkinned.enabled = false;

            }

            for (int rendererIndex = 0; rendererIndex < highlightRenderers.Length; rendererIndex++)
            {
                MeshRenderer existingRenderer = existingRenderers[rendererIndex];
                MeshRenderer highlightRenderer = highlightRenderers[rendererIndex];

                if (existingRenderer != null && highlightRenderer != null && attachedToHand == false)
                {
                    highlightRenderer.transform.position = existingRenderer.transform.position;
                    highlightRenderer.transform.rotation = existingRenderer.transform.rotation;
                    highlightRenderer.transform.localScale = existingRenderer.transform.lossyScale;
                    highlightRenderer.enabled = isHovering && existingRenderer.enabled && existingRenderer.gameObject.activeInHierarchy;
                }
                else if (highlightRenderer != null)
                    highlightRenderer.enabled = false;
            }
        }

        /// <summary>
        /// Called when a Hand starts hovering over this object
        /// </summary>
        protected virtual void OnHandHoverBegin(Hand hand)
        {
            wasHovering = isHovering;
            isHovering = true;

            hoveringHands.Add(hand);

            if (highlightOnHover == true && wasHovering == false)
            {
                CreateHighlightRenderers();
                UpdateHighlightRenderers();
            }
        }


        /// <summary>
        /// Called when a Hand stops hovering over this object
        /// </summary>
        protected virtual void OnHandHoverEnd(Hand hand)
        {
            wasHovering = isHovering;

            hoveringHands.Remove(hand);

            if (hoveringHands.Count == 0)
            {
                isHovering = false;

                if (highlightOnHover && highlightHolder != null)
                    Destroy(highlightHolder);
            }
        }

        protected virtual void Update()
        {
            if (highlightOnHover)
            {
                UpdateHighlightRenderers();

                if (isHovering == false && highlightHolder != null)
                    Destroy(highlightHolder);
            }
        }


        protected float blendToPoseTime = 0.1f;
        protected float releasePoseBlendTime = 0.2f;

        protected virtual void OnAttachedToHand(Hand hand)
        {
            if (activateActionSetOnAttach != null)
                activateActionSetOnAttach.Activate(hand.handType);

            if (onAttachedToHand != null)
            {
                onAttachedToHand.Invoke(hand);
            }

            if (skeletonPoser != null && hand.skeleton != null)
            {
                hand.skeleton.BlendToPoser(skeletonPoser, blendToPoseTime);
            }

            attachedToHand = hand;
        }

        protected virtual void OnDetachedFromHand(Hand hand)
        {
            if (activateActionSetOnAttach != null)
            {
                if (hand.otherHand == null || hand.otherHand.currentAttachedObjectInfo.HasValue == false ||
                    (hand.otherHand.currentAttachedObjectInfo.Value.interactable != null &&
                     hand.otherHand.currentAttachedObjectInfo.Value.interactable.activateActionSetOnAttach != this.activateActionSetOnAttach))
                {
                    activateActionSetOnAttach.Deactivate(hand.handType);
                }
            }

            if (onDetachedFromHand != null)
            {
                onDetachedFromHand.Invoke(hand);
            }


            if (skeletonPoser != null)
            {
                if (hand.skeleton != null)
                    hand.skeleton.BlendToSkeleton(releasePoseBlendTime);
            }

            attachedToHand = null;
        }

        protected virtual void OnDestroy()
        {
            isDestroying = true;

            if (attachedToHand != null)
            {
                attachedToHand.DetachObject(this.gameObject, false);
                attachedToHand.skeleton.BlendToSkeleton(0.1f);
            }

            if (highlightHolder != null)
                Destroy(highlightHolder);

        }


        protected virtual void OnDisable()
        {
            isDestroying = true;

            if (attachedToHand != null)
            {
                attachedToHand.ForceHoverUnlock();
            }

            if (highlightHolder != null)
                Destroy(highlightHolder);
        }
    }
}

抓取脚本Core

代码

using UnityEngine;
using System.Collections;
using Valve.VR.InteractionSystem;
using System;
using Valve.VR;

//该脚本所必须的辅助脚本
[RequireComponent(typeof(Interactable))]
public class Core : MonoBehaviour
{
    private Interactable interactable;
    private Hand.AttachmentFlags attachmentFlags = Hand.defaultAttachmentFlags &
                                                    (~Hand.AttachmentFlags.SnapOnAttach) &
                                                    (~Hand.AttachmentFlags.DetachOthers) &
                                                    (~Hand.AttachmentFlags.VelocityMovement);
    void Awake()
    {
        interactable = this.GetComponent<Interactable>();
        //Sound初始化
        //audioSource = GetComponent<AudioSource>();
        //Soundplayer(audioSource, beginSound);
        UI初始化
        //textMesh = UI.GetComponentInChildren<TextMesh>();
        //textMesh.fontSize = 240;
        //textMesh.color = new Color32(248, 241, 22, 255);
        //textMesh.text = beginText;
    }

    /// <summary>
    /// 触碰但未抓取
    /// </summary>
    /// <param name="hand"></param>
    private void OnHandHoverBegin(Hand hand)
    {
        //if (textMesh != null)
        //{
        //    textMesh.color = new Color32(23, 219, 57, 255);
        //    textMesh.text = beginText;
        //}
    }

    /// <summary>
    /// 正在抓着物品
    /// </summary>
    /// <param name="hand"></param>
    private void OnAttachedToHand(Hand hand)
    {
        //StudyFlag.studyFlag = true;//去除第一次碰撞检测
        //Rigidbody rigidbodyOfAttachedObject = hand.currentAttachedObject.GetComponentInChildren<Rigidbody>();
        Transform transformOfAttachedObject = hand.currentAttachedObject.GetComponentInChildren<Transform>();
        //rigidbodyOfAttachedObject.drag = 10000;
        //rigidbodyOfAttachedObject.angularDrag = 10000;

        //foreach (var correctGameObject in correctGameObjects)
        //{
        //    if (correctGameObject.tag == hand.currentAttachedObject.tag)
        //    {
        //        Flag.operationCount++;
        //        Flag.correctCount++;
        //        Debug.Log(hand.currentAttachedObject.tag);
        //        switch (correctGameObject.tag)
        //        {
        //            case "Apple":
        //                SupermarketFlag.selectedApple = true;
        //                Debug.Log("Apple");
        //                break;
        //            case "Orange":
        //                SupermarketFlag.selectedOrange = true;
        //                Debug.Log("Orange");
        //                break;
        //            case "Pear":
        //                SupermarketFlag.selectedPear = true;
        //                Debug.Log("Pear");
        //                break;
        //        }
        //    }
        //}


        //if (textMesh != null)
        //{
        //    //textMesh.color = new Color32(23, 219, 57, 255);
        //    //textMesh.text = processText;
        //}
        //else
        //{
        //    //Soundplayer(audioSource, alreadySettedSuccessfully);
        //    //Flag.operationCount++;
        //}
    }

    /// <summary>
    /// 放下物品
    /// </summary>
    /// <param name="hand"></param>
    private void OnDetachedFromHand(Hand hand)
    {

        //Rigidbody rigidbodyOfAttachedObject = hand.currentAttachedObject.GetComponentInChildren<Rigidbody>();
        Transform transformOfAttachedObject = hand.currentAttachedObject.GetComponentInChildren<Transform>();
        //rigidbodyOfAttachedObject.drag = 1;
        //rigidbodyOfAttachedObject.angularDrag = 1;


        //if (textMesh != null)
        //{
        //    textMesh.color = new Color32(0, 90, 71, 255);
        //    textMesh.text = endText;

        //    Flag.correctCount++;
        //    Flag.operationCount++;

        //    StartCoroutine(WaitAndPrint(0.3f));//两秒后执行WaitAndPrint()方法
        //}
        //else
        //{
        //    if(textMesh != null)
        //    {
        //        textMesh.color = new Color32(248, 241, 22, 255);
        //        textMesh.text = errorText;
        //    }
        //    Flag.operationCount++;
        //}
    }

    /// <summary>
    /// 放开手
    /// </summary>
    /// <param name="hand"></param>
    private void HandAttachedUpdate(Hand hand)
    {
    }

    //等待wait时间执行 
    IEnumerator WaitAndPrint(float waitTime)
    {
        yield return new WaitForSeconds(waitTime);
        //等待之后执行的动作  
        //DestroyObject(textMesh);
    }

    /// <summary>
    /// 音频播放
    /// </summary>
    /// <param name="audioSource"></param>
    /// <param name="audioClip"></param>
    public void Soundplayer(AudioSource audioSource, AudioClip audioClip)
    {
        //this.audioSource = audioSource;
        //this.audioSource.clip = audioClip;
        //this.audioSource.Play();
    }

    /// <summary>
    /// 不能删除
    /// </summary>
    /// <param name="hand"></param>
    private void HandHoverUpdate(Hand hand)
    {
        GrabTypes startingGrabType = hand.GetGrabStarting();
        bool isGrabEnding = hand.IsGrabEnding(this.gameObject);

        if (interactable.attachedToHand == null && startingGrabType != GrabTypes.None)
        {
            hand.HoverLock(interactable);
            hand.AttachObject(gameObject, startingGrabType, attachmentFlags);
        }
        else if (isGrabEnding)
        {
            hand.DetachObject(gameObject);
            hand.HoverUnlock(interactable);
        }
    }
}

本文地址:https://blog.csdn.net/y18771025420/article/details/109279070