《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)

《SteamVR2.2.0官方教程》

《SteamVR2.2.0官方教程》

版本

作者

参与者

完成日期

备注

SteamVR2.2.0_Tutorials_V01_1.0

严立钻

 

2019.04.15

 

 

 

 

 

 

 

##《SteamVR2.2.0官方教程》发布说明:

++++“SteamVR2.2.0官方教程”:是对“SteamVR2.2.0”的官方教程(Tutorials)梳理总结;(2019年度的重点技术突破点确立为:“SteamVR”)(前面已经有了一个“V2.0”和“V2.2.0”开发指南了:https://blog.csdn.net/VRunSoftYanlz/article/details/86618187https://blog.csdn.net/VRunSoftYanlz/article/details/88784527;快速入门:https://blog.csdn.net/VRunSoftYanlz/article/details/88833579;交互系统:https://blog.csdn.net/VRunSoftYanlz/article/details/89199778;这个“官方教程”是基于前面几篇操作指南和快速入门的一个拓展,所以可以先粗略查阅一下这几篇博文;这里重点说明一下:实战是关键,所以官方教程是重中之重,后期还会基于熟悉官方示例的基础上拓展应用到现实应用中,敬请期待

++++“SteamVR2.2.0官方教程”:定位在熟悉SteamVR框架

 

++++SteamVR的Github:https://github.com/ValveSoftware/steamvr_unity_plugin

++++SteamVR的QuickStart:https://valvesoftware.github.io/steamvr_unity_plugin/

++++SteamVR的Releases:https://github.com/ValveSoftware/steamvr_unity_plugin/releases

++++SteamVR2.2.0开发指南https://blog.csdn.net/VRunSoftYanlz/article/details/88784527

++++SteamVR2.2.0快速入门https://blog.csdn.net/VRunSoftYanlz/article/details/88833579

++++SteamVR2.2.0交互系统https://blog.csdn.net/VRunSoftYanlz/article/details/89199778

++++SteamVR2.2.0传送机制https://blog.csdn.net/VRunSoftYanlz/article/details/89390866

++++SteamVR2.2.0官方教程https://blog.csdn.net/VRunSoftYanlz/article/details/89324067

++++SteamVR2.2.0教程(一)https://blog.csdn.net/VRunSoftYanlz/article/details/89324067

++++SteamVR2.2.0教程(二)https://blog.csdn.net/VRunSoftYanlz/article/details/89894097

 

 

 

##《SteamVR2.2.0官方教程》目录

#第一篇:v2.2.0快速入门

#第二篇:v2.2.0官方教程

#第三篇:v2.2.0的API

#第四篇:v2.2.0框架结构

#第五篇:立钻哥哥对SteamVR的拓展

推广:【XR游戏开发QQ群:784477094

 

 

 

#第一篇:v2.2.0快速入门

#第一篇:v2.2.0快速入门

#第一篇:v2.2.0快速入门

++++立钻哥哥:在“Valve”发布了“The Lab”之后,SteamVR也采用了该项目的经验,创建了一个“交互系统(Interaction System)”,该系统提供了一些常用的交互应用,包括:“与Unity UI元素的交互(Interaction with Unity UI elements)”,“拾起,放下,扔出去(Pickup, Drop, and Throw)”,“投掷速度的多种变化(Multiple variations on throwing velocites)”,“弓箭(Bow and Arrow)”,“轮交互(Wheel interactions)”,“邻近按钮(Proximity button)”,“各种骨骼输入示例(Variety of Skeleton Input example)”,“传送(Teleporting)”,“使用抓握对象(Using held objects)”,“使用手持物体的手的骨架输入(Using Skeleton Input to from a hand around a held object)”等,这些都是非常好的应用案例,后期立钻哥哥将一一剖析拓展,敬请期待关注“SteamVR”分类:https://blog.csdn.net/vrunsoftyanlz/article/category/8582642)!

++++SteamVR2.0开发指南:https://blog.csdn.net/VRunSoftYanlz/article/details/86618187

++++SteamVR2.2.0开发指南:https://blog.csdn.net/VRunSoftYanlz/article/details/88784527

++++SteamVR2.2.0快速入门:https://blog.csdn.net/VRunSoftYanlz/article/details/88833579

++++SteamVR2.2.0交互系统:https://blog.csdn.net/VRunSoftYanlz/article/details/89199778

++++A.1、快速入门(Getting started)

++++A.2、示例场景(Sample scene)

 

 

 

##A.1、快速入门(Getting started)

##A.1、快速入门(Getting started)

##A.1、快速入门(Getting started)

++++立钻哥哥:交互系统(Interaction System)是游戏的核心,一般是交互系统先行设计开发,基于交互系统再进行游戏交互的设计和情景设计;那我们就从“交互系统”出发,快速入门吧!

++++关于SteamVR的快速入门,可查阅这个链接:https://blog.csdn.net/VRunSoftYanlz/article/details/88833579

++++获取更多关于SteamVR技术知识,可查阅这个分类:https://blog.csdn.net/vrunsoftyanlz/article/category/8582642

++++A.1.1、交互系统(Interaction System)的认知

++++A.1.2、入门指南(Getting started)

 

 

 

###A.1.1、交互系统(Interaction System)的认知

###A.1.1、交互系统(Interaction System)的认知

++A.1.1、交互系统(Interaction System)的认知

++++立钻哥哥:在Valve发布“The Lab”之后,SteamVR也创建了一个“交互系统”,我们可以在自己的项目中使用这些例子,该系统也更新使用了“SteamVR Input”和新的“SteamVR Skeleton Input”系统

++++[Interaction with Unity UI elements]:与Unity UI元素的交互

++++[Pickup, Drop, and Throw]:拾起,放下,扔出去

++++[Multiple variations on throwing velocities]:投掷速度的多种变化

++++[Bow and Arrow]:弓箭

++++[Wheel interactions]:轮交互

++++[Proximity button]:邻近按钮

++++[Variety of Skeleton Input example]:各种骨骼输入示例

++++[Teleporting]:传送

++++[Using held objects]:使用抓握对象

++++[Using Skeleton Input to from a hand around a held object]:使用手持物体的手的骨骼输入

 

++“The Lab”中的交互系统(Interaction System)

++++立钻哥哥:“交互系统(Interacion System)”是一系列脚本、预制体和其他资源,是“The Lab”中所有迷你游戏和其他场景的基础,这个系统最初被设计成轻量级和灵活的,这样他就可以支持我们当时正在进行的所有实验

++++Steam平台上的“The Lab”链接:https://store.steampowered.com/app/450390/The_Lab/

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第1张图片

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第2张图片

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第3张图片

 

 

 

 

###A.1.2、入门指南(Getting Started)

###A.1.2、入门指南(Getting Started)

++A.1.2、入门指南(Getting Started)

++++立钻哥哥:要获取示例,可查看“Assets/SteamVR/InteractionSystem/Samples/Scenes”中的“Interactions_Example”场景

++++Assets/SteamVR/InteractionSystem/Samples/立钻哥哥的测试场景(Interactions_Example).unity

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第4张图片

++++1、新建场景

++++2、删除“主摄像机”对象

++++3、将“Player”预制体拖放到场景中

++++4、戴上头盔观察场景

++++5、观察“Skeleton Input”控制器

++++6、添加“Interactable”可交互组件

++++7、添加“Throwable”可抛出组件

++++8、添加“Skeleton Poser”骨架姿态组件

++++9、添加“Teleporting”传送预制体

++++10、添加“TeleportPoint”传送点预制体

++++11、添加“TeleportArea”传送区域预制体

 

 

++1、新建场景

++++立钻哥哥:新建场景;当然,那需要先导入“SteamVR插件”

++++SteamVR的Unity资源商店链接:https://assetstore.unity.com/packages/tools/integration/steamvr-plugin-32647

++++SteamVR在Github上的Releasehttps://github.com/ValveSoftware/steamvr_unity_plugin/releases

++++新建工程后,导入SteamVR插件,那就可以开始新建一个测试场景了

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第5张图片

 

 

 

++2、删除“主摄像机”对象

++++立钻哥哥:删除“主摄像机(Main Camera)”

++++如果需要做一款VR游戏,需要把摄像机调成VR视角

++++[方法1]:使用预制的VR摄像机

++++[方法2]:将普通的摄像机修改成VR摄像机

++++Tips:比较详细的描述可参考“SteamVR简介”https://blog.csdn.net/VRunSoftYanlz/article/details/86484254

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第6张图片

 

 

 

++3、将“Player”预制体拖放到场景中

++++立钻哥哥:将“Assets/SteamVR/InteractionSystem/Core/Prefabs/”下的“Player.prefab”预制体拖到场景中;这个预制体设置了主要的玩家和手,它还挂钩到所有相关的“SteamVR Input”需要的动作

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第7张图片

 

 

 

++4、戴上头盔观察场景

++++立钻哥哥:现在我们就可以戴上头盔观察一下场景吧,里面有什么呢?估计是一个空白的场景,很可能有控制器呀!

 

 

 

++5、观察“Skeleton Input”控制器

++++立钻哥哥:如果我们的控制器是支持“Skeleton Input”的,操作时会看到双手触摸并按下控制器上的按钮

 

 

 

++6、添加“Interactable”可交互组件

++++立钻哥哥:将“Interactable”组件添加到场景中的任何对象中,该对象上的所有其他组件将开始从玩家手中接收相关信息了

++++可参考:Assets/SteamVR/InteractionSystem/Samples/Scripts/InteractableExample.cs

//Purpose: Demonstrates how to create a simple interactable object.(立钻哥哥:目的:演示如何创建一个简单的可交互对象.

using UnityEngine;

using System.Collections;

 

namespace Valve.VR.InteractionSystem.Sample{

    [RequireComponent(typeof(Interactable))]

    public class InteractableExample : MonoBehaviour{

        private TextMesh generalText;

        private TextMesh hoveringText;

        private Vector3 oldPosition;

        private Quaternion oldRotation;

 

        private float attachTime;

 

        private Hand.AttachmentFlags attachmentFlags = Hand.defaultAttachmentFlags

            & (~Hand.AttachmentFlags.SnapOnAttach)

            & (~Hand.AttachmentFlags.DetachOthers)

            & (~Hand.AttachmentFlags.VelocityMovement);

        

        private Interactable interactable;

 

        void Awake(){

            var textMeshs = GetComponentsInChildren<TextMesh>()

            generalText = textMeshs[0];

            hoveringText = textMeshs[1];

 

            generalText.text = 立钻哥哥:No Hand Hovering!;

            hoveringText.text = 立钻哥哥:Hovering: False!;

 

            interactable = this.GetComponent<Interactable>();

        }

 

        //Called when a Hand starts hovering over this object.(立钻哥哥:当一只手开始悬停在该对象上时调用

        private void OnHandHoverBegin(){

            generalText.text = 立钻哥哥:Hovering hand:  + hand.name;

        }

 

        //Called when a Hand stops hovering over this object.(立钻哥哥:当一只手停止悬停在该对象上时调用.

        private void OnHandHoverEnd(Hand hand){

            generalText.text = 立钻哥哥:No Hand Hovering.;

        }

 

        //Called every Update() while a Hand is hovering over this object.(立钻哥哥:当一只手悬停在此对象上时调用每个Update().

        private void HandHoverUpdate(Hand hand){

            GrabTypes startingGrabType = hand.GetGrabStarting();

            bool isGrabEnding = hand.IsGrabEnding(this.gameObject);

 

            if(interactable.attachedToHand == null && startingGrabType != GrabType.None){

                //Save our position/rotation so that we can restore it when we detach.(立钻哥哥:保存我们的位置/旋转,以便我们可以在分离时恢复它

                oldPosition = transform.position;

                oldRotation = transform.rotation;

 

                //Call this to continue receiving HandHoverUpdate messages, and prevent the hand from hovering over anything else.(立钻哥哥:调用此函数可以继续接收HandHoverUpdate消息,并防止手悬停在任何其他位置.

                hand.HoverLock(interactable);

 

                //Attach this object to the hand.(立钻哥哥:把这个物体系在手上.

                hand.AttachObject(gameObject, startingGrabType, attachmentFlags);

 

            }else if(isGrabEnding){

                //Detach this object from the hand.(立钻哥哥:将此对象从手中分离出来.

                hand.DetachObject(gameObject);

 

                //Call this to undo HoverLock.(立钻哥哥:调用此命令可以撤销HoverLock

                hand.HoverUnlock(interactable);

 

                //Restore position/rotation.(立钻哥哥:恢复/旋转位置

                transform.position = oldPosition;

                transform.rotation = oldRotation;

            }

        }    //立钻哥哥:private void HandHoverUpdate(Hand hand){}

 

        //Called when this GameObject becomes attached to the hand.(立钻哥哥:当GameObject(游戏物体)与手相连时调用.

        private void OnAttachedToHand(Hand hand){

            generalText.text = string.Format(立钻哥哥:Attached: {0}, hand.name);

            attachTime = Time.time;

        }

 

        //Called when this GameObject is detached from the hand.(立钻哥哥:当GameObject(游戏物体)与手分离时调用.

        private void OnDetachedFromHand(Hand hand){

            generalText.text = string.Format(立钻哥哥:Attached: {0} :: Time:{1:F2}, hand.name, (Time.time - attachTime));

        }

 

        private bool lastHovering = false;

        private void Update(){

            if(interactable.isHovering != lastHovering){

                hoveringText.text = string.Format(Hovering: {0}, interactable.isHovering);

                lastHovering = interactable.isHovering;

            }

        }    //立钻哥哥:private void Update(){}

 

        //Called when this attached GameObject becomes the primary attached object.(立钻哥哥:当这个附属游戏对象成为主要附属对象时调用.

        private void OnHandFocusAcquired(Hand hand){

        }

 

        //Called when another attached GameObject becomes the primary attached object.(立钻哥哥:当另一个附加游戏对象成为主要附加对象时调用.

        private void OnHandFocusLost(Hand hand){

        }

 

    }    //立钻哥哥:public class InteractableExample:MonoBehaviour{}

 

}    //立钻哥哥:namespace Valve.VR.InteractionSystem.Sample{}

 

++++立钻哥哥:这里必须指出一点的是,SteamVR在这里没有采用delegate-event形式,而是采用了SendMessage(),这个是有争议的,但是不伤大雅!

//立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs

//Purpose: The hands used by the player in the vr interaction system.(立钻哥哥:用途:玩家在vr交互系统中使用的手

using UnityEngine;

using System.Threading;

 

namespace Valve.VR.InteractionSystem{

    //Links with an appropriate SteamVR controller and facilitates interactions with objects in the virtual world.(立钻哥哥:链接到适当的SteamVR控制器,并方便与虚拟世界中的对象进行交互.

    public class Hand : MonoBehaviour{

++++L170: _hoveringInteractable.SendMessage(OnHandHoverEnd, this, SendMessageOptions.DontRequireReceiver);

++++L185: _hoveringInteractable.SendMessage(OnHandHoverBegin, this, SendMessageOptions.DontRequireReceiver);

++++L384: currentAttachedObject.SendMessage(OnHandFocusLost, this, SendMessageOptions.DontRequireReceiver);

++++L560: objectToAttach.SendMessage(OnAttachedToHand, this, SendMessageOptions.DontRequireReceiver);

++++L656: attachedObjects[index].attachedObject.SendMessage(OnDetachedFromHand, this, SendMessageOptions.DontRequireReceiver);

++++L672: newTopObject.SendMessage(OnHandFocusAcquired, this, SendMessageOptions.DontRequireReceiver);

++++L1083: attachedObject.SendMessage(HandAttachedUpdate, this, SendMessageOptions.DontRequireReceiver);

++++L1088: hoveringInteractable.SendMessage(HandHoverUpdate, this, SendMessageOptions.DontRequireReceiver);

++++L1202: attachedInfo.interactable.gameObject.SendMessage(OnThrowableAttachEaseInCompleted, this, SendMessageOptions.DontRequireReceiver);

    }    //立钻哥哥:public class Hand:MonoBehaviour{}

}    //立钻哥哥:namespace Valve.VR.InteractionSystem{}

 

//立钻哥哥:SendMessageOptions

using System;

namespace UnityEngine{

    public enum SendMessageOptions{

        RequireReceiver,

        DontRequireReceiver

    }    //立钻哥哥:public enum SendMessageOptions{}

}    //立钻哥哥:namespace UnityEngine{}

 

//立钻哥哥:GameObject.SendMessage()发送消息

void SendMessage(string methodName, object value=null, SendMessageOptions options=SendMessageOptions.RequireReceiver);

++++[methodName]: 调用的方法名;

++++[value]:可选参数,被调用的方法传递的值;

++++[options]:如果目标对象方法不存在,是否引发错误;

++++[描述]:在此游戏对象所有MonoBehaviour上调用名称为methodName的方法;接收消息的方法可以通过不要参数的方法来选择忽略参数;当选项被设置为[SendMessageOptions.RequireReceiver]时,如果消息没有被任何一个组件处理,则会打印一个错误;

++++[注意]:消息不会发送到非激活的对象上(如,那些在编辑器或者通过SetActive已经关闭的对象);

 

using UnityEngine;

using System.Collections;

 

public class YanlzExampleClass : MonoBehaviour{

    void YanlzApplyDamage(float damage){

        Debug.Log(立钻哥哥:受到的攻击 + damage);

    }

 

    void MyExampleFunc(){

        gameObject.SendMessage(YanlzApplyDamage, 5.0f);

    }    

}    //立钻哥哥:public class YanlzExampleClass:MonoBehaviour{}

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第8张图片

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第9张图片

 

++++立钻哥哥:比较全面地熟悉了“InteractableExample.cs”和相关的“Hand.cs”,那我们顺便熟悉一下“Interactable.cs”吧:

//立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Interactable.cs

//Purpose: This object will get hover events and can be attached to the hands.(立钻哥哥:用途:此对象将获得悬停事件,并可以附加到

using UnityEngine;

using UnityEngine.Event;

using System.Collections;

using System.Collections.Generic;

 

namespace Valve.VR.InteractionSystem{

    public class Interactable : MonoBehaviour{

        public SteamVR_ActionSet activateActionSetOnAttach;

        public bool hideHandOnAttach = true;

        public bool hideSkeletonOnAttach = false;

        public bool hideControllerOnAttach = false;

        public int handAnimationOnPickup = 0;

        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;

 

        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;

 

        [HideInInspector]

        public SteamVR_Skeleton_Poser skeletonPoser;

 

        public bool handFollowTransform = true;

 

        public bool highlightOnHover = true;

        protected MeshRenderer[] highlightRenderers;

        protected MeshRenderer[] existingRenderers;

        protected GameObject highlightHolder;

        protected SkinnedMeshRenderer[] highlightSkinnedRenderers;

        protected SkinnedMeshRenderer[] existingSkinnedRenderers;

        protected static Material highlightMat;

        public GameObject[] hideHighlight;

 

        [System.NonSerialized]

        public Hand attachedToHand;

 

        [System.NonSerialized]

        public Hand hoveringHand;

 

        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(){

            highlightMat = (Material)Resources.Load(SteamVR_HoverHighlight, typeof(Material));

        }

 

        protected virtual bool ShouldIgnoreHighlight(Component component){}

        protected virtual bool ShouldIgnore(GameObject check){}

 

        protected virtual void CreateHighlightRenderers(){

            existingSkinnedRenderers = this.GetComponentsInChildren<SkinnedMeshRenderer>(true);

            highlightHolder = new GameObject(Highlighter);

            highlightSkinnedRenderers = new SkinnedMeshRenderer[existingSkinnedRenderers.Length];

        }

 

        protected virtual void UpdateHighlightRenderers(){}

        protected virtual void OnHandHoverBegin(Hand hand){}

        private void OnHandHoverEnd(Hand hand){}

        protected virtual void Update(){}

 

        protected float blendToPoseTime = 0.1f;

        protected float releasePoseBlendTime = 0.2f;

 

        protected virtual void OnAttachedToHand(Hand hand){}

        protected virtual void OnDetachedFromHand(Hand hand){}

        protected virtual void OnDestroy(){}

        protected virtual void OnDisable(){}

 

    }    //立钻哥哥:public class Interactable:MonoBehaviour{}

 

}    //立钻哥哥:namespace Valve.VR.InteractionSystem{}

 

 

++++立钻哥哥:其实上面的那些都是了解,没有真正实战,实战才是关键,那我们就开始操练起来:

//立钻哥哥:参考“InteractableExample.cs”编写一个脚本“YanlzVRDemoInteractable190416.cs”

//目的:能把那个风骚的Cube拿起来!

using UnityEngine;

using System.Collections;

 

namespace YanlzXR.VR.InteractionSystem.Sample{

    [RequireComponent(typeof(Interactable))]

    public class YanlzVRDemoInteractable190416 : MonoBehaviour{

        private Vector3 oldPosition;

        private Quaternion oldRotation;

 

        private Hand.AttachmentFlags attachmentFlags = Hand.defaultAttachmentFlags

            & (~Hand.AttachmentFlags.SnapOnAttach)

            & (~Hand.AttachmentFlags.DetachOthers)

            & (~Hand.AttachmentFlags.VelocityMovement);

 

        private Interactable interactable;

 

        void Awake(){

            Debug.Log(立钻哥哥:----YanlzVRDemoInteractable190416----[Awake()]----IN----);

            interactable = this.GetComponent<Interactable>();

        }

 

        //Called every Update() while a Hand is hovering over this object.(立钻哥哥:当一只手悬停在此对象上时每个Update()都调用.

        private void HandHoverUpdate(Hand hand){

            GrabTypes startingGrabType = hand.GetGrabStarting();

            bool isGrabEnding = hand.IsGrabEnding(this.gameObject);

 

            if(interactable.attachedToHand == null && startingGrabType != GrabTypes.None){

                //Save our position/rotation so that we can restore it when we detach.(立钻哥哥:保存我们的位置/旋转,以便我们可以在分离时恢复它.

                oldPosition = transform.position;

                oldRotation = transform.rotation;

 

                //Call this to continue receiving HandHoverUpdate message, and prevent the hand from hovering over anything else.(立钻哥哥:调用此函数可以继续接收HandHoverUpdate消息,并防止手悬停在任何其他位置.

                hand.HoverLock(interactable);

 

                //Attach this object to the hand.(立钻哥哥:把这个物体系在手上.

                hand.AttachObject(gameObject, startingGrabType, attachmentFlags);

 

            }else if(isGrabEnding){

                //Detach this object from the hand.(立钻哥哥:将此对象从手中分离出来.

                hand.DetachObject(gameObject);

 

                //Call this to undo HoverLock.(立钻哥哥:调用此命令可以撤销HoverLock

                hand.HoverUnlock(interactable);

 

                //Restore position/rotation.(立钻哥哥:恢复旋转/位置

                transform.position = oldPosition;

                transform.rotation = oldRotation;

            }

 

        }    //立钻哥哥:private void HandHoverUpdate(Hand hand){}

 

    }    //立钻哥哥:public class YanlzVRDemoInteractable190416:MonoBehaviour{}

 

}    //立钻哥哥:namespace YanlzXR.VR.InteractionSystem.Sample{}

 

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第10张图片

 

++知识点01:Hand.AttachmentFlags

++++立钻哥哥:The flags used to determine how an object is attached to the hand.用于确定对象如何附加到手的标志

++++public const AttachmentFlags defaultAttachmentFlags = AttachmentFlags.ParentToHand | AttachmentFlags.DetachOthers | AttachmentFlags.DetachFromOtherHand | AttachmentFlags.TurnOnKinematic | AttachmentFlags.SnapOnAttach;

++++[Flags] public enum AttachmentFlags{

    SnapOnAttach = 1 << 0,

    DetachOthers = 1 << 1,

    DetachFromOtherHand = 1 << 2;

    ParentToHand = 1 << 3,

    VelocityMovement = 1 << 4,

    TurnOnKinematic = 1 << 5,

    TurnOffGravity = 1 << 6,

    AllowSidegrade = 1 << 7,

};

++++[SnapOnAttach]:The object should snap to the position of the specified attachment point on the hand.(立钻哥哥:[SnapOnAttach]: 将物体附着在手的指定位置。

++++[DetachOthers]:Other objects attached to this hand will be detached.立钻哥哥:[DetachOthers]:其他对象附加到这只手会分离.

++++[DetachFromOtherHand]:This object will be detached from the other hand.立钻哥哥:[DetachFromOtherHand]:这个对象将从另一只手脱离

++++[ParentToHand]:The object will be parented to the hand.立钻哥哥:[ParentToHand]:对象将作为的子物体。

++++[VelocityMovement]:The object will attempt to move to match the position and rotation of the hand.立钻哥哥:[VelocityMovement]:对象将尝试移动到位置和旋转都匹配的手上。

++++[TurnOnKinematic]:The object will not respond to external physics.立钻哥哥:[TurnOnKinematic]: 对象不响应外部物理属性。

++++[TurnOffGravity]:The object will not respond to external physics.立钻哥哥:[TurnOffGravity]:外部物理对象不会回应

++++[AllowDidegrade]:The object is able to switch from a pinch grab to a grip grab. Decreases likelyhood of a good throw but also decreases likelyhood of accidental drop.立钻哥哥:AllowDidegrade]:对象可以切换从一个捏抓握抓。减少一个好的投掷的可能性,但也减少意外掉落的可能性

 

++知识点02:HandHoverUpdate

++++立钻哥哥:private void HandHoverUpdate(Hand hand){}

++++我们来加个断点来调试跟踪一下,这个接口是从哪里调用过来的:

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第11张图片

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第12张图片

 

 

++++\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs

//立钻哥哥:L1076(void Valve.VR.InteractionSystem.Hand:Update())

protected virtual void Update(){

    UpdateNoSteamVRFallback();

 

    GameObject attachedObject = currentAttachedObject;

    if(attachedObject != null){

        attachedObject.SendMessage(HandAttachedUpdate, this, SendMessageOptions.DontRequireReceiver);

    }

 

    if(hoveringInteractable){

        //立钻哥哥:void YanlzXR.VR.InteractionSystem.Sample.YanlzVRDemoInteractable190416:HandHoverUpdate(Hand) ==>private void HandHoverUpdate(Hand hand){}

        hoveringInteractable.SendMessage(HandHoverUpdate, this, SendMessageOptions.DontRequireReceiver);

    }

}    //立钻哥哥:protected virtual void Update(){}

 

++知识点03:hand.GetGrabStarting()

++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs

public GrabType GetGrabStarting(GrabTypes explicitType=GrabType.None){

    if(explicitType != GrabTypes.None){

        if(noSteamVRFallbackCamera){

            if(Input.GetMouseButtonDown(0)){

                return explicitType;

            }

        }

 

        if(explicitType == GrabTypes.Pinch && grabPinchAction.GetStateDown(handType)){

            return GrabTypes.Pinch;

        }

 

        if(explicitType == GrabTypes.Grip && grabGripAction.GetStateDown(handType)){

            return GrabTypes.Grip;

        }

 

    }else{

        if(noSteamVRFallbackCamera){

            if(Input.GetMouseButtonDown(0)){

                return GrabType.Grip;

            }

        }

 

        if(grabPinchAction.GetStateDown(handType)){

            return GrabTypes.Pinch;

        }

 

        if(grabGripAction.GetStateDown(handType)){

            return GrabTypes.Grip;

        }

 

        return GrabTypes.None;

    }

 

    return GrabTypes.None;

}

 

++知识点04:hand.IsGrabEnding()

++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs

public bool IsGrabEnding(GameObject attachedObject){

    for(int attachedObjectIndex=0; attachedObjectIndex < attachedObjects.Count; attachedObjectIndex++){

        if(attachedObjects[attachedObjectIndex].attachedObject == attachedObject){

            return IsGrabbingWithType(attachedObjects[attachedObjectIndex].grabbedWithType) == false;

        }

    }

 

    return false;

}

 

++知识点05:hand.HoverLock()

++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs

//Continue to hover over this object indefinitely, whether or not the Hand moves out of its interaction trigger volume.(立钻哥哥:无论手是否移出交互触发范围,都将无限期地悬停在该对象上

public void HoverLock(Interactable interactable){

    if(spewDebugText){

        HandDebugLog(立钻哥哥:HoverLock  + interactable);

    }

 

    hoverLocked = true;

 

    //[interactable]: The Interactable to hover over indefinitely.(立钻哥哥:[可交互的]:可以无限悬停的可交互的

    hoveringInteractable = interactable;

}

 

++知识点05:hand.AttachObject()

++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs

//Attach a GameObject to this GameObject.(立钻哥哥:将GameObject(游戏物体)附加到这个GameObject(游戏物体)上。

//[objectToAttach]: The GameObject to attach.(立钻哥哥:[objectToAttach]:要附加的GameObject

//[flags]: The flags to use for attaching the object.(立钻哥哥:[flags]:用于附加对象的标志.

//[attachmentPoint]: Name of the GameObject in the hierarchy of this Hand which should act as the attachment point for this GameObject.(立钻哥哥:[attachmentPoint]:这只手的层次结构中GameObject的名称,它应该作为这个GameObject的连接点.

public void AttachObject(GameObject objectToAttach, GrabTypes grabbedWithType, AttachmentFlags flags=defaultAttachmentFlags, Transform attachmentOffset=null){

    AttachedObject attachedObject = new AttachedObject();

    attachedObject.attachmentFlags = flags;

    attachedObject.attachedOffsetTransform = attachmentOffset;

    attachedObject.attachTime = Time.time;

 

    if(flags == 0){

        flags = defaultAttachmentFlags;

    }

 

    //Make sure top object an stack is non-null.(立钻哥哥:确保栈顶对象非空.

    CleanUpAttachedObjectStack();

 

    ... ...

 

    attachedObjects.Add(attachedObject);

 

    UpdateHovering();

 

   objectToAttach.SendMessage(OnAttachedToHand, this, SendMessageOptions.DontRequireReceiver);

 

}    //立钻哥哥:public void AttachObject{}

 

++知识点05:hand.DetachObject()

++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs

//Detache this GameObject from the attached object stack of this Hand.(立钻哥哥:从这只手的附加对象堆栈中分离这个GameObject.

//[objectToDetach]: The GameObject to detach from this Hand.(立钻哥哥:[objectToDetach]:要从这只手分离的GameObject.

public void DetachObject(GameObject objectToDetach, bool restoreOriginalParent=true){

    int index = attachedObjects.FindIndex(l => l.attachedObject == objectToDetach);

    if(index != -1){  ...  }

    ... ...

}

 

++知识点05:hand.HoverUnlock()

++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs

//Stop hovering over this object indefinitely.(立钻哥哥:停止无限期地悬停在这个物体上.

//[interactable]: The hover-locked Interactable to stop hovering over indefinitely.(立钻哥哥:[可交互]:锁定物体的可交互,以停止无限期地悬停

public void HoverUnlock(Interactable interactable){

    if(hoveringInteractable == interactable){

        hoverLocked = false;

    }

}

 

++立钻哥哥:Hand”类为“交互系统(Interaction System)”做了大部分繁重的工作;“Hand”检查它所悬停的对象(Interactables),并根据当前悬停状态向它们发送消息;一只手一次只能悬停在一个物体上;物体可以附着在手上,也可以从手上分离出来,只有一个对象可以是手的焦点对象,但同时可以将多个对象附加到手;一旦一个对象与手分离,那么与手相连的前一个对象(如果它仍然与手相连)就成为手的焦点对象;当没有任何东西附着在手上时,它总是会显示控制器;所附加的对象可以设置AttachmentFlags,该标记确定手和对象在被附加后的行为;根据不同的情况,可以将手锁定在悬停在其他物体或任何物体上

 

++“Hand”手发送给正在与之交互的对象的消息:

++++立钻哥哥、OnHandHoverBegin、HandHoverUpdate、OnHandHoverEnd、OnAttachedToHand、HandAttachedUpdate、OnDetachedFromHand、OnHandFocusLost、OnHandFocusAcquired;

++++[OnHandHoverBegin]:当手第一次开始悬停在对象上时发送

++++[HandHoverUpdate]:发送手悬停在对象上的每一帧

++++[OnHandHoverEnd]:当手离开悬停物体上时发送

++++[OnAttachedToHand]:当对象附加到hand上时发送

++++[HandAttachedUpdate]:当对象附在手上时,发送每一帧

++++[OnDetachedFromHand]:当对象脱离手时发送

++++[OnHandFocusLost]:当一个附加对象因为其他对象被附加到手上而失去焦点时发送

++++[OnHandFocusAcquired]:当一个附加对象获得焦点时发送,因为之前的焦点对象已经与手分离

+++++++++++++++++++++

//立钻哥哥:我们这里的【6、添加“Interactable”可交互组件】中就应用到了“HandHoverUpdate(Hand hand)”

private void HandHoverUpdate(Hand hand){

    GrabTypes startingGrabType = hand.GetGrabStarting();

    bool isGrabEnding = hand.IsGrabEnding(this.gameObject);

 

    if(interactable.attachedToHand == null && startingGrabType != GrabTypes.None){

        oldPosition = transform.position;

        oldRotation = transform.rotation;

        hand.HoverLock(interactable);

        hand.AttachObject(gameObject, startingGrabType, attachmentFlags);

    }else if(isGrabEnding){

        hand.DetachObject(gameObject);

        hand.HoverUnlock(interactable);

        transform.position = oldPosition;

        transform.rotation = oldRotation;

    }

}    //立钻哥哥:private void HandHoverUpdate(Hand hand){}

 

++“Hand”手发送给它的子对象的消息

++++立钻哥哥:OnHandInitialized、OnParentHandHoverBegin、OnParentHandHoverEnd、OnParentHandInputFocusAcquired、OnParentHandInputFocusLost;

++++[OnHandInitialized]:通过将自己与“SteamVR”跟踪控制器的设备ID相关联,首次初始化手时发送

++++[OnParentHandHoverBegin]:当手开始悬停在某物上时发送

++++[OnParentHandHoverEnd]:当手离开悬停在某物上时发送

++++[OnParentHandInputFocusAcquired]:当游戏窗口获得输入焦点时发送

++++[OnParentHandInputFocusLost]:当游戏窗口失去输入焦点时发送

 

++“Hand”类中处理连接和分离的成员

++++立钻哥哥:AttachObject、DetachObject、currentAttachedObject;

++++[AttachObject]:使用传递的AttachmentFlags从手上附加对象

++++[DetachObject]:从手中分离对象,并可选地将其还原到其原始父对象

++++[currentAttachedObject]:这将返回手上的“in-focus”附加对象(如果有的话)

 

++“Hand”类中用来定制其行为的有用的属性和功能

++++立钻哥哥:otherHand、hoverSphereTransform、hoverSphereRadius、hoverLayerMask、hoverUpdateInterval、HoverLock、HoverUnlock、GetGrabStarting、GetGrabEnding;

++++[public Hand otherHand;]:这是Player上的另一只手,这对于需要双手交互的对象(如长弓)非常有用

++++[public Transform hoverSphereTransform; public float hoverSphereRadius=0.05f;]:可用于自定义手的悬停范围

++++[public LayerMask hoverLayerMask=-1;]:这可以改变,使手只悬停在某些层的对象上

++++[public float hoverUpdateInterval=0.1f;]:可以根据游戏的需求定义悬停检查的频率

++++[public void HoverLock(Interactable interactable){}; public void HoverUnlock(Interactable interactable){};]:这是用来让手只悬停在一个特定的物体上;传递null将使手在悬停锁定时不悬停在其他物体上;此技术用于使手在传送弧处于活动状态时不悬停在物体上

++++[public GrabTypes GetGrabStarting(GrabTypes explicitType=GrabTypes.None){}; public GrabTypes GetGrabEnding(GrabTypes explicitType=GrabTypes.None){};]:这些用于确定布尔抓取操作是否在那个时候被触发;抓握有两种类型:抓取和捏抓;这些通常与手柄按钮和触发器按钮相关联,但在“Knuckles控制器”上具有特殊功能

 

++Interactable(可交互的)

++++立钻哥哥:Interactable类更像是一个标识符,它向“手”标识该对象是可交互的

++++任何具有此“Interactable”组件的对象都将从“Hand”接收相关信息

++++\Assets\SteamVR\InteractionSystem\Core\Scripts\Interactable.cs(立钻哥哥:此对象将获得悬停事件,并可以附加到手上)

 

 

 

++++立钻哥哥:好吧,拓展了这么多,貌似啥啥啥??!! =>好吧,那就看一下利用“Interactable”组件实现的效果吧:

 

 

 

++7、添加“Throwable”可抛出组件

++++立钻哥哥:“将Throwable组件添加到对象中,将允许玩家拾取并抛出该物体”,Throwable”是最基本的交互对象之一;当一只手悬停在这个物体上并按下其中一个抓取按钮(通常是扳机或手柄)时,玩家可以拿起这个物体;当按下按钮时,该对象被附在手上并保持在那里;当按钮被释放时,手中的任何速度都被赋予抛出的物体;这让我们可以创建可以拾取和抛出的基本对象

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第13张图片

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第14张图片

 

++++立钻哥哥:只要把“Throwable”组件加到物体上,这个物体就可以被抛出了!那我们来看一下效果吧:

 

++++立钻哥哥:现在我们来剖析一下这个神奇的脚本“Throwable.cs”:

//Purpose: Basic throwable object.(立钻哥哥:用途:基本抛掷物.

using UnityEngine;

using UnityEngine.Events;

using System.Collections;

 

namespace Valve.VR.InteractionSystem{

     [RequireComponent(typeof(Interactable))]

    [RequireComponent(typeof(Rigidbody))]

    [RequireComponent(typeof(VelocityEstimator))]

    public class Throwable : MonoBehaviour{

        [EnumFlags]

        [Tooltip(The flags used to attach this object to the hand.(立钻哥哥:用于将此对象附加到手的标志.)]

        public Hand.AttachmentFlags attachmentFlags = Hand.AttachmentFlags.ParentToHand | Hand.AttachmentFlags.DetachFromOtherHand | Hand.AttachmentFlags.TurnOnKinematic;

    

        [Tooltip(The local point which acts as a positional and rotational offset to use while held.(立钻哥哥:局部点,在保持时起位置偏移和旋转偏移的作用.)]

        public Transform attachmentOffset;

 

        [Tooltip(How fast must this object be moving to attach due to a trigger hold instead of a trigger press?(-1 to disable.)(立钻哥哥:由于触发器保持而不是触发器按下,该对象移动到附加时的速度必须有多快?(-1禁用).)]

        public float catchingSpeedThreshold = -1;

 

        public ReleaseStyle releaseVelocityStyle = ReleaseStyle.GetFromHand;

 

        [Tooltip(This time offset used when releasing the object with the RawFromHand option.(立钻哥哥:使用RawFromHand选项释放对象时使用的时间偏移量.)]

        public float releaseVelocityTimeOffset = -0.011f;

    

        public float scaleReleaseVelocity = 1.1f;

 

        [Tooltip(When detaching the object, should it return to its original parent?(立钻哥哥:当分离对象时,它应该返回到原来的父对象吗?)]

        public bool restoreOriginalParent = flase;

 

        protected VelocityEstimator velocityEstimator;

        protected bool attached = false;

        protected float attachTime;

        protected Vector3 attachPosition;

        protected Quaternion attachRotation;

        protected Transform attachEaseInTransform;

 

        public UnityEvent onPickUp;

        public UnityEvent onDetachFromHand;

        public UnityEvent<Hand> onHeldUpdate;

 

        protected RigidbodyInterpolation handInterpolation = RigidbodyInterpolation.None;

        protected new Rigidbody rigidbody;

 

        [HideInInspector]

        public Interactable interactable;

 

        protected virtual void Awake(){

            velocityEstimator = GetComponent<VelocityEstimator>();

            interactable = GetComponent<Interactable>();

 

            rigidbody = GetComponent<Rigidbody>();

            rigidbody.maxAngularVelocity = 50.0f;

 

            if(attachmentOffset != null){

                //remove?

                //interactable.handFollowTransform = attachmentOffset;

            }

        }    //立钻哥哥:protected virtual void Awake(){}

 

        protected virtual void OnHandHoverBegin(Hand hand){

            bool showHint = false;

    

            //Catch the throwable by holding down the interaction button instead of pressing it. Only do this if the throwable is moving faster than the prescribed threshold speed, and if it isnt attached to another hand.(立钻哥哥:按下交互按钮,而不是按下按钮,就可以“捕捉”可扔物品。只有当投掷物的移动速度超过规定的阈值速度,并且没有附在另一只手上时才这样做.

            if(!attached && catchingSpeedThreshold != -1){

                float catchingThreshold = catchingSpeedThreshold * SteamVR_Utils.GetLossyScale(Player.instance.trackingOriginTransform);

                GrabTypes bestGrabType = hand.GetBestGrabbingType();

 

                if(bestGrabType != GrabTypes.None){

                    if(rigidbody.velocity.magnitude >= catchingThreshold){

                        hand.AttachObject(gameObject, bestGrabType, attachmentFlags);

                        showHint = false;

                    }

                }

            }

 

            if(showHint){

                hand.ShowGrabHint();

            }

        }    //立钻哥哥:protected virtual void OnHandHoverBegin(Hand hand){}

 

        protected virtual void OnHandHoverEnd(Hand hand){

            hand.HideGrabHint();

        }

 

        protected virtual void HandHoverUpdate(Hand hand){

            GrabTypes startingGrabType = hand.GetGrabStarting();

            if(startingGrabType != GrabTypes.None){

                hand.AttachObject(gameObject, startingGrabType, attachmentFlags, attachmentOffset);

                hand.HideGrabHint();

            }

        }    //立钻哥哥:protected virtual void HandHoverUpdate(Hand hand){}

 

        protected virtual void OnAttachedToHand(Hand hand){

            //Debug.Log([SteamVR Interaction] Pickup:  + hand.GetGrabStarting().ToString());

            hadInterpolation = this.rigidbody.interpolation;

            attached = true;

            onPickUp.Invoke();

            hand.HoverLock(null);

            rigidbody.interpolation = RigidbodyInterpolation.None;

            velocityEstimator.BeginEstimatingVelocity();

 

            attachTime = Time.time;

            attachPosition = transform.position;

            attachRotation = transform.rotation;

        }    //立钻哥哥:protected virtual void OnAttachedToHand(Hand hand){}

 

        protected virtual void OnDetachedFromHand(Hand hand){

            attached = false;

            onDetachFromHand.Invoke();

            hand.HoverUnlock(null);

            rigidbody.interpolation = hadInterpolation;

 

            Vector3 velocity;

            Vector3 angularVelocity;

            GetReleaseVelocities(hand, out velocity, out angularVelocity);

 

            rigidbody.velocity = velocity;

            rigidbody.angularVelocity = angularVelocity;

        }    //立钻哥哥:protected virtual void OnDetachedFromHand(Hand hand){}

   

        public virtual void GetReleaseVelocities(Hand hand, out Vector3 velocity, out Vector3 angularVelocity){

            if(hand.noSteamVRFallbackCamera && releaseVelocityStyle != ReleaseStyle.NoChange){

                //only type that works with fallback hand is short estimation.(立钻哥哥:只有使用备用手的类型是short estimate.

                releaseVelocityStyle = ReleaseStyle.ShortEstimation;    

           }

 

            switch(releaseVelocityStyle){

               case ReleaseStyle.ShortEstimation:

                    velocityEstimator.FinishEstimatingVelocity();

                    velocity = velocityEstimator.GetVelocityEstimate();

                    angularVelocity = velocityEstimator.GetAngularVelocityEstimate();

                    break;

                case ReleaseStyle.AdvancedEstimation:

                    hand.GetEstimatedPeakVelocities(out velocity, out angularVelocity);

                    break;

                case ReleaseStyle.GetFromHand:

                    velocity = hand.GetTrackedObjectVelocity(releaseVelocityTimeOffset);

                    angularVelocity = hand.GetTrackedObjectAngularVelocity(releaseVelocityTimeOffset);

                   break;

                default:

                case ReleaseStyle.NoChange:

                    velocity = rigidbody.velocity;

                    angularVelocity = rigidbody.angularVelocity;

                    break;    

            }    //立钻哥哥:switch(releaseVelocityStyle){}

 

            if(releaseVelocityStyle != ReleaseStyle.NoChange){

                velocity *= scaleReleaseVelocity;

            }

        }    //立钻哥哥:public virtual void GetReleaseVelocities(){}

 

        protected virtual void HandAttachedUpdate(Hand hand){

            if(hand.IsGrabEnding(this.gameObject)){

                hand.DetachObject(gameObject, restoreOriginalParent);

 

                //Uncomment to detach ourselves late in the frame. This is so that any vehicles the player is attached to have a chance to finish updating themselves. If we detach now, our position could be behind what it will be at the end of the frame, and the object may appear to teleport behind the hand when the player releases it.(立钻哥哥:取消注释,以便在稍后的帧中分离我们自己。这样玩家所连接的任何物体都有机会完成自我更新。如果我们现在分离,我们的位置可能在帧后调用,当玩家释放这个物体时,它可能会出现在手的后面.

                //StartCoroutine(LateDetach(hand));    //立钻哥哥:稍后分离

            }

 

            if(onHeldUpdate != null){

                onHeldUpdate.Invoke(hand);

            }

        }    //立钻哥哥:protected virtual void HandAttachedUpdate(Hand hand){}

 

        protected virtual IEnumerator LateDetach(Hand hand){

            yield return new WaitForEndOfFrame();

 

            hand.DetachObject(gameObject, restoreOriginalParent);

        }    //立钻哥哥:protected virtual IEnumerator LateDetach(Hand hand){}

 

        protected virtual void OnHandFocusAcquired(Hand hand){

            gameObject.SetActive(true);

            velocityEstimator.BeginEstimatingVelocity();

        }    //立钻哥哥:protected virtual void OnHandFocusAcquired(Hand hand){}

 

        protected virtual void OnHandFocusLost(Hand hand){

           gameObject.SetActive(false);

            velocityEstimator.FinishEstimatingVelocity();

        }    //立钻哥哥:protected virtual void OnHandFocusLost(Hand hand){}

    }    //立钻哥哥:public class Throwable:MonoBehaviour{}

 

    public enum ReleaseStyle{

        NoChange,

        GetFromHand,

        ShortEstimation,

        AdvancedEstimation,

    }    //立钻哥哥:public enum ReleaseStyle{}

 

}    //立钻哥哥:namespace Valve.VR.InteractionSystem{}

 

++知识点01:ReleaseStyle

++++立钻哥哥:public ReleaseStyle releaseVelocityStyle = ReleaseStyle.GetFromHand;

public enum ReleaseStyle{

    NoChange,

    GetFromHand,

     ShortEstimation,

    AdvancedEstimation,

}

 

++知识点02:VelocityEstimator

++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\VelocityEstimator.cs

//Purpose: Estimates the velocity of an object based on change in position.(立钻哥哥:目的:根据物体位置的变化来估计物体的速度.

using UnityEngine;

using System.Collections;

namespace Valve.VR.InteractionSystem{

    public class VelocityEstimator : MonoBehaviour{

        public int velocityAverageFrames = 5;

        public int angularVelocityAverageFrames = 11;

        public bool estimateOnAwake = false;

        private Coroutine routine;

        private int sampleCount;

        private Vector3[] velocitySamples;

        private Vector3[] angularVelocitySamples;

 

        public void BeginEstimatingVelocity(){}

        public void FinishEstimatingVelocity(){}

        public Vector3 GetVelocityEstimate(){}

        public Vector3 GetAngularVelocityEstimate(){}

        public Vector3 GetAccelerationEstimate(){}

 

        void Awake(){}

        private IEnumerator EstimateVelocityCoroutine(){}

    }    //立钻哥哥:public class VelocityEstimator:MonoBehaviour{}

}    //立钻哥哥:namespace Valve.VR.InteractionSystem{}

++++[RequireComponent(typeof(VelocityEstimator))]

++++protected VelocityEstimator velocityEstimator;

++++velocityEstimator = GetComponent<VelocityEstimator>();

++++velocityEstimator.BeginEstimatingVelocity();

++++velocityEstimator.FinishEstimatingVelocity();

++++velocity = velocityEstimator.GetVelocityEstimate();

++++angularVelocity = velocityEstimator.GetAngularVelocityEstimate();

++++velocityEstimator.BeginEstimatingVelocity();

++++velocityEstimator.FinishEstimatingVelocity();

 

++知识点02:Hand

++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs

//Purpose: The hands used byt the player in the vr interaction system.(立钻哥哥:用途:VR交互系统中玩家使用的手.

using UnityEngine;

using System;

using System.Collections;

using System.Collections.Generic;

using System.Collections.ObjectModel;

using UnityEngine.Events;

using System.Threading;

 

namespace Valve.VR.InteractionSystem{

    //Links with an appropriate SteamVR controller and facilitates interactions with objects in the virtual world.(立钻哥哥:链接到适当的SteamVR控制器,并方便与虚拟世界中的对象进行交互.

    public class Hand : MonoBehaviour{

        //The flags used to determine how an object is attached to the hand.(立钻哥哥:用于确定对象如何附加到手的标志.

        [Flags]

        public enum AttachmentFlags{}

 

        public const AttachmentFlags defaultAttachmentFlags = AttachmentFlags.ParentToHand | AttachmentFlags.DetachOthers | AttachmentFlags.DetachFromOtherHand | AttachmentFlags.TurnOnKinematic | AttachmentFlags.SnapOnAttach;

        public Hand otherHand;

        public SteamVR_Input_Sources handType;

        public SteamVR_Behaviour_Pose trackedObject;

        public SteamVR_Action_Boolean grabPinchAction = SteamVR_Input.GetAction<SteamVR_Action_Boolean>(GrabPinch);

        public SteamVR_Action_Boolean grabGripAction = SteamVR_Input.GetAction<SteamVR_Action_Boolean>(GrabGrip);

        public SteamVR_Action_Vibration hapticAction = SteamVR_Input.GetAction<SteamVR_Action_Vibration>(Haptic);

        public SteamVR_Action_Boolean uiInteractAction = SteamVR_Input.GetAction<SteamVR_Action_Boolean>(InteractUI);

 

        public bool useHoverSphere = true;

        public Transform hoverSphereTransform;

        public float hoverSphereRadius = 0.05f;

        public LayerMask hoverLayerMask = -1;

        public float hoverUpdateInterval = 0.1f;

 

        public bool useControllerHoverComponent = true;

        public string controllerHoverComponent = tip;

        public float controllerHoverRadius = 0.075f;

 

        public bool useFingerJointHover = true;

        public SteamVR_Skeleton_JointIndexEnum fingerJointHover = SteamVR_Skeleton_JointIndexEnum.indexTip;

        public float fingerJointHoverRadius = 0.025f;

 

        [Tooltip(A transform on the hand to center attached objects on.(立钻哥哥:将手边的转换转换为将附加对象居中)]

        public Transform objectAttachmentPoint;

 

        public Camera noSteamVRFallbackCamera;

        public float noSteamVRFallbackMaxDistanceNoItem = 10.0f;

        public float noSteamVRFallbackMaxDistanceWithItem = 0.5f;

        private float noSteamVRFallbackInteractorDistance = -1.0f;

 

        public GameObject rendeModelPrefab;

        protected List<RenderModel> renderModels = new List<RenderModel>();

        protected RenderModel mainRenderModel;

        protected RenderModel hoverhighlightRenderModel;

 

        public bool showDebugText = false;

        public bool spewDebugText = false;

        public bool showDebugInteractable = false;

 

        public struct AttachedObject{

            public GameObject attachedObject;

            public Interactable interactable;

            public Rigidbody attachedRigidbody;

            public CollisionDetectionMode collisionDetectionMode;

            public bool attachedRigidbodyWasKinematic;

            public bool attachedRigidbodyUsedGravity;

            public GameObject originalParent;

            public bool isParentedToHand;

            public GrabTypes grabbedWithType;

            public AttachmentFlags attachmentFlags;

            public Vector3 initialRotationalOffset;

            public Quaternion initialRotationalOffset;

            public Transform attachedOffsetTransform;

            public Transform handAttachmentPointTransform;

            public Vector3 easeSourcePosition;

            public Quaternion easeSourceRotation;

            public float attachTime;

 

            public bool HasAttachFlag(AttachmentFlags flag){

                return (attachmentFlags & flag) == flag;

            }

        }    //立钻哥哥:public struct AttachedObject{}

 

        private List<AttachedObject> attachedObjects = new List<AttachedObject>();

        public ReadOnlyCollection<AttachedObject> AttachedObjects{}

        public bool hoverLocked{}

        private Interactable _hoveringInteractable;

        private TextMesh debugText;

        private int prevOverlappingColliders = 0;

        private const int ColliderArraySize = 16;

        private Collider[] overlappingColliders;

        private Player playerInstance;

        private GameObject applicationLostFocusObject;

        private SteamVR_Events.Action inputFocusAction;

        public bool isActive{}

        public bool isPoseValid{}

 

        //The Interactable object this Hand is currently hovering over.(立钻哥哥:这只手当前悬停的可交互对象.

        public Interactable hoveringInteractable{}

 

        //Active GameObject attached to this Hand.(立钻哥哥:活动的GameObject附在这只手上.

        public GameObject currentAttachedObject{}

 

        public AttachedObject? currentAttachedObjectInfo{}

        public SteamVR_Behaviour_Skeleton skeleton{}

        public void ShowController(bool permanent=false){}

        public void HideController(bool permanent=false){}

        public void ShowSkeleton(bool permanent=false){}

        public void HideSkeleton(bool permanent=false){}

        public bool HasSkeleton(){}

        public void Show(){}

        public void Hide(){}

        public void SetVisibility(bool visible){}

        public void SetSkeletonRangeOfMotion(EVRSkeletalMotionRange newRangeOfMotion, float blendOverSeconds=0.1f){}

        public void SetTemporarySkeletonRangeOfMotion(SkeletonMotionRangeChange temporaryRangeOfMotionChange, float blendOverSeconds=0.1f){}

        public void ResetTemporarySkeletonRangeOfMotion(float blendOverSeconds=0.1f){}

        public void SetAnimationState(int stateValue){}

        public void StopAnimation(){}

 

        //Attach a GameObject to this GameObject.(立钻哥哥:将GameObject(游戏物体)附加到这个GameObject(游戏物体)上.

        //[objectToAttach]: The GameObject to attach.(立钻哥哥:[objectToAttach]:要附加的GameObject.

        //[flags]: The flags to use for attaching the object.(立钻哥哥:[flags]:用于附加对象的标志.

        //[attachmentPoint]: Name of the GameObject in the hierarchy of this Hand which should act as the attachment point for this GameObject.(立钻哥哥:[attachmentPoint]:这只手的层次结构中GameObject的名称,它应该作为这个GameObject的连接点.

        public void AttachObject(GameObject objectToAttach, GrabType grabbedWithType, AttachmentFlags flags=defaultAttachmentFlags, Transform attachmentOffset=null){

            L348

            AttachedObject attachedObject = new AttachedObject();

            attachedObject.attachmentFlags = flags;

            attachedObject.attachedOffsetTransform = attachmentOffset;

            attachedObject.attachTime = Time.time;

            ....

            attachedObject.Add(attachedObject);

            UpdateHovering();

            objectToAttach.SendMessage(OnAttachedToHand, this, SendMessageOptions.DontRequireReceiver);

            L560(-L348=>212+1)

        }

 

        public bool ObjectIsAttached(GameObject go){}

        public void ForceHoverUnlock(){}

 

        //Detach this GameObject from the attached object stack of this Hand.(立钻哥哥:从这只手的附加对象堆栈中分离这个GameObject.

        //[objectToDetach]: The GameObject to detach from this Hand.(立钻哥哥:[objectToDetach]:要从这只手分离的GameObject.

        public void DetachObject(GameObject objectToDetach, bool restoreOriginalParent=true){

            L586

            int index = attachedObject.FindIndex(l=>l.attachedObject == objectToDetach);

            ... ...

            CleanUpAttachedObjectStack();

            L681(-L586=>95+1)

        }

 

        //Get the world velocity of the VR Hand.(立钻哥哥:得到VR手的世界速度

        public Vector3 GetTrackedObjectVelocity(float timeOffset=0){}

 

        //Get the world space angular velocity of the VR Hand.(立钻哥哥:得到VR手的世界空间角速度.

         public Vector3 GetTrackedObjectAngularVelocity(float timeOffset=0){}

 

        public void GetEstimatedPeakVelocities(out Vector3 velocity, out Vector3 angularVelocity){}

        private void CleanUpAttachedObjectStack(){}

        protected virtual void Awake(){}

        protected virtual void OnDestroy(){}

        protected virtual void OnTransformUpdated(SteamVR_Behaviour_Pose updatePose, SteamVR_Input_Sources updateSource){}

        protected virtual IEnumerator Start(){}

        protected virtual void UpdateHovering(){}

        protected virtual bool CheckHoveringForTransform(Vector3 hoverPosition, float hoverRadius, ref float closestDistance, ref Interactable closestInteractable, Color debugColor){}

        protected virtual void UpdateNoSteamVRFallback(){}

        private void UpdateDebugText(){}

        protected virtual void OnEnable(){}

        protected virtual void OnDisable(){}

        protected virtual void Update(){}

        public bool IsStilllHovering(Interactable interactable){}

        protected virtual void HandFollowUpdate(){}

        protected virtual void FixedUpdate(){}

 

        protected const float MaxVelocityChange = 10f;

        protected const float VelocityMagic = 6000f;

        protected const float AngularVelocityMagic = 50f;

        protected const float MaxAngularVelocityChange = 20f;

 

        protected void UpdateAttachedVelocity(AttachedObject attachedObjectInfo){}

        protected Vector3 TargetItemPosition(AttachedObject attachedObject){}

        protected Quaternion TargetItemRotation(AttachedObject attachedObject);

        protected bool GetUpdatedAttachedVelocites(AttachedObject attachedObjectInfo, out Vector3 velocityTarget, out Vector3 angularTarget){}

        protected virtual void OnInputFocus(bool hasFocus){}

        protected virtual void OnDrawGizmos(){}

        prvate void HandDebugLog(string msg){}

 

        //Continue to hover over this object indefinitely, whether or not the Hand moves out of its interaction trigger volume.(立钻哥哥:无论手是否移出交互触发范围,都将无限期地悬停在该对象上

        //[interactable]: The Interactable to hover over indefinitely.(立钻哥哥:[可交互的]:可以无限悬停的可交互的.

        public void HoverLock(Interactable interactable){}

 

        //Stop hovering over this object indefinitely.(立钻哥哥:停止无限期地悬停在这个物体上.

        //[interactable]: The hover-locked Interactable to stop hovering over indefinitely.(立钻哥哥:[可交互]:锁定悬停的可交互,以停止无限期地悬停.

        public void HoverUnlock(Interactable interactable){}

 

        public void TriggerHapticPulse(ushort microSecondsDuration){}

        public void TriggerHapticPulse(float duration, float frequency, float amplitude){}

        public void ShowGrabHint(){}

        public void HideGrabHint(){}

        public void ShowGrabHint(string text){}

        public GrabTypes GetGrabStarting(GrabTypes explicitType=GrabTypes.None){}

        public GrabTypes GetGrabEnding(GrabTypes explicitType=GrabTypes.None){}

        public bool IsGrabEnding(GameObject attachedObject){}

        public bool IsGrabbingWithType(GrabTypes type){}

        public bool IsGrabbingWithOppositeType(GrabTypes type){}

        public GrabTypes GetBestGrabbingType(){}

        public GrabTypes GetBestGrabbingType(GrabTypes preferred, bool forcePreference=false){}

        private void InitController(){}

        public void SetRenderModel(GameObject prefab){}

        public void SetHoverRenderModel(RenderModel hoverRenderModel){}

        public int GetDeviceIndex(){}

 

    }    //立钻哥哥:public class Hand:MonoBehaviour{}

 

    [System.Serializable]

    public class HandEvent : UnityEvent<Hand>();

 

        #if UNITY_EDITOR

            [UnityEditor.CustomEditor(typeof(Hand))]

            public class HandEditor : UnityEditor.Editor{

                //Custom Inspector GUI allows us to click from within the UI.(立钻哥哥:自定义检查器GUI允许我们从UI中单击.

                pulic override void OnInspectorGUI(){

                    DrawDefaultInspector();

                }

           }    //立钻哥哥:public class HandEditor:UnityEditor.Editor{}

        #endif

 

    }    //立钻哥哥:namespace Valve.VR.InteractionSystem{}

++++public Hand.AttachmentFlags attachmentFlags = Hand.AttachmentFlags.ParentToHand | Hand.AttachmentFlags.DetachFromOtherHand | Hand.AttachmentFlags.TurnOnKinematic;

++++public UnityEvent<Hand> onHeldUpdate;

++++protected virtual void OnHandHoverBegin(Hand hand){}

++++GrabTypes bestGrabType = hand.GetBestGrabbingType();

++++hand.AttachObject(gameObject, bestGrabType, attachmentFlags);

++++hand.ShowGrabHint();

++++protected virtual void OnHandHoverEnd(Hand hand){}

++++hand.HideGrabHint();

++++protected virtual void HandHoverUpdate(Hand hand){}

++++GrabTypes startingGrabType = hand.GetGrabStarting();

++++hand.AttachObject(gameObject, startingGrabType, attachmentFlags, attachmentOffset);

++++protected virtual void OnAttachedToHand(Hand hand){}

++++hand.HoverLock(null);

++++protected virtual void OnDetachedFromHand(Hand hand){}

++++hand.HoverUnlock(null);

++++GetReleaseVelocities(hand, out velocity, out angularVelocity);

++++public virtual void GetReleaseVelocities(Hand hand, out Vector3 velocity, out Vector3 angularVelocity){}

++++if(hand.noSteamVRFallbackCamera && releaseVelocityStyle!=ReleaseStyle.NoChange){}

++++hand.GetEstimatedPeakVelocities(out velocity, out angularVelocity);

++++velocity = hand.GetTrackedObjectVelocity(releaseVelocityTimeOffset);

++++angularVelocity = hand.GetTrackedObjectAngularVelocity(releaseVelocityTimeOffset);

++++protected virtual void HandAttachedUpdate(Hand hand){}

++++if(hand.IsGrabEnding(this.gameObject)){}

++++hand.DetachObject(gameObject, restoreOriginalParent);

++++onHeldUpdate.Invoke(hand);

++++protected virtual IEnumerator LateDetach(Hand hand){}

++++hand.DetachObject(gameObject, restoreOriginalParent);

++++protected virtual void OnHandFocusAcquired(Hand hand){}

++++protected virtual void OnHandFocusLost(Hand hand){}

 

++知识点03:UnityEvent

++++立钻哥哥:C:\Users\unity\AppData\Local\Temp\MetadataAsSource\4d44249b313b4410af4d2d6d08747e70\af4587a0fa6c4928911d2554e9cffda8\UnityEvent.cs

//程序集 UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null

//E:\E_ProgramFiles_02\UnitySetup64-2018.3.0f2\Unity\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll

using System.Reflection;

using UnityEngine.Scripting;

namespace UnityEngine.Events{

    //A zero argument persistent callback that can be saved with the Scene.(立钻哥哥:可以与场景一起保存的零参数持久回调.

    public class UnityEvent : UnityEventBase{

        //Constructor.(立钻哥哥:构造函数

        [RquiredByNativeCode]

        public UnityEvent();

 

        //Add a no persistent listener to the UnityEvent.(立钻哥哥:向UnityEvent添加一个no持久性侦听器.

        //[call]: Callback function.(立钻哥哥:[call]:回调函数

        public void AddListener(UnityAction call);

 

        //Invoke all registered callbacks(runtime and persistent).(立钻哥哥:调用所有已注册的回调(运行时和持久回调)

        public void Invoke();

 

        //Remove a non persistent listener from the UnityEvent.(立钻哥哥:从UnityEvent中删除一个非持久性侦听器.

        public void RemoveListener(UnityAction call);

 

        protected override MethodInfo FindMethod_Impl(string name, object targetObj);

    }    //立钻哥哥:public class UnityEvent:UnityEventBase{}

}    //立钻哥哥:namespace UnitEngine.Events{}

++++public UnityEvent onPickUp;

++++public UnityEvent onDetachFromHand;

++++public UnityEvent<Hand> onHeldUpdate;

 

++知识点04:RigidbodyInterpolation

++++立钻哥哥:C:\Users\unity\AppData\Local\Temp\MetadataAsSource\4d44249b313b4410af4d2d6d08747e70\7c712a196dab48d19d50417cc6836298\RigidbodyInterpolation.cs

//程序集 UnityEngine.PhysicsModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null

//E:\E_ProgramFiles_02\UnitySetup64-2018.3.0f2\Unity\Editor\Data\Managed\UnityEngine\UnityEngine.PhysicsModule.dll

namespace UnityEngine{

    //Rigidbody interpolation mode.(立钻哥哥:Rigidbody插值模式.

    public enum RigidbodyInterpolation{

        //No Interpolation.(立钻哥哥:没有插值.

        None = 0,

 

        //Interpolation will always lag a little bit behind but can be smoother than extrapolation.(立钻哥哥:插值总是有点落后,但可以比外推平滑.

        Interpolate = 1,

 

        //Extrapolation will predict the position of the rigidbody based on the current velocity.(立钻哥哥:外推法将根据电流速度来预测刚体的位置.

        Extrapolate = 2

    }    //立钻哥哥:public enum RigidbodyInterpolation{}

}    //立钻哥哥:namespace UnityEngine{}

++++protected RigidbodyInterpolation hadInterpolation = RigidbodyInterpolation.None;

++++rigidbody.interpolation = RigidbodyInterpolation.None;

 

++知识点05:SteamVR_Utils.GetLossyScale

++++立钻哥哥:\Assets\SteamVR\Scripts\SteamVR_Utils.cs

public static float GetLossyScale(Transform forTransform){

    float scale = 1f;

    while(forTransform != null && forTransform.parent != null){

        forTransform = forTransform.parent;

        scale *= forTransform.localScale.x;

    }

    return scale;

}    //立钻哥哥:public static float GetLossyScale(){}

++++float catchingThreshold = catchingSpeedThreshold * SteamVR_Utils.GetLossyScale(Player.instance.trackingOriginTransform);

 

++知识点06:hand.GetBestGrabbingType

++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs

public GrabTypes GetBestGrabbingType(){

    return GetBestGrabbingType(GrabTypes.None);

}    //立钻哥哥:public GrabTypes GetBestGrabbingType(){}

++++GrabTypes bestGrabType = hand.GetBestGrabbingType();

 

++知识点07:GrabTypes

++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\GrabTypes.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace Valve.VR.InteractionSystem{

    public enum GrabTypes{

        None,

        Trigger,

        Pinch,

        Grip,

        Scripted,

    }    //立钻哥哥:public enum GrabTypes{}

}    //立钻哥哥:namespace Valve.VR.InteractionSystem{}

++++GrabTypes bestGrabType = hand.GetBestGrabbingType();

++++if(bestGrabType != GrabType.None){}

++++GrabTypes startingGrabType = hand.GetGrabStarting();

++++if(startingGrabType != GrabType.None){}

 

++知识点08:hand.AttachObject

++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs

//Attach a GameObject to this GameObject.(立钻哥哥:将GameObject(游戏物体)附加到这个GameObject(游戏物体)上

//[objectToAttach]: The GameObject to attach.(立钻哥哥:[objectToAttach]:要附加的GameObject.

//[flags]: The flags to use for attaching the object.(立钻哥哥:[flags]:用于附加对象的标志.

//[attachmentPoint]: Name of the GameObject in the hierarchy of this Hand which should act as the attachment point for this GameObject.(立钻哥哥:[attachmentPoint]:这只手的层次结构中GameObject的名称,它应该作为这个GameObject的连接点.

public void AttachObject(GameObject objectToAttach, GrabTypes grabbedWithType, AttachmentFlags flags=defaultAttachmentFlags, Transform attachmentOffset=null){

    AttachedObject attachedObject = new AttachedObject();

    attachedObject.attachmentFlags = flags;

    attachedObject.attachedOffsetTransform = attachmentOffset;

    attachedObject.attachTime = Time.time;

 

    if(flags == 0){

        flags = defaultAttachmentFlags;

    }

 

    //Make sure top object on stack is non-null.(立钻哥哥:确保堆栈上的top对象非空.

    CleanUpAttachedObjectStack();

 

    //Detach the object if it is already attached so that it can get re-attached at the top of the stack.(立钻哥哥:如果对象已经附加,则将其分离,以便可以在堆栈顶部重新附加.

    if(ObjectIsAttached(objectToAttach)){

        DetachObject(objectToAttach);

    }

 

    //Detach from the other hand if requested.(立钻哥哥:如果需要,从另一只手断开.

    if(attachedObject.HasAttachFlag(AttachmentFlags.DetachFromOtherHand)){

        if(otherHand != null){

            otherHand.DetachObject(objectToAttach);

        }

    }

 

    ... ...

 

    UpdateHovering();

 

    objectToAttach.SendMessage(OnAttachedToHand, this, SendMessageOptions.DontRequireReceiver);

}    //立钻哥哥:public void AttachObject(){}

++++hand.AttachObject(gameObject, bestGrabType, attachmentFlags);

++++hand.AttachObject(gameObject, startingGrabType, attachmentFlags, attachmentOffset);

 

++知识点09:hand.ShowGrabHint

++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs

public void ShowGrabHint(){

    ControllerButtonHints.ShowButtonHint(this, grabGripAction);

}    //立钻哥哥:public void ShowGrabHint(){}

++++hand.ShowGrabHint();

 

++知识点10:hand.HideGrabHint

++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs

public void HideGrabHint(){

    ControllerButtonHints.HideButtonHint(this, grabGripAction);

}    //立钻哥哥:public void HideGrabHint(){}

++++hand.HideGrabHint();

 

++知识点11:hand.HoverLock

++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs

//Continue to hover over this object indefinitely, whether or not the Hand moves out of its interaction trigger volume.(立钻哥哥:无论手是否移出交互触发范围,都将无限期地悬停在该对象上

//[interactable]: The Interactable to hover over indefinitely.(立钻哥哥:[interactable]:可以无限悬停的可交互的.

public void HoverLock(Interactable interactable){

    hoverLocked = true;

    hoveringInteractable = interactable;

}    //立钻哥哥:public void HoverLock(){}

++++hand.HoverLock(null);

 

++知识点12:velocityEstimator.BeginEstimatingVelocity

++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\VelocityEstimator.cs

public void BeginEstimatingVelocity(){

    FinishEstimatingVelocity();

    routine = StartCoroutine(EstimateVelocityCoroutine());

}    //立钻哥哥:public void BeginEstimatingVelocity(){}

++++velocityEstimator.BeginEstimatingVelocity();

 

++知识点13:hand.HoverUnlock

++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs

//Stop hovering over this object indefinitely.(立钻哥哥:停止无限期地悬停在这个物体上.

//[interactable]: The hover-locked Interactable to stop hovering over indefinitely.(立钻哥哥:[interactable]:锁定悬停的可交互,以停止无限期地悬停

public void HoverUnlock(Interactable interactable){

    if(hoveringInteractable == interactable){

        hoverLocked = false;

    }

}    //立钻哥哥:public void HoverUnlock(){}

++++hand.HoverUnlock(null);

 

++知识点14:velocityEstimator.FinishEstimatingVelocity

++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\VelocityEstimator.cs

public void FinishEstimatingVelocity(){

    if(routine != null){

        StopCoroutine(routine);

        routine = null;

    }

}    //立钻哥哥:public void FinishEstimatingVelocity(){}

++++velocityEstimator.FinishEstimatingVelocity();

 

++知识点15:velocityEstimator.GetVelocityEstimate

++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\VelocityEstimator.cs

public Vector3 GetVelocityEstimate(){

    Vector3 velocity = Vector3.zero;

    int velocitySampleCount = Mathf.Min(sampleCount, velocitySamples.Length);

    if(velocitySampleCount != 0){

        for(int i = 0;  i < velocitySampleCount;  i++){

            velocity += velocitySamples[i];

        }

        velocity *= (1.0f / velocitySampleCount);

    }

    return velocity;

}    //立钻哥哥:public Vector3 GetVelocityEstimate(){}

++++velocity = velocityEstimator.GetVelocityEstimate();

 

++知识点16:velocityEstimator.GetAngularVelocityEstimate

++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\VelocityEstimator.cs

public Vector3 GetAngularVelocityEstimate(){

    Vector3 angularVelocity = Vector3.zero;

    int angularVelocitySampleCount = Mathf.Min(sampleCount, angularVelocitySamples.Length);

    if(angularVelocitySampleCount != 0){

        for(int i = 0;  i < angularVelocitySampleCount;  i++){

            angularVelocity += angularVelocitySamples[i];

        }

        angularVelocity *= (1.0f / angularVelocitySampleCount);

    }

    return angularVelocity;

}    //立钻哥哥:public Vector3 GetAngularVelocityEstimate(){}

++++angularVelocity = velocityEstimator.GetAngularVelocityEstimate();

 

++知识点17:hand.GetEstimatedPeakVelocites

++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs

public void GetEstimatedPeakVelocites(out Vector3 velocity, out Vector3 angularVelocity){

    trackedObject.GetEstimatedPeakVelocities(out velocity, out angularVelocity);

    velocity = Player.instance.trackingOriginTransform.TransformVector(velocity);

    angularVelocity = Player.instance.trackingOriginTransform.TransformDirection(angularVelocity);

}    //立钻哥哥:public void GetEstimatedPeakVelocites(){}

++++hand.GetEstimatedPeakVelocities(out velocity, out angularVelocity);

 

++知识点18:hand.GetTrackedObjectVelocity

++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\VelocityEstimator.cs

//Get the world velocity of the VR Hand.(立钻哥哥:得到VR手的世界速度.

public Vector3 GetTrackedObjectVelocity(float timeOffset=0){

    if(trackedObject == null){

        Vector3 velocityTarget, angularTarget;

        GetUpdatedAttachedVelocities(currentAttachedObjectInfo.Value, out velocityTarget, out angularTarget);

        return velocityTarget;

    }

 

    if(isActive){

        if(timeOffset == 0){

            return Player.instance.trackingOriginTransform.TransformVector(trackedObject.GetVelocity());

        }else{

            Vector3 velocity;

            Vector3 angularVelocity;

            trackedObject.GetVelocitiesAtTimeOffset(timeOffset, out velocity, out angularVelocity);

            return Player.instance.trackingOriginTransform.TransformVector(velocity);

        }

    }

 

    return Vector3.zero;

}    //立钻哥哥:public Vector3 GetTrackedObjectVelocity(){}

++++velocity = hand.GetTrackedObjectVelocity(releaseVelocityTimeOffset);

 

++知识点19:hand.GetTrackedObjectAngularVelocity

++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs

//Get the world space angular velocity of the VR Hand.(立钻哥哥:得到VR手的世界空间角速度.

public Vector3 GetTrackedObjectAngularVelocity(float timeOffset=0){

    if(trackedObject == null){

        Vector3 velocityTarget, angularTarget;

        GetUpdateAttachedVelocities(currentAttachedObjectInfo.Value, out velocityTarget, out angularTarget);

        return angularTarget;

    }

 

    if(isActive){

        if(timeOffset == 0){

            return Player.instance.trackingOriginTransform.TransformDirection(trackedObject.GetAngularVelocity());

        }else{

            Vector3 velocity;

            Vector3 angularVelocity;

 

            trackedObject.GetVelocitiesAtTimeOffset(timeOffset, out velocity, out angularVelocity);

            return Player.instance.trackingOriginTransform.TransformDirection(angularVelocity);

        }

    }

 

    return Vector3.zero;

}    //立钻哥哥:public Vector3 GetTrackedObjectAngularVelocity(){}

++++angularVelocity = hand.GetTrackedObjectAngularVelocity(releaseVelocityTimeOffset);

 

++知识点20:hand.IsGrabEnding

++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs

public bool IsGrabEnding(GameObject attachedObject){

    for(int attachedObjectIndex=0;  attachedObjectIndex < attachedObjects.Count;  attachedObjectIndex++){

        if(attachedObjects[attachedObjectIndex].attachedObject==attachedObject){

            return IsGrabbingWithType(attachedObjects[attachedObjectIndex].grabbedWithType)==false;

        }

    }

    return false;

}    //立钻哥哥:public bool IsGrabEnding(){}

++++if(hand.IsGrabEnding(this.gameObject)){}

 

++知识点21:hand.DetachObject

++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs

//Detach this GameObject from the attached object stack of this Hand.(立钻哥哥:从这只手的附加对象堆栈中分离这个GameObject.

//[objectToDetach]: The GameObject to detach from this Hand.(立钻哥哥:[objectToDetach]:要从这只手分离的GameObject.

public void DetachObject(GameObject objectToDetach, bool restoreOriginalParent=true){

    int index = attachedObjects.FindIndex(l=>l.attachedObject==objectToDetach);

    if(index != -1){

        GameObject prevTopObject = currentAttachedObject;

        ... ...

    }

 

    attachedObjects.RemoveAt(index);

    CleanUpAttachedObjectStack();

    GameObject newTopObject = currentAttachedObject;

    hoverLocked = false;

    ... ...

}    //立钻哥哥:public void DetachObject(){}

++++hand.DetachObject(gameObject, restoreOriginalParent);

 

 

 

 

 

++8、添加“Skeleton Poser”骨架姿态组件

++++立钻哥哥:将“SteamVR_Skeleton_Poser”组件添加到带有“Interactable”的GameObject(游戏物体)中,并在与之交互时摆出我们想要的手的样子

++++[Pose]类型的动作表示三维空间中的位置和旋转,一般用于跟踪VR控制器;(在Unity中对应类为“SteamVR_Action_Pose”);

++++[Skeleton]类型的动作能够获取用户在持握手柄控制器时的手指关节数据,通过返回数据,结合手部渲染模型,能够更加真实的呈现手部在虚拟世界的姿态,虽然不及像“Leap Motion”等设备获取手指输入那样精确,但是足以获得良好的沉浸感;(在Unity中对应类为:“SteamVR_Action_Skeleton”);

++++[SteamVR_Behaviour_Pose]:姿态行为组件(SteamVR_Behaviour_Pose)是跟踪对象的方向;将其添加到GameObject(游戏对象)中,以自动设置转换的位置和旋转,以匹配我们跟踪的对象(通常是控制器);它还包含速度数据和各种辅助函数用于常用的定向函数

++++[SteamVR_Behaviour_Skeleton]:使用“SteamVR骨骼输入”(SteamVR_Behaviour_Skeleton)来帮助我们猜测每个关节的位置;根据当前使用的控制器和跟踪系统的不同,精度也有所不同;这也可以将GameObject内联到控制器中;所以我们不需要在同一个物体上有一个姿态和一个骨架行为

++++[Skeleton Input(骨骼输入)]:内联的“Knuckles Valve”已经发布了一个系统,以获得骨骼手数据独立于我们使用的控制器;有些控制器对单个关节的手部跟踪数据有很高的保真度,有些控制器只有我们用于近似关节数据的按钮;【With Controller(带控制器)】:我们的最佳近似值,在现实世界中,我们手中的关节是围绕在控制器周围的;【Without Controller(不需要控制器)】:基于“控制器”数据,我们估计打开或关闭我们的手,当我们试图持平或握拳紧握手

++++[Skeleton Poser(骨骼姿态)]:SteamVR_Skeleton_Poser”组件脚本被设计成独立于“SteamVR交互系统”运行,并且可以添加到我们自己的系统中;这个组件将在后面补充比较详细的描述,请继续往下查阅吧!(官方Demo链接:https://valvesoftware.github.io/steamvr_unity_plugin/tutorials/Skeleton-Poser.html

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第15张图片

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第16张图片

++++\Assets\SteamVR\Input\SteamVR_Skeleton_Poser.cs

using System;

using System.Collections;

using UnityEngine;

using Valve.VR;

using System.Collectons.Generic;

using System.Linq;

 

namespace Valve.VR{

    public class SteamVR_Skeleton_Poser : MonoBehaviour{

        public GameObject previewLeftHandPrefab;

        public GameObject previewRightHandPrefab;

 

        public SteamVR_Skeleton_Pose skeletonMainPose;

        public List<SteamVR_Skeleton_Pose> skeletonAdditionalPose = new List<SteamVR_Skeleton_Pose>();

 

        [SerializeField]

        protected bool showLeftPreview = false;

        protected bool showRightPreview = true;

        protected GameObejct previewLeftInstance;

        protected GameObject previewRightInstance;

        protected int previewPoseSelection = 0;

 

        public int blendPoseCount{}

 

        public List<PoseBlendingBehaviour> blendingBehaviours = new List<PoseBlendingBehaviour>();

        public SteamVR_Skeleton_PoseSnapshot blendedSnapShotL;

        public SteamVR_Skeleton_PoseSnapshot blendedSnapShortR;

        private SkeletonBlendablePose[] blendPoses;

        private int boneCount;

        private bool poseUpdateThisFrame;

        public float scale;

 

        protected void Awake(){}

 

        //Set the blending value of a blendingBehaviour. Works best on Manual type behaviours.(立钻哥哥:设置混合行为的混合值。最适用于手动类型的行为.

        public void SetBlendingBehaviourValue(string behaviourName, float value){}

 

        //Get the blending value of a blendingBehaviour.(立钻哥哥:获取混合行为的混合值

        public float GetBlendingBehaviourValue(string behaviourName){}

 

        //Enable or disable a blending behaviour.(立钻哥哥:启用或禁用混合行为.

        public void SetBlendingBehaviourEnabled(string behaviourName, bool value){}

 

        //Check if a blending behaviour is enabled.(立钻哥哥:检查是否启用了混合行为

        public bool GetBlendingBehaviourEnabled(string behaviourName){}

 

        //Get a blending behaviour by name.(立钻哥哥:通过名称获得混合行为

        public PoseBlendingBehaviour GetBlendingBehaviour(string behaviourName){}

 

        public SteamVR_Skeleton_Pose GetPoseByIndex(int index){}

        private SteamVR_Skeleton_PoseSnapshot GetHandSnapshot(SteamVR_Input_Source inputSource){}

 

        //Retrieve the final animated pose, to be applied to a hand skeleton.(立钻哥哥:检索要应用于手部骨骼的最终动画姿势.

        public SteamVR_Skeleton_PoseSnapshot GetBlendedPose(SteamVR_Action_Skeleton skeletonAction, SteamVR_Input_Sources handType){}

        public SteamVR_Skeleton_PoseSnapshot GetBlendedPose(SteamVR_Behaviour_Skeleton skeletonBehaviour){}

 

        //Updates all pose animation and blending. Can be called from different places without performance concerns, as it will only let itself run once per frame.(立钻哥哥:更新所有的姿态动画和混合。可以从不同的地方调用,而不需要考虑性能问题,因为它只允许自己在每帧中运行一次.

        public void UpdatePose(SteamVR_Action_Skeleton skeletonAction, SteamVR_Input_Sources inputSource){}

 

        protected void ApplyBlenderBehaviours(SteamVR_Action_Skeleton skeletonAction, SteamVR_Input_Sources inputSource, SteamVR_Skeleton_PoseSnapshot snapshot){}

 

        protected void LateUpdate(){}

 

        //Weighted average of n vector2s.(立钻哥哥:n个向量的加权平均

        public Vector3 BlendVectors(Vector3[] vectors, float[] weights){}

 

        //Weighted average of n quaternions.(立钻哥哥:n个四元数的加权平均

        protected Quaternion BlendQuaternions(Quaternion[] quaternions, float[] weights){}

    

        //A SkeletonBlendablePose holds a reference to a Skeleton_Pose scriptableObject, and also contains some helper functions. Also handles pose-specific animation like additive finger motion.(立钻哥哥:SkeletonBlendablePose持有对Skeleton_Pose脚本对象的引用,并且还包含一些帮助函数。还处理特定位置的动画,如添加手指运动.

        public class SkeletonBlendablePose{

            public SteamVR_Skeleton_Pose pose;

            public SteamVR_Skeleton_PoseSnapshot snapshotR;

            public SteamVR_Skeleton_PoseSnapshot snapshotL;

 

            //Get the snapshot of this pose with effects such as additive finger animation applied.(立钻哥哥:使用添加手指动画等效果获取此姿态的快照.

            public SteamVR_Skeleton_PoseSnapshot GetHandSnapshot(SteamVR_Input_Sources inputSource){}

 

            public void UpdateAdditiveAnimation(SteamVR_Action_Skeleton skeletonAction, SteamVR_Input_Sources inputSource){}

 

            //Init based on an existing Skeleton_Pose.(立钻哥哥:初始化基于一个现有的骨架姿态.

            public SkeletonBlendablePose(SteamVR_Skeleton_Pose p){}

 

            //Copy tht base pose into the snapshots.(立钻哥哥:将基本姿势复制到快照中

            public void PoseToSnapshots(){}

 

            public SkeletonBlendablePose(){}

 

        }    //立钻哥哥:public class SkeletonBlendablePose{}   

 

        //A filter applied to the base pose. Blends to a secondary pose by a certain weight. Can be masked per-finger.(立钻哥哥:用于基本位姿的滤波器。通过一定的重量调整到第二个姿势。每个手指都可以蒙面.

        [System.Serializable]

        public class PoseBlendingBehaviour{

            public string name;

            public bool enabled = true;

            public float influence = 1;

            public int pose = 1;

            public float value = 0;

            public SteamVR_Action_Single action_single;

            public SteamVR_Action_Boolean action_bool;

            public float smoothingSpeed = 0;

            public BlenderTypes type;

            public bool useMask;

            public SteamVR_Skeleton_HandMask mask = new SteamVR_Skeleton_HandMask();

            public bool previewEnabled;

 

            //Performs smoothing based on deltaTime parameter.(立钻哥哥:基于deltaTime参数执行平滑.

            public void Update(){}

 

            //Apply blending this behaviours pose to an existing snapshot.(立钻哥哥:将此行为的姿态混合应用于现有快照.

            public void ApplyBlending(SteamVR_Skeleton_PoseSnapshot snapshot, SkeletonBlendablePose[] blendPose, SteamVR_Input_Sources inputSource){}

 

            public PoseBlendingBehaviour(){}

 

            public enum BlenderTypes{

                Manual,

                AnalogAction,

                BooleanAction

            }    //立钻哥哥:public enum BlenderTypes{}

 

        }    //立钻哥哥:public class PoseBlendingBehaviour{}

 

    }    //立钻哥哥:public class SteamVR_Skeleton_Poser:MonoBehaviour{}

 

 

    //PoseSnapshots hold a skeleton pose for one hand, as well as storing which hand they contain. They have several functions for combining BlendablePoses.(立钻哥哥:PoseSnapshots为一只手保留一个骨架的姿势,同时也保存了它们包含的那只手。他们有几个功能,以结合可调和的姿势.

    public class SteamVR_Skeleton_PoseSnapshot{

        public Vector3 position;

        public Quaternion rotation;

        public Vector3[] bonePositions;

        public Quaternion[] boneRotations;

 

        public SteamVR_Skeleton_PoseSnapshot(int boneCount, SteamVR_Input_Sources source){}

 

        //Perform a deep copy from one poseSnapshot to another.(立钻哥哥:执行从一个位置到另一个位置的深度复制.

        public void CopyFrom(SteamVR_Skeleton_PoseSnapshot source){}

 

    }    //立钻哥哥:public class SteamVR_Skeleton_PoseSnapshot{}

 

    //Simple mask for fingers.(立钻哥哥:简单的手指遮罩

    [System.Serializable]

    public class SteamVR_Skeleton_HandMask{

        public bool palm;

        public bool thumb;

        public bool index;

        public bool middle;

        public bool ring;

        public bool pinky;

        public boo[] values = new bool[6];

 

        public void SetFinger(int i, bool value){}

        public bool GetFinger(int i){}

 

        public SteamVR_Skeleton_HandMask(){}

 

        //All elements on.(立钻哥哥:所有的元素.

        public void Reset(){}

 

        protected void Apply(){}

 

        public static readonly SteamVR_Skeleton_HandMask fullMask = new SteamVR_Skeleton_HandMask();

 

    }    //立钻哥哥:public class SteamVR_Skeleton_HandMask{}

 

}    //立钻哥哥:namespace Valve.VR{}

 

++SteamVR_Skeleton_Poser相关的类

++++立钻哥哥SteamVR_Skeleton_Poser”相关的平级类有:“public class SteamVR_Skeleton_PoseSnapshot{}”和“public class SteamVR_Skeleton_HandMask{}”,注意:这两个类没有继承MonoBehaviour,应该是一个数据类

++++“public class SteamVR_Skeleton_Poser:MonoBehaviour{}”内嵌的类有:“public class SkeletonBlendablePose{}”和“public class PoseBlendingBehaviour{}”,注意:这没有继承MonoBehaviour,应该是一个数据类

namespace Valve.VR{

    public class SteamVR_Skeleton_Poser : MonoBehaviour{

        //A SkeletonBlendablePose holds a reference to a Skeleton_Pose scriptableObject, and also contains some helper functions. Also handles pose-specific animation like additive finger motion.(立钻哥哥:SkeletonBlendablePose持有对Skeleton_Pose脚本对象的引用,并且还包含一些帮助函数。还处理特定位置的动画,如添加手指运动.

        public class SkeletonBlendablePose{

        }    //立钻哥哥:public class SkeletonBlendablePose{}   

 

        //A filter applied to the base pose. Blends to a secondary pose by a certain weight. Can be masked per-finger.(立钻哥哥:用于基本位姿的滤波器。通过一定的重量调整到第二个姿势。每个手指都可以蒙面.

        [System.Serializable]

        public class PoseBlendingBehaviour{

        }    //立钻哥哥:public class PoseBlendingBehaviour{}

 

    }    //立钻哥哥:public class SteamVR_Skeleton_Poser:MonoBehaviour{}

 

    //PoseSnapshots hold a skeleton pose for one hand, as well as storing which hand they contain. They have several functions for combining BlendablePoses.(立钻哥哥:PoseSnapshots为一只手保留一个骨架的姿势,同时也保存了它们包含的那只手。他们有几个功能,以结合可调和的姿势.

    public class SteamVR_Skeleton_PoseSnapshot{

    }    //立钻哥哥:public class SteamVR_Skeleton_PoseSnapshot{}

 

    //Simple mask for fingers.(立钻哥哥:简单的手指遮罩

    [System.Serializable]

    public class SteamVR_Skeleton_HandMask{

    }    //立钻哥哥:public class SteamVR_Skeleton_HandMask{}

 

}    //立钻哥哥:namespace Valve.VR{}

 

++知识点01:SteamVR_Skeleton_Poser

++++立钻哥哥SteamVR_Skeleton_Poser”组件是在“v2.2RC1”版本中增加的,简化了创建姿势,很容易与“SteamVR骨骼系统”兼容,例如,检查“交互系统”场景中的对象,或者将组件添加到“Interactable”中

++++SteamVR_Skeleton_Poser”脚本被设计成独立于“SteamVR交互系统”,并且可以添加到我们自己的系统中

++++我们可以将“SteamVR_Skeleton_Poser”组件添加到带有“Interactable”的GameObject(游戏物体)中,并在与之交互时摆出我们想要的手的样子;(You can then add the SteamVR_Skeleton_Poser component to a GameObject with an Interactable and pose how you want the hand to look when interacting with it.

namespace Valve.VR{

    public class SteamVR_Skeleton_Poser : MonoBehaviour{

        public class SkeletonBlendablePose{}

        public class PoseBlendingBehaviour{}

    }

}

++++\Assets\SteamVR\InteractionSystem\Core\Scripts\Interactable.cs

public class Interactable : MonoBehaviour{

++++public SteamVR_Skeleton_Poser skeletonPoser;

++++skeletonPoser = GetComponent<SteamVR_Skeleton_Poser>();

++++if(skeletonPoser != null){}

++++if(skeletonPoser != null && hand.skeleton != null){}

++++hand.skeleton.BlendToPoser(skeletonPoser, blendToPoseTime);

}    //立钻哥哥:public class Interactable : MonoBehaviour{}

++++-\Assets\SteamVR\Input\SteamVR_Behaviour_Skeleton.cs

public class SteamVR_Behaviour_Skeleton : MonoBehaviour{

++++SteamVR_Skeleton_Poser blendPoser;

++++if(blendPoser != null && skeletonBlend < 1){}

++++blendSnapshot = blendPoser.GetBlendedPose(this);

++++blendPoser = poser;(public void BlendToPoser(SteamVR_Skeleton_Poser poser, float overTime=0.1f){})

++++if(blendPoser != null){}

++++SteamVR_Skeleton_Pose_Hand minPose = blendPoser.skeletonMainPose.GetHand(inputSource);

++++public void BlendToPoser(SteamVR_Skeleton_Poser poser, float overTime = 0.1f){}

}    //立钻哥哥:public class SteamVR_Behaviour_Skeleton:MonoBehaviour{}

++++\Assets\SteamVR\Input\Editor\SteamVR_Skeleton_PoserEditor.cs

[CustomEditor(typeof(SteamVR_Skeleton_Poser))]

public class SteamVR_Skeleton_PoserEditor : Editor{

++++private SteamVR_Skeleton_Poser poser;

++++poser = (SteamVR_Skeleton_Poser)target;

++++preview.transform.parent = poser.transform;

++++handData.position = thisSkeleton.transform.InverseTransformPoint(poser.transform.position);

++++EditorUtility.SetDirty(poser.skeletonMainPose);

++++poser.poseNames = new string[skeletonAdditionalPosesProperty.arraySize + 1];

++++poser.poseNames[i] = skeletonMainPoseProperty.objectReferenceValue = null ? [not set] : skeletonMainPoseProperty.objectReferenceValue.name +  (MAIN);

++++poser.poseNames[i] = skeletonAdditionalPosesProperty.GetArrayElementAtIndex(i-1).objectReferenceValue == null ? [not set] : skeletonAdditionalPosesProperty.GetArrayElementAtIndex(i - 1).objectReferenceValue.name;

++++int poseSelected = GUILayout.Toolbar(activePoseIndex, poser.poseNames);

++++blenderPose.intValue = EditorGUILayout.Popup(Pose, blenderPose.intValue, poser.poseNames);

++++poser.blendingBehaviours[i].mask.Reset();

++++poser = (SteamVR_Skeleton_Poser)target;

++++if(blenderType.intValue == (int)SteamVR_Skeleton_Poser.PoseBlendingBehaviour.BlenderType.Manual){}

++++if(blenderType.intValue == (int)SteamVR_Skeleton_Poser.PoseBlendingBehaviour.BlenderTypes.AnalogAction){}

++++if(blenderType.intValue == (int)SteamVR_Skeleton_Poser.PoseBlendingBehaviour.BlenderTypes.BooleanAction){}

}    //立钻哥哥:public class SteamVR_Skeleton_PoserEditor:Editor{}

++++public class SteamVR_Skeleton_Poser:MonoBehaviour{}

 

++知识点02:SKeletonBlendablePose

++++立钻哥哥A SkeletonBlendablePose holds a reference to a Skeleton_Pose scriptableObject, and also contains some helper functions. Also handles pose-specific animation like additive finger motion.SkeletonBlendablePose持有对Skeleton_Pose脚本对象的引用,并且还包含一些帮助函数。还处理特定位置的动画,如添加手指运动

namespace Valve.VR{

    public class SteamVR_Skeleton_Poser : MonoBehaviour{

        public class SkeletonBlendablePose{

            public SteamVR_Skeleton_Pose pose;

            public SteamVR_Skeleton_PoseSnapshot snapshotR;

            public SteamVR_Skeleton_PoseSnapshot snapshotL;

 

            public SteamVR_Skeleton_PoseSnapshot GetHandSnapshot(SteamVR_Input_Sources inputSource){}

            public void UpdateAdditiveAnimation(SteamVR_Action_Skeleton skeletonAction, SteamVR_Input_Sources inputSource){}

            public SkeletonBlendablePose(SteamVR_Skeleton_Pose p){}

            public void PoseToSnapshots(){}

            public SkeletonBlendlePose(){}

        }    //立钻哥哥:public class SkeletonBlendablePose{}

    }    //立钻哥哥:public class SteamVR_Skeleton_Poser:MonoBehaviour{}

}     //立钻哥哥:namespace Valve.VR{}

++++\Assets\SteamVR\Input\SteamVR_Skeleton_Poser.cs

public class SteamVR_Skeleton_Poser:MonoBehaviour{

++++private SkeletonBlendablePose[] blendPoses;

++++blendPoses = new SkeletonBlendablePose[skeletonAdditionalPoses.Count + 1];

++++blendPoses[i] = new SkeletonBlendablePose(GetPoseByIndex(i));

++++blendPoses[i].PoseToSnapshots();

++++blendPoses[0].UpdateAdditiveAnimation(skeletonAction, inputSource);

++++snap.CopyFrom(blendPoses[0].GetHandSnapshot(inputSource));

++++blendPoses[blendingBehaviours[behaviourIndex].pose].UpdateAdditiveAnimation(skeletonAction, inputSource);

++++blendingBehaviours[behaviourIndex].ApplyBlending(snapshot, blendPoses, inputSource);

++++public void ApplyBlending(SteamVR_Skeleton_PoseSnapshot snapshot, SkeletonBlendablePose[] blendPoses, SteamVR_Input_Sources inputSource){}

++++SteamVR_Skeleton_PoseSnapshot targetSnapshot = blendPoses[pose].GetHandSnapshot(inputSource);

++++public int blendPoseCount{  get  {  return blendPoses.Length;  }  }

++++public SkeletonBlendablePose(SteamVR_Skeleton_Pose p){}

++++public SkeletonBlendablePose(){}

}    //立钻哥哥:public class SteamVR_Skeleton_Poser:MonoBehaviour{}

++++public class SkeletonBlendablePose{}

 

++知识点03:PoseBlendingBehaviour

++++立钻哥哥A filter applied to the base pose. Blends to a secondary pose by a certain weight. Can be masked per-finger.用于基本位姿的滤波器。通过一定的重量调整到第二个姿势。每个手指都可以蒙面

[System.Serializable]

public class PoseBlendingBehaviour{

    public string name;

    public bool enabled = true;

    public float influence = 1;

    public int pose = 1;

    public float value = 0;

    public SteamVR_Action_Single action_single;

    public SteamVR_Action_Boolean action_bool;

    public float smoothingSpeed = 0;

    public BlenderType type;

    public bool useMask;

    public SteamVR_Skeleton_HandMask mask = new SteamVR_Skeleton_HandMask();

    public bool previewEnabled;

 

    public void Update(float deltaTime, SteamVR_Input_Sources inputSource){}

    public void ApplyBlending(SteamVR_Skeleton_PoseSnapshot snapshot, SkeletonBlendingPose[] blendPoses, SteamVR_Input_Sources inputSource){}

    public PoseBlendingBehaviour{}

    public enum BlenderTypes{}

}    //立钻哥哥:public class PoseBlendingBehaviour{}

++++\Assets\SteamVR\Input\SteamVR_Skeleton_Poser.cs

public class SteamVR_Skeleton_Poser : MonoBehaviour{

++++public List<PoseBlendingBehaviour> blendingBehaviours = new List<PoseBlendingBehaviour>();

++++PoseBlendingBehaviour behaviour = blendingBehaviours.Find(b=>b.name==behaviourName);

++++for(int behaviourIndex=0; behaviourIndex < blendingBehaviours.Count; behaviourIndex++){}

++++blendingBehaviours[behaviourIndex].Update(Time.deltaTime, inputSource);

++++if(blendingBehaviour[behaviourIndex].enabled && blendingBehaviours[behaviourIndex].influence * blendingBehaviours[behaviourIndex].value > 0.01f){}

++++if(blendingBehaviours[behaviourIndex].pose != 0){}

++++blendPoses[blendingBehaviours[behaviourIndex].pose].UpdateAdditiveAnimation(skeletonAction, inputSource);

++++blendingBehaviours[behaviourIndex].ApplyBlending(snapshot, blendPoses, inputSource);

++++public PoseBlendingBehaviour GetBlendingBehaviour(string behaviourName){}

++++public PoseBlendingBehaviour{}

}    //立钻哥哥:public class SteamVR_Skeleton_Poser:MonoBehaviour{}

++++\Assets\SteamVR\Input\Editor\SteamVR_Skeleton_PoserEditor.cs

[CustomEditor(typeof(SteamVR_Skeleton_Poser))]

public class SteamVR_Skeleton_PoserEditor : Editor{

++++if(blenderType.intValue==(int)SteamVR_Skeleton_Poser.PoseBlendingBehaviour.BlenderType.Manual){}

++++if(blenderType.intValue==(int)SteamVR_Skeleton_Poser.PoseBlendingBehaviour.BlenderTypes.AnalogAction){}

++++if(blenderType.intValue==(int)SteamVR_Skeleton_Poser.PoseBlendingBehaviour.BlenderTypes.BooleanAction){}

}    //立钻哥哥:public class SteamVR_Skeleton_PoserEditor:Editor{}

++++public class PoseBlendingBehaviour{}

 

++知识点04:SteamVR_Skeleton_PoseSnapshot

++++立钻哥哥PoseSnapshots hold a skeleton pose for one hand, as well as storing which hand they contain. They have several functions for combining BlendablePoses.PoseSnapshots为一只手保留一个骨架的姿势,同时也保存了它们包含的那只手。他们有几个功能,以结合可调和的姿势

public class SteamVR_Skeleton_PoseSnapshot{

    public SteamVR_Input_Sources inputSource;

    public Vector3 position;

    public Quaternion rotation;

    public Vector3[] bonePositions;

    public Quaternion[] boneRotations;

 

    public SteamVR_Skeleton_PoseSnapshot(int boneCount, SteamVR_Input_Sources source){}

    public void CopyFrom(SteamVR_Skeleton_PoseSnapshot source){}

}    //立钻哥哥:public class SteamVR_Skeleton_PoseSnapshot{}

++++\Assets\SteamVR\Input\SteamVR_Behaviour_Skeleton.cs

public class SteamVR_Behaviour_Skeleton : MonoBehaviour{

++++protected SteamVR_Skeleton_PoseSnapshot blendSnapshot;

++++blendSnapshot = blendPoser.GetBlendedPose(this);

++++SetBonePosition(boneIndex, Vector3.Lerp(blendSnapshot.bonePositions[boneIndex], blendedRangeOfMotionPosition, skeletonBlend));

++++Quaternion poseRotation = blendSnapshot.boneRotations[boneIndex];

++++SetBonePosition(boneIndex, blendSnapshot.bonePositions[boneIndex]);

++++SetBonePosition(boneIndex, Vector3.Lerp(blendSnapshot.bonePositions[boneIndex], bonePositions[boneIndex], skeletonBlend));

}    //立钻哥哥:public class SteamVR_Behaviour_Skeleton:MonoBehaviour{}

++++\Assets\SteamVR\Input\SteamVR_Skeleton_Poser.cs

public class SteamVR_Skeleton_Poser : MonoBehaviour{

++++public SteamVR_Skeleton_PoseSnapshot blendedSnapshotL;

++++blendedSnapshotL = new SteamVR_Skeleton_PoseSnapshot(boneCount, SteamVR_Input_Sources.LeftHand);

++++if(intpusource == SteamVR_Input_Sources.LeftHand){ return blendedSnapshotL; }

++++if(inputSource == SteamVR_Input_Sources.LeftHand){ blendedSnapshotL = snap; }

++++public SteamVR_Skeleton_PoseSnapshot blendedSnapshotR;

++++blendedSnapshotR = new SteamVR_Skeleton_PoseSnapshot(boneCount, SteamVR_Input_Sources.RightHand);

++++if(inputSource == SteamVR_Input_Sources.LeftHand){}else{ return blendedSnapshotR; }

++++if(inputSource == SteamVR_Input_Sources.RightHand){ blendedSnapshotR = snap; }

++++private SteamVR_Skeleton_PoseSnapshot GetHandSnapshot(SteamVR_Input_Sources inputSource){}

++++public SteamVR_Skeleton_PoseSnapshot GetBlendedPose(SteamVR_Action_Skeleton skeletonAction, SteamVR_Input_Sources handType){}

++++public SteamVR_Skeleton_PoseSnapshot GetBlendedPose(SteamVR_Behaviour_Skeleton skeletonBehaviour){}

++++SteamVR_Skeleton_PoseSnapshot snap = GetHandSnapshot(inputSource);

++++snap.CopyFrom(blendPoses[0].GetHandSnapshot(inputSource));

++++ApplyBlenderBehaviours(skeletonAction, inputSource, snap);

++++if(inputSource == SteamVR_Input_Sources.RightHand){ blendedSnapshotR = snap; }

++++if(inputSource == SteamVR_Input_Sources.LeftHand){ blendedSnapshotL = snap; }

++++protected void ApplyBlenderBehaviours(SteamVR_Action_Skeleton skeletonAction, SteamVR_Input_Sources inputSource, SteamVR_Skeleton_PoseSnapshot snapshot){}

++++blendingBehaviours[behaviourIndex].ApplyBlending(snapshot, blendPoses, inputSource);

}    //立钻哥哥:public class SteamVR_Skeleton_Poser:MonoBehaviour{}

++++\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs

//Links with an appropriate SteamVR controller and facilitates interactions with objects in the virtual world.(立钻哥哥:链接到适当的SteamVR控制器,并方便与虚拟世界中的对象进行交互.

public class Hand : MonoBehaviour{

++++SteamVR_Skeleton_PoseSnapshot pose = attachedObject.interactable.skeletonPoser.GetBlendedPose(skeleton);

++++objectToAttach.transform.position = this.transform.TransformPoint(pose.position);

++++objectToAttach.transform.rotation = this.transform.rotation * pose.rotation;

++++SteamVR_Skeleton_PoseSnapshot pose = null;

++++pose = currentAttachedObjectInfo.Value.interactable.skeletonPoser.GetBlendedPose(skeleton);

++++if(pose == null){}

}    //立钻哥哥:public class Hand:MonoBehaviour{}

++++public class SteamVR_Skeleton_PoseSnapshot{}

 

++知识点05:SteamVR_Skeleton_HandMask

++++立钻哥哥Simple mask for fingers.简单的手指遮罩

[System.Serializable]

public class SteamVR_Skeleton_HandMask{

    public bool palm;

    public bool thumb;

    public int index;

    public bool middle;

    public bool ring;

    public bool pinky;

    public bool[] values = new bool[6];

 

    public void SetFinger(int i, bool value){}

    public bool GetFinger(int i){}

    public SteamVR_Skeleton_HandMask(){}

    public void Reset(){}

    protected void Apply(){}

 

    public static readonly SteamVR_Skeleton_HandMask fullMask = new SteamVR_Skeleton_HandMask();

}    //立钻哥哥:public class SteamVR_Skeleton_HandMask{}

++++\Assets\SteamVR\Input\SteamVR_Skeleton_Poser.cs

public class SteamVR_Skeleton_Poser : MonoBehaviour{

++++public SteamVR_Skeleton_HandMask mask = new SteamVR_Skeleton_HandMask();

++++if(mask.GetFinger(0) || useMask==false){}

++++if(mask.GetFinger(SteamVR_Skeleton_JointIndexes.GetFingerForBone(boneIndex)+1) || useMask==false){}

++++public static readonly SteamVR_Skeleton_HandMask fullMask = new SteamVR_Skeleton_HandMask();

}    //立钻哥哥:public class SteamVR_Skeleton_Poser:MonoBehaviour{}

++++public class SteamVR_Skeleton_HandMask{}

 

 

++++立钻哥哥:经过上面对“SteamVR_Skeleton_Poser”组件的学习,现在我们来实践一下吧!

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第17张图片

----尝试1:直接在一个Cube上挂载“SteamVR_Skeleton_Poser”组件,没有能拿起来!

----尝试2:那我们就添加一个“Throwable”组件吧,因为这个组件会自动加载“Interactable”组件;其实我们需要的是验证“SkeletonPoserInteractable”之间的配合关系呢!(立钻哥哥:还是没有手势呢!!)

----尝试3:参考官方Demo示例,挂载缺失的脚本,看看能不能有奇迹出现呢?(比对后缺少脚本:“InteractableHoverEvents.cs”、“TargetHitEffect.cs”):挂载了这两个脚本,运行后还是没有出现手呢!?运行前倒是有一只手了?仅在运行前能显示出来,运行后就没有了!

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第18张图片

----尝试4:对比各个脚本差异,配置参数,只能再试一次了,不行就只能暂时跳过这个环节,后期补充一个专题;(嗯,有一个重大的发现:示例有一个空物体来承载所有脚本:请看“尝试5”)

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第19张图片

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第20张图片

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第21张图片

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第22张图片

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第23张图片

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第24张图片

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第25张图片

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第26张图片

----尝试5:在比对配置时,发现示例的可抛物是有层级的,父类是个空物体,把需要抓取的物品作为子物体处理的,我们先尝试一下吧!(依次挂载脚本:“SteamVR_Skeleton_Poser.cs(抓取失败,但是没有配置)”、“Throwable.cs(可以抓取了)”),先挂这两个脚本,其次先配置一下“SteamVR_Skeleton_Poser”组件的配置;通过“PoserEditor”可以配置手势,但是还是没有出现手势匹配;那我们继续添加脚本“InteractableHoverEvents.cs”和“TargetHitEffect.cs”,单挂脚本没有任何作用;那就来比对配置一下参数吧,貌似还是不行呀!

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第27张图片

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第28张图片

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第29张图片

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第30张图片

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第31张图片

++++立钻哥哥:经过第一轮的各种尝试,还没有成功,暂且跳过这个环节,后期会推出对于“SteamVR_Skeleton_Poser”组件的专题,请在“SteamVR”分类中查阅:

https://blog.csdn.net/vrunsoftyanlz/article/category/8582642

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第32张图片

+++++立钻哥哥:官网也有关于“Skeleton Poser”的教程,后期会根据这个教程整理一个专题:

https://valvesoftware.github.io/steamvr_unity_plugin/tutorials/Skeleton-Poser.html

 

++【Introduction】(介绍)

++++立钻哥哥:The Skeleton Poser system has a straightforward purpose: when picking up physical objects, your in-game hands should morph to poses holding the objects. These rock solid poses can be authored and tweaked right in the Unity editor, for quick iteration as your game progresses. You can apply fancy effects on top of these poses such as additive per-finger animation and dynamic grips, and multi-pose blending.骨架手势”系统有一个简单的目的:当你拿起实物时,你在游戏中的手应该变形成拿着实物的姿势。这些固定的姿势可以在Unity编辑器编写和调整,加快游戏迭代的速度。您可以在这些姿态之上应用一些奇特的效果,比如添加每个手指的动画和动态握把,以及多姿态混合

++++The value of this system comes from the simplified workflow. Instead of dealing with imported animations and nightmarish animation graphs, poses are stored as compact assets and animations are applied automatically based on the pose associated with whatever youre holding. This allows more complex hand behaviour on a smaller time budget.(立钻哥哥:该系统的价值来自于简化的工作流。与处理导入的动画和噩梦般的动画图形不同,pose存储为压缩资源,并根据与您所持有的任何内容相关联的姿势自动应用动画。这使得更复杂的手行为在更小的时间预算.

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第33张图片

++++These are the basic of what these tools can do. What makes them superior to built in Unity animations is that, again, poses are authored right in the scene view, and complex behaviours can be stacked with the flick of a few switches.(立钻哥哥:这些是这些工具的基本功能。它们优于Unity动画的地方在于,同样的,姿势是在场景视图中创建的,复杂的行为可以通过一些开关堆叠起来.

++++To add hand poses to any object in your game, just add the SteamVR_Skeleton_Poser script to it. There are two sections of the Poser script, and we will be covering both in this tutorial.(立钻哥哥:要向游戏中的任何对象添加手部姿势,只需添加“SteamVR_Skeleton_Poser”脚本即可。不易处理的脚本有两个部分,我们将涵盖在本教程.

 

++【Pose Editor】(姿态编辑器)

++++立钻哥哥:The pose editor is for creating and editing Poses(SteamVR_Skeleton_Pose) which can be saved as ScriptableObjects into your project and used on this object or any other in the game.pose编辑器用于创建和编辑pose (SteamVR_Skeleton_Pose),它可以作为“脚本对象”保存到您的项目中,并用于该对象或游戏中的任何其他对象

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第34张图片

++++When you first add the script to a GameObject you will see an option to either select a pose from the project, or create a new one.(立钻哥哥:当您第一次将脚本添加到GameObject时,您将看到一个选项,要么从项目中选择一个姿势,要么创建一个新姿势.

++++The preview the poses youre authoring, click the hand Icons in the Left Hand and Right Hand sections to toggle the previews on and off in the scene. These preview skeletons hold all your modifications in their transforms, so remember not to disable a hand with changes unless they have been saved the Save Pose button.(立钻哥哥:预览你正在创作的姿势,点击“左手”和“右手”部分的手势图标,在场景中切换预览。这些预览框架在它们的转换中包含所有的修改,所以请记住,除非已经保存了“Save Pose”按钮,否则不要禁用带有更改的手.

++++The hands instantiated in the scene when you do this are temporary and will be destroyed when the game is run, as long as the script has kept track of them properly. It is good practice to disable both hand previews before applying to a prefab, as the skeletons are messy, large, and unnecessary in a prefab.(立钻哥哥:当你这样做时,在场景中实例化的手是临时的,并且在游戏运行时将被销毁,只要脚本正确地跟踪它们。在应用到预置之前禁用双手预览是一个很好的实践,因为在预置中骨架是混乱的、大的、不必要的.

++++Its easiest to edit the poses when just one is enabled, but for some of the buttons in this tab to work you need both preview hands to be enabled. If a button is greyed out, you likely need to enable one or both skeletons to activate it.(立钻哥哥:当只启用一个时,编辑姿势是最简单的,但是要使这个选项卡中的一些按钮工作,您需要启用两个预览手。如果一个按钮是灰色的,您可能需要启用一个或两个骨架来激活它

++++If you want to modify the skeletons pose, just open up the hierarchy underneath your interactable object. You can see that a vr glove skeleton has been added to it, and you can go in and edit the transforms of these bones to form your pose.(立钻哥哥:如果您想修改骨架的姿态,只需打开interactable对象下面的层次结构。你可以看到一个“vr手套”骨架被添加到其中,你可以进入并编辑这些骨骼的变换来形成你的姿势

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第35张图片

++++If you want to make asymmetrical poses: if you have, say an asymmetrical object: you can author a different pose for the right hand and left hand. For simple or symmetrical objects, though, you probably want the same pose for both hands, so you can copy any single-hand modifications youve made over the other hand with the Copy x Pose to y hand buttons. When the pose is copied, the hands are automatically mirrored across your object, and often give perfect results. Be careful with this operation, as it will permanently overwrite the other hands pose.(立钻哥哥:如果你想做一个不对称的姿势:如果你有,比如说一个不对称的物体:你可以为右手和左手设计一个不同的姿势。不过,对于简单或对称的对象,您可能希望两只手的姿势相同,因此您可以使用“将x位姿复制到y位手”按钮复制对另一只手进行的任何单手修改。当姿势被复制时,手会自动地在你的对象上镜像,并且通常会得到完美的结果。小心这个操作,因为它会永久地覆盖另一只手的姿势.

++++Its a good idea to make backups of really important poses if youre going to be editing them, as the work can be lost easily.(立钻哥哥:如果你要编辑一些非常重要的姿势,备份是一个好主意,因为这些动作很容易丢失

++++To add more usable poses to an object, or to create a new pose, hit the little plus button next to the list of poses at the top. Youll see a new tab is created with no pose selected by default, and again you can either select one from the project or create a new pose. The poses added to a single SteamVR_Skeleton_Poser will be the poses available for blending later on. The order of these doesnt matter except for the first pose, labeled(MAIN), which will be the base pose.(立钻哥哥:要向对象添加更多可用的姿势,或创建一个新的姿势,请单击顶部的姿势列表旁边的小加号按钮。您将看到创建了一个新选项卡,默认情况下没有选择任何姿势,同样,您可以从项目中选择一个姿势,也可以创建一个新姿势。添加到单个“SteamVR_Skeleton_Poser”中的姿势将是稍后用于“混合”的姿势。这些的顺序无关紧要,除了第一个姿势,标记为(MAIN),这将是基本姿势

++++Underneath each of the hand icons you may have noticed all the options for finger movement. This is for additive animation where you want the skeletal systems individual finger animation to apply on top of the poses that youve created. By default this will be set to static, but there are three other options.(立钻哥哥:在每个手的图标下面,你可能已经注意到了手指移动的所有选项。这是为“添加动画”,您希望骨骼系统的个别手指动画应用于您所创建的姿势之上。默认情况下,这将被设置为静态,但还有其他三个选项.

----[Static]: No additive animation;(立钻哥哥:[静态]:无添加动画;

----[Free]: If you do not want your pose to apply to that finger at all, and in that case its listen only to the skeleton system.(立钻哥哥:([自由]):如果你不希望你的姿势应用到手指上,在这种情况下,它只听骨架系统

----[Extend]: If the pose that in the hand is in will be the tightest possible grip of that finger, lifting it up when the player lifts their finger up. This will probably be the most common, as poses are mainly going to be wrapping around objects.(立钻哥哥:[伸展]:如果手的姿势是手指最紧的握法,那么当玩家抬起手指时就把手指举起来。这可能是最常见的,因为姿势主要是围绕着物体

----[Contract]: The opposite of extend, where whatever pose the finger is in will be the maximum extended value of the finger, and it will only be allowed to contract further towards the fist pose. Im not sure when that one would be used but we added it just in case.(立钻哥哥:[收缩]:与伸展相反,无论手指处于什么姿势,都是手指的最大伸展值,只允许手指向第一个姿势进一步收缩。我不确定什么时候会用到这个但是我们加了以防万一

 

++【Blending Editor】(混合编辑器)

++++立钻哥哥:The next tab is the blending editor. This is what you will use if you want to create more complicated behaviours, i.e. blending between multiple poses.(立钻哥哥:下一个选项卡是混合编辑器。如果你想创造更复杂的行为,比如多个姿势之间的混合,你可以使用这个.

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第36张图片

++++To start, youll want to hit the plus button at the bottom to add a new blending behaviour, called New Behaviour by default. You can enable and disable behavious, and they have an influence slider where you can turn them off and on with more of a ramp if you dont want to harshly enable and disable them during runtime.(立钻哥哥:首先,您需要点击底部的“plus按钮”来添加一个新的混合行为,默认情况下称为“new behavior”。你可以启用和禁用这个行为,它们有一个影响滑块,如果你不想在运行时严格地启用和禁用它们,你可以使用更多的斜坡来关闭和打开它们.

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第37张图片

++++They have a target pose that they will be blending to which by default is the main pose. This is poor design, because since the main pose is the base, this wont do anything. Instead, youll want to set this to one of the secondary poses youve added on the pose editor list.(立钻哥哥:他们有一个目标“姿势”,他们将混合其中的默认是主要的姿势。这是一个糟糕的设计,因为由于主要的姿势是基础,这不会做任何事情。相反,您将希望将此设置为您在pose编辑器列表中添加的辅助姿势之一.

++++There are three different types of Blending Behavious: ManualAnalogBoolean.(立钻哥哥:有三种不同类型的混合行为:手动混合、模拟混合、布尔混合.

----[Manual]:What you would use if you want this blending to be controlled by a script or just set in the inspector right here with this value slider. Does nothing on its own.(立钻哥哥:(手动):你会使用如果你想要这种混合控制的一套脚本或检查员用这个值在这里滑块。它自己什么也不做

----[Analog]:Lets you map this blending behaviour weight to one of the analog actions in your project. Smoothing speed lets you apply a little bit of smoothing to this. Zero means no smoothing, anything above zero is going to be slow smoothing getting faster and faster as the value goes up. An appropriate value would be somewhere between 10 and 30, although you may not want any smoothing at all since this is an analog action.(立钻哥哥:(模拟):让这种混合行为映射到一个模拟行动在您的项目中。平滑速度可以让你对它进行一点平滑。零意味着没有平滑,任何大于零的都是缓慢平滑,随着数值的增加,平滑的速度越来越快。一个适当的值应该在10到30之间,尽管您可能根本不需要任何平滑,因为这是一个模拟操作

----[Boolean]:This is very similar to the analog action, except it can be mapped to a boolean action in your project such as a button press. In this behaviour type the smoothing is probably a little bit more important, because if you dont have any smoothing its going to be an instant jump. Again, a value between 10 and 30 is recommended.(立钻哥哥:(布尔):这非常类似于模拟行动,除了它可以被映射到一个布尔行动项目中如一个按钮按下。在这种行为类型中平滑可能更重要一些,因为如果你没有平滑,它将是一个瞬间的跳跃。同样,建议值在10到30之间

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第38张图片

++++立钻哥哥:The final option in every blending behaviour is the mask. Anybody whos used Unitys humanoid animation system will find this UI very familiar, and those who havent will find it is pretty self-explanatory. If you do not use the mask the blending behavior will be applied to the entire hand. If you do opt in for the mask, them you can select different parts of the hand to apply blending to. Green parts will have the blending behavior applied to them, and gray parts will not.每种混合行为的最后一个选项是蒙版。任何使用过Unity类人动画系统的人都会发现这个UI非常熟悉,而那些没有使用过的人会发现它非常容易理解。如果您不使用蒙版,混合行为将适用于整个手。如果你选择了蒙版,你可以选择手的不同部位进行混合。绿色部分将应用混合行为,而灰色部分不会

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第39张图片

----Remember, you can stack multiple blending behaviours on top of each other and they will be applied in order. Using this, you can create some really cool complicated hand behaviours.(立钻哥哥:记住,您可以将多个混合行为堆叠在一起,它们将按顺序应用。使用这个,你可以创造一些非常酷的复杂的手的行为

 

++【Manual Behaviours】(手动操作)

++++立钻哥哥:Analog and Boolean behaviours animate automatically, but you do have to modify manual ones through code. Luckily, this is very easy. Heres an example script that would modulate a Behaviour named Example Behaviour using a since wave:(立钻哥哥:模拟和布尔行为自动动画,但你必须修改手动通过代码。幸运的是,这很简单。下面是一个示例脚本,它将使用since wave来调节名为“示例行为”的行为

using UnityEngine;

using System.Collections;

using Valve.VR;

 

public class PoseModulator : MonoBehaviour{

    SteamVR_Skeleton_Poser poser;

 

    private void Start(){

        poser = GetComponent<SteamVR_Skeleton_Poser>();

    }

 

    private void Update(){

        poser.SetBlendingBehaviourValue(Example Behaviour, Mathf.Sin(Time.time * 10)/2 + 0.5f);

    }

 

}    //立钻哥哥:public class PoseModulator:MonoBehaviour{}

 

++And the result(结果):

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第40张图片

 

 

++【Scaling】(缩放)

++++立钻哥哥:Lots of games are made at different scales for any number of reasons. What matters is that your player may be scaled up or down. The poses are applied at runtime at whatever the player scale is, which is great, but the pose authoring tools are done at a normal scale by default. This will be a problem if youre making objects that should be interactable at larger scales, as the preview you get as you work on a pose will not match the pose that you see in the game. To solve this, we added a property, Preview Pose Scale, that lets you change the working scale of the pose editor.由于各种原因,许多游戏都是以不同的规模制作的。重要的是你的玩家可能被放大或缩小。姿态在运行时以任意玩家比例应用,这很好,但默认情况下,姿态创作工具是在正常比例下完成的。这将是一个问题,如果你正在制作的对象在更大的尺度上应该是可交互的,因为你在一个姿势上得到的预览与你在游戏中看到的姿势不匹配。为了解决这个问题,我们添加了一个属性“预览姿态缩放”,它允许您更改位姿编辑器的工作缩放

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第41张图片

----This value should be set to whatever your players scale will be.(立钻哥哥:这个值应该设置为你的玩家的规模将是什么.

----Poses saved from different Preview Scales will be indistinguishable, it is merely a helper for the editor to show what your poses will look applied from differently scaled hands.(立钻哥哥:从不同的预览比例保存的姿势将是无法区分的,它只是一个帮助编辑器显示你的姿势将从不同比例的手看起来应用.

 

++【Conclusion】(总结)

++++立钻哥哥:I hope this tutorial helped you get started creating your own hand poses!我希望本教程能帮助您开始创建自己的手部姿势

++立钻哥哥:好吧,都看完“官方教程”了,感觉还是一头雾水,不管怎样,我们再尝试一次,看看能否得到想要的“手势动作”!

++++步骤1:新建一个Cube,缩放到想要的比例后,挂上“SteamVR_Skeleton_Poser”看一下效果,因为根据教程就只需要挂上这个脚本就可以的呢!

++++步骤2:需要添加一个“Throwable”组件;==??能抓取,但是没有显示手??

++++总之,还是失败了,这里就不再继续了,有兴趣的可以查阅“SteamVR”分类,立钻哥哥会推出一个关于“SteamVR_Skeleton_Poser”组件的专题,来全面研究学习一下,这次就不拓展了!

++++那还是官方标准的手势匹配的例子吧:

++++SteamVR分类:https://blog.csdn.net/vrunsoftyanlz/article/category/8582642

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第42张图片

 

 

 

++9、添加“Teleporting”传送预制体

++++立钻哥哥:To add teleporting to your scene drag in the Teleporting prefab from Teleport/Prefabs into your scene. This will set up all the teleport logic.在场景中添加“远程传送”功能,请将“远程传送”预制件从“Teleport/Prefabs”拖动到场景中,这将设置所有的传送逻辑

++++关于“传送机制”有一篇专门的博客:https://blog.csdn.net/VRunSoftYanlz/article/details/89390866

++++“The Lab(Valve的实验室)”的传送系统支持传送到特定的传送点或更通用的传送区;重要的类是“Teleport”、“TeleportPoint”、“TeleportArea

++++Teleport/Prefabs”下的预制体“Teleporting”包括了传送系统运作的所有逻辑;向场景中添加“TeleportPoints”或“TeleportAreas”,可以添加玩家可以传送到的点

++++Teleport.cs”这个类处理“Teleporting传送”的大部分逻辑;当触摸板被按下时,传送指针就会出现,当指针指向一个有效的点,松开即可传送玩家;(我们也可以按下键盘上的“T”,在2D备份模式下,可以打开传送指针),“Teleport.cs”该类跟踪场景中的所有传送端口标记,并根据传送端口指针的状态通知它们淡入/淡出

++++在某些情况下,在地板上使用不同于传送网格的网格是很有用的,在这种情况下,传送系统将追踪它击中传送网的位置,并试图将其放置在地板网孔上,这样做的目的是尝试将场景中的视觉地板与玩家游戏区域中的物理地板匹配起来

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第43张图片

++++Teleport.cs”中有一些属性可能需要调整:“tracerLayerMask”、“floorFixupMask”、“floorFixupMaximumTraceDistance”、“ShowPlayAreaMarker”、“arcDistance”等

----[tracerLayerMask]:这是传送指针将尝试命中的所有层

----[floorFixupMask]:地板所在的层

----[floorFixupMaximumTraceDistance]:查找地板的最大跟踪距离

----[ShowPlayAreaMarker]:这将切换是否显示传送时玩家游戏区域的矩形,这可以帮助玩家在他们的物理空间中找到方向

----[arcDistance]:传送弧应该走多远,增加这个数字将允许玩家在场景中传送得更远,这个值可能需要为每个场景进行调整

//\Assets\SteamVR\InteractionSystem\Teleport\Scripts\Teleport.cs

//Purpose: Handles all the teleport logic.(立钻哥哥:用途:处理所有的传送逻辑.

using UnityEngine;

using UnityEngine.Events;

using System.Collections;

 

namespace Valve.VR.InteractionSystem{

    public class Teleport : MonoBehaviour{

        public SteamVR_Action_Boolean teleportAction = SteamVR_Input.GetAction<SteaVR_Action_Boolean>(Teleport);

 

        private Hand pointerHand = null;

        private Player player = null;

        private TeleportArc teleportArc = null;

 

        private static Teleport _instance;

        public static Teleport instance{}

 

        void Awake(){  instance = this;  }

 

        private void UpdatePointer(){}

        private void TeleportPlayer(){}

    }    //立钻哥哥:public class Teleport:MonoBehaviour{}

}    //立钻哥哥:namespace Valve.VR.InteractionSystem{}

 

++++TeleportMarkerBase(传送标记基类):这是所有传送标记的基类;它包含“Teleport”类期望出现在所有Teleport标记中的方法;我们可以用这个作为基类来创建一个新的传送标记;传送标记可以锁定或解锁,玩家不能传送到锁定的标记

//\Assets\SteamVR\InteractionSystem\Teleport\Scripts\TeleportMarkerBase.cs

//Purpose: Base class for all the objects that the player can teleport to.(立钻哥哥:用途:玩家可以传送到的所有对象的基类.

using UnityEngine;

 

namespace Valve.VR.InteractionSystem{

    public abstract class TeleportMarkerBase : MonoBehaviour{

        public bool locked = false;

        public bool markerActive = false;

 

        public virtual bool showReticle{}

        public void SetLocked(bool locked){}

        public virtual void TeleportPlayer(Vector3 pointedAtPosition){}

        public abstract void UpdateVisuals();

        public abstract void Highlight(bool highlight);

        public abstract void SetAlpha(float tintAlpha, float alphaPercent);

        public abstract bool ShouldActivate(Vector3 playerPosition);

        public abstract bool ShouldMovePlayer();

    }    //立钻哥哥:public abstract class TeleportMarkerBase:MonoBehaviour{}

}    //立钻哥哥:namespace Valve.VR.InteractionSystem{}

++++TeleportArea(传送区域):这是一个由网格组成的传送区;当传送到这些东西上时,玩家将会准确地传送到他们所指向的地方(加上地板固定);将“TeleportArea”组件添加到任何带有碰撞体和网格渲染器的对象中,以允许玩家在其上传送

//\Assets\SteamVR\InteractionSystem\Teleport\Scripts\TeleportArea.cs

//Purpose: An area that the player can teleport to.(立钻哥哥:用途:玩家可以传送到的区域.

using UnityEngine;

#if UNITY_EDITOR

    using UnityEditor;

#endif

 

namespace Valve.VR.InteractionSystem{

    public class TeleportArea : TeleportMarkerBase{

        public Bounds meshBounds{}

        private MeshRenderer areaMesh;

 

        public void Awake(){

            areaMesh = GetComponent<MeshRenderer>();

            tintColorId = Shader.PropertyToID(_TintColor);

            CalculateBounds();

        }

 

        public void Start(){}

 

        public override bool ShouldActivate(Vector3 playerPosition){}

        public override bool ShouldMovePlayer(){}

        public override void Highlight(bool highlight){}

        public override void SetAlpha(float tintAlpha, float alphaPercent){}

        public override void UpdateVisuals(){}

        private bool CalculateBounds(){}

        private Color GetTintColor(){}

    }    //立钻哥哥:public class TeleportArea:TeleportMarkerBase{}

}    //立钻哥哥:namespace Valve.VR.InteractionSystem{}

 

++++[Teleporting]:传送预制体处理系统的所有传送逻辑

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第44张图片

++++TeleportPoint(传送点):这是玩家可以传送到的传送点;当传送到这些东西上时,玩家将会在点的原点进行传送,而不管他们所指向的点在哪里

//\Assets\SteamVR\InteractionSystem\Teleport\Scripts\TeleportPoint.cs

//Purpose: Single location that the player can teleport to.(立钻哥哥:用途:单一的位置,玩家可以传送到.

using UnityEngine;

using UnityEngine.UI;

#if UNITY_EDITOR

    using UnityEditor;

#endif

 

namespace Valve.VR.InteractionSystem{

    public class TeleportPoint : TeleportMarkerBase{

        public enum TeleportPointType{

            MoveToLocation,

            SwitchToNewScene

        };

 

        public TeleportPointType teleportType = TeleportPointType.MoveToLocation;

 

        public override bool showReticle{}

        void Awake(){}

        void Start(){}

        void Update(){}

        public override bool ShouldActivate(Vector3 playerPosition){}

        public override bool ShouldMovePlayer(){}

        public override void Highlight(bool highlight){}

        public override void UpdateVisuals(){}

        public override void SetAlpha(float tintAlpha, float alphaPercent){}

        public void SetMeshMaterials(Material material, Color textColor){}

        public void TeleportToScene(){}

        public void GetRelevantComponents(){}

        public void ReleaseRelevantComponents(){}

        public void UpdateVisualsInEditor(){}

    }    //立钻哥哥:public class TeleportPoint:TeleportMarkerBase{}

}    //立钻哥哥:namespace Valve.VR.InteractionSystem{}

++++TeleportArc(传送弧):这将为传送端口指针绘制弧线,并为传送端口系统进行物理跟踪

//\Assets\SteamVR\InteractionSystem\Teleport\Scripts\TeleportArc.cs

//Purpose: Displays the arc lines for teleporting and does the traces.(立钻哥哥:用途:显示用于远程传送的弧线并进行跟踪.

using UnityEngine;

 

namespace Valve.VR.InteractionSystem{

    public class TeleportArc : MonoBehaviour{

        public int segmentColor = 60;

        public float thickness = 0.01f;

 

        void Start(){}

        void Update(){}

        private void CreateLineRendererObjects(){}

        public void SetArcData(Vector3 position, Vector3 velocity, bool gravity, bool pointerAtBadAngle){}

        public void Show(){}

        public void Hide(){}

        public bool DrawArc(out RaycastHit hitInfo){}

        private void DrawArcSegment(int index, float startTime, float endTime){}

        public void SetColor(Color color){}

        private float FindProjectileCollison(out RaycastHit hitInfo){}

        public Vector3 GetArcPositionAtTime(float time){}

        private void HideLineSegments(int startSegment, int endSegment){}

    }    //立钻哥哥:public class TeleportArc:MonoBehaviour{}

}    //立钻哥哥:namespace Valve.VR.InteractionSystem{}

++++AllowTeleportWhileAttachedToHand(允许传送时附加在手):默认情况下,我们不能用一只手来传送东西,将此“AllowTeleportWhileAttachedToHand”组件添加到附加对象上可以绕过该规则

//\Assets\SteamVR\InteractionSystem\Teleport\Scripts\AllowTeleportWhileAttachedToHand.cs

//Purpose: Adding this component to an object will allow the player to initiate teleporting while that object is attached to their hand.(立钻哥哥:目的:将这个组件添加到一个对象将允许玩家在该对象与他们的手连接时启动传送

using UnityEngine;

namespace Valve.VR.InteractionSystem{

    public class AllowTeleportWhileAttachedToHand : MonoBehaviour{

        public bool teleportAllowed = true;

        public bool overrideHoverLock = true;

    }    //立钻哥哥:public class AllowTeleportWhileAttachedToHand:MonoBehaviour{}

}    //立钻哥哥:namespace Valve.VR.InteractionSystem{}

++++IgnoreTeleportTrace(忽略传送跟踪):将其添加到带有碰撞体的对象将允许传送跟踪穿透它;另一种处理方法是将该对象放在TeleportArc不检查的另一个层上

//\Assets\SteamVR\InteractionSystem\Teleport\Scripts\IgnoreTeleportTrace.cs

//Purpose: Allows the teleport arc trace to pass through any colliders on this object.(立钻哥哥:目的:允许传送弧跟踪通过该对象上的任何碰撞器

using UnityEngine;

using System.Collections;

namespace Valve.VR.InteractionSystem{

    public class IgnoreTeleportTrace : MonoBehaviour{

    }    //立钻哥哥:public class IgnoreTeleportTrace:MonoBehaviour{}

}    //立钻哥哥:namespace Valve.VR.InteractionSystem{}

++++Teleporting(Prefab)(传送预制体):这个预制体设置了整个传送系统;拖拽这个预制体到场景中会在游戏中打开传送指针;所有的传送系统的视觉和声音可以通过这个预制的属性来改变

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第45张图片

++++TeleportPoint(Prefab)(传送点预制体):将这些添加到场景中,以添加玩家可以传送到的位置

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第46张图片

++++立钻哥哥:经过大量的相关知识拓展,貌似没有什么用!毕竟,我们需要的是实战!实战!实战!!!那我们接下来操练起来吧!

----首先,我们直接拖一个预制体(\Assets\SteamVR\InteractionSystem\Teleport\Prefabs\Teleporting.prefab)到场景中,运行一下看看效果吧

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第47张图片

----运行很顺利,而且效果也还不错,没有什么明显的bug,可以直接拿来用的,如果想实现传送功能,还需要继续往下操作“10、添加TeleportPoint传送点预制体”和“11、添加TeleportArea传送区域预制体

++++立钻哥哥:经过上面的操练,这个“Teleporting”预制体还是比较顺利的运行了,那我们就来看看这个预制体中的核心代码吧!(核心代码就两个:“Teleport.cs”和“TeleportArc.cs”)

++++[Teleport.cs]:处理所有的传送逻辑!这个解释已经非常明确了,这个脚本非常非常重要呀!

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第48张图片

//\Assets\SteamVR\InteractionSystem\Teleport\Scripts\Teleport.cs

//Purpose: Handles all the teleport logic.(立钻哥哥:用途:处理所有的传送逻辑.

using UnityEngine;

using UnityEngine.Events;

using System.Collections;

 

namespace Valve.VR.InteractionSystem{

    public class Teleport : MonoBehaviour{

        public SteamVR_Action_Boolean teleportAction = SteamVR_Input.GetAction<SteamVR_Action_Boolean>(Teleport);

 

        public LayerMask traceLayerMask;

        public LayerMask floorFixupTraceLayerMask;

        public float floorFixupMaximumTraceDistance = 1.0f;

        public Material areaVisibleMaterial;

        public Material areaLockedMaterial;

        public Material areaHighlightedMaterial;

        public Material pointVisibleMaterial;

        public Material pointLockedMaterial;

        public Material pointHighlightedMaterial;

        public Transform destinationReticleTransform;

        public Transform invalidReticleTransform;

        public GameObject playAreaPreviewCorner;

        public GameObject playAreaPreviewSide;

        public Color pointerValidColor;

        public Color pointerInvalidColor;

        public Color pointerLockedColor;

        public bool showPlayAreaMarker = true;

 

        public float teleportFadeTime = 0.1f;

        public float meshFadeTime = 0.2f;

        public float arcDistance = 10.0f;

 

        [Header(Effects(立钻哥哥:效果))]

        public Transform onActivateObjectTransform;

        public Transform onDeactivateObjectTransform;

        public float activateObjectTime = 1.0f;

        public float deactivateObjectTime = 1.0f;

 

        [Header(Audio Sources(立钻哥哥:声音来源))]

        public AudioSource pointerAudioSource;

        public AudioSource loopingAudioSource;

        public AudioSource headAudioSource;

        public AudioSource reticleAudioSource;

 

        [Header(Sounds(立钻哥哥:音效))]

        public AudioClip teleportSound;

        public AudioClip pointerStartSound;

        public AudioClip pointerLoopSound;

        public AudioClip pointerStopSound;

        public AudioClip goodHighlightSound;

        public AudioClip badHighlightSound;

 

        [Header(Debug(立钻哥哥:调试))]

        public bool debugFloor = false;

        public bool showOffsetReticle = false;

        public Transform offsetReticleTransform;

        public MeshRenderer floorDebugSphere;

        public LineRenderer floorDebugLine;

 

        private LineRenderer pointerLineRenderer;

        private GameObject teleportPointerObject;

        private Transform pointerStartTransform;

        private Hand pointerHand = null;

        private Player player = null;

        private TeleportArc teleportArc = null;

 

        private bool visible = false;

 

        private TeleportMarkerBase[] teleportMarkers;

        private TeleportMarkerBase pointedAtTeleportMarker;

        private TeleportMarkerBase teleportingToMarker;

        private Vector3 pointedAtPosition;

        private Vector3 prevPointedAtPosition;

        private bool teleporting = false;

        private float currentFadeTime = 0.0f;

 

        private float meshAlphaPercent = 1.0f;

        private float pointerShowStartTime = 0.0f;

        private float pointerHideStartTime = 0.0f;

        private bool meshFading = false;

        private float fullTintAlpha;

   

        private float invalidReticleMinScale = 0.2f;

        private float invalidReticleMaxScale = 1.0f;

        private float invalidReticleMinScaleDistance = 0.4f;

        private float invalidReticleMaxScaleDistance = 2.0f;

        private Vector3 invalidReticleScale = Vector3.one;

        private Quaternion invalidReticleTargetRotation = Quaternion.identity;

 

        private Transform playAreaPreviewTransform;

        private Transform[] playAreaPreviewCorners;

        private Transform[] playAreaPreviewSides;

 

        private float loopingAudioMaxVolume = 0.0f;

 

        private Coroutine hintCoroutine = null;

 

        private bool originalHoverLockState = false;

        private Interactable originalHoveringInteractable = null;

        private AllowTeleportWhileAttachedToHand allowTeleportWhileAttached = null;

 

        private Vector3 startingFeetOffset = Vector3.zero;

        private bool movedFeetFarEnough = false;

 

        SteamVR_Events.Action chaperoneInfoInitializedAction;

 

        //Events(立钻哥哥:事件)

        public static SteamVR_Events.Event<float> ChangeState = new SteamVR_Events.Event<float>();

        public static SteamVR_Events.Action<float> ChangeSceneAction(UnityAction<float> action){};

        public static SteamVR_Events.Event<TeleportMarkderBase> Player = new SteamVR_Events.Event<TeleportMarkerBase>();

        public static SteamVR_Events.Action<TeleportMarkerBase> PlayerAction(UnityAction<TeleportMarkerBase> actionsss){}

        public static SteamVR_Events.Event<TeleportMarkerBase> PlayerPre = new SteamVR_Events.Event<TeleportMarkerBase>();

        public static SteamVR_Events.Action<TeleportMarkerBase> PlayerPreAction(UnityAction<TeleportMarkerBase> action){}

 

        private static Teleport _instance;

        public static Teleport instance{}

 

        void Awake(){

            _instance = this;

            chaperoneInfoInitializedAction = ChaperoneInfo.InitializedAction(OnChaperoneInfoInitialized);

 

            pointerLineRenderer = GetComponentInChildren<LineRenderer>();

            teleportPointerObject = pointerLineRenderer.gameObject;

    

            int tintColorID = Shader.PropertyToID(_TintColor);

            fullTintAlpha = pointVisibleMaterial.GetColor(tintColorID).a;

 

            teleportArc = GetComponent<TeleportArc>();

            teleportArc.traceLayerMask = traceLayerMask;

 

            loopingAudioMaxVolue = loopingAudioSource.volume;

 

            playAreaPreviewCorner.SetActive(false);

            playAreaPreviewSide.SetActive(false);

 

            float invalidReticleStartingScale = invalidReticleTransform.localScale.x;

            invalidReticleMinScale *= invalidReticleStartingScale;

            invalidReticleMaxScale *= invalidReticleStartingScale;

        }    //立钻哥哥:void Awake(){}

 

        void Start(){

            teleportMarkers = GameObject.FindObjectsOfType<TeleportMarkerBase>();

            HidePointer();

            player = InteractionSystem.Player.instance;

 

            if(player == null){

                Debug.LogError(立钻哥哥:[SteamVR Interaction] Teleport: No Player instance found in map.);

                Destroy(this.gameObject);

                return;

            }

 

            CheckForSpawnPoint();

            Invoke(ShowTeleportHint, 5.0f);

        }    //立钻哥哥:void Start(){}

 

        void OnEnable(){

            chaperoneInfoInitializedAction.enabled = true;

            OnChaperoneInfoInitialized();

        }

 

        void OnDisable(){

            chaperoneInfoInitializedAction.enabled = false;

            HidePointer();

        }

 

        private void CheckForSpawnPoint(){}

        pubic void HideTeleportPointer(){}

        void Update(){}

        private void UpdatePointer(){}

        void FixedUpdate(){}

        private void OnChaperoneInfoInitialized(){}

        private void HidePointer(){}

        private void ShowPointer(Hand newPointerHand, Hand oldPointerHand){}

        private void UpdateTeleportColors(){}

        private void PlayAudioClip(AudioSource source, AudioClip clip){}

        private void PlayPointerHaptic(bool validLocation){}

        private void TryTeleportPlayer(){}

        private void InitiateTeleportFade(){}

        private void TeleportPlayer(){}

        private void HighlightSelected(TeleportMarkerBase hitTeleportMarker){}

        public void ShowTeleportHint(){}

        public void CancelTeleportHint(){}

        private IEnumerator TeleportHintCoroutine(){}

        public bool IsEligibleForTeleport(Hand hand){}

        private bool ShouldOverrideHoverLock(){}

        private bool WasTeleportButtonReleased(Hand hand){}

        private bool IsTeleportButtonDown(Hand hand){}

        private bool WasTeleportButtonPressed(Hand hand){}

        private Transform GetPointerStartTransform(Hand hand){}

    }    //立钻哥哥:public class Teleport:MonoBehaviour{}

}    //立钻哥哥:namespace Valve.VR.InteractionSystem{}

++++\Assets\SteamVR\InteractionSystem\Teleport\Scripts\TeleportArc.cs

//Purpose: Displays the arc lines for teleporting and does the traces.(立钻哥哥:用途:显示用于远程传送的弧线并进行跟踪

using UnityEngine;

 

namespace Valve.VR.InteractionSystem{

    public class TeleportArc : MonoBehaviour{

        public int segmentCount = 60;

        public float thickness = 0.01f;

        public float arcDuration = 3.0f;

        public float segmentBreak = 0.025f;

        public float arcSpeed = 0.2f;

        public Material material;

 

        [HideInInspector]

        public int traceLayerMask = 0;

 

        private LineRenderer[] lineRenderers;

        private float arcTimeOffset = 0.0f;

        private float prevThickness = 0.0f;

        private int prevSegmentCount = 0;

        private bool showArc = true;

        private Vector3 startPos;

        private Vector3 projectileVelocity;

        private bool useGravity = true;

        private Transform arcObjectsTransform;

        private bool arcInvalid = false;

        private float scale = 1;

 

        void Start(){}

        void Update(){}

        private void CreateLineRendererObjects(){}

        public void SetArcData(Vector3 position, Vector3 velocity, bool gravity, bool pointerAtBadAngle){}

        public void Show(){}

        public void Hide(){}

        public bool DrawArc(out RaycastHit hitInfo){}

        private void DrawArcSegment(int index, float startTime, float endTime){}

        public void SetColor(Color color){}

        private float FindProjectileCollision(out RaycastHit hitInfo){}

        public Vector3 GetArcPositionAtTime(float time){}

       private void HideLineSegments(int startSegment, int endSegment){}

    }    //立钻哥哥:public class TeleportArc:MonoBehaviour{}

}    //立钻哥哥:namespace Valve.VR.InteractionSystem{}

++++立钻哥哥:这个“Teleporting”预制体,我们就先了解到这里,接下来看看“TeleportPoint”和“TeleportArea”预制体吧;

 

 

++10、添加“TeleportPoint”传送点预制体

++++立钻哥哥:在前面我们剖析了“Teleporting”这个预制体,这个预制体处理系统的所有传送逻辑,是一个非常重要的预制体哟;那这个“TeleportPoint(传送点)”也非常关键,这里提供了传送点功能逻辑

++++从“\Assets\SteamVR\InteractionSystem\Teleport\Prefabs\”下拖入这个预制体“TeleportPoint.prefab”到场景中,就可以生成一个传送点

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第49张图片

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第50张图片

++++立钻哥哥:上面展示了“TeleportPoint(传送点)”的效果,还不错,没有什么大的问题,那我们就可以根据这个初步Demo,来展开我们的想象了,替换成我们想要的功能和UI

++++\Assets\SteamVR\InteractionSystem\Teleport\Scripts\TeleportPoint.cs

//Purpose: Single location that the player can teleport to.(立钻哥哥:用途:单一的位置,玩家可以传送到.

using UnityEngine;

using UnityEngine.UI;

#if UNITY_EDITOR

    using UnityEditor;

#endif

 

namespace Valve.VR.InteractionSystem{

    public class TeleportPoint : TeleportMarkerBase{

        public enum TeleportPointType{

            MoveToLocation,

            SwitchToNewScene

        };

 

        public TeleportPointType teleportType = TeleportPointType.MoveToLocation;

 

        void Awake(){}

        void Start(){}

        void Update(){}

    }    //立钻哥哥:public class TeleportPoint:TeleportMarkerBase{}

}    //立钻哥哥:namespace Valve.VR.InteractionSystem{}

++++TeleportMarkerBase(传送标记基类):这是所有传送标记的基类;它包含“Teleport”类期望出现的所有Teleport标记中的方法;我们可以用这个作为基类来创建一个新的传送标记;传送标记可以锁定或解锁,玩家不能传送到锁定的标记

//\Assets\SteamVR\InteractionSystem\Teleport\Scripts\TeleportMarkerBase.cs

//Purpose: Base class for all the objects that the player can teleport to.(立钻哥哥:用途:玩家可以传送到的所有对象的基类.

using UnityEngine;

namespace Valve.VR.InteractionSystem{

    public abstract class TeleportMarkerBase : MonoBehaviour{

        public bool locked = false;

        public bool markerActive = true;

 

        public virtual bool showReticle{}

        public void SetLocked(bool locked){}

        public virtual void TeleportPlayer(Vector3 pointedAtPosition){}

        public abstract void UpdateVisuals();

        public abstract void Highlight(bool highlight);

        public abstract void SetAlpha(float tintAlpha, float alphaPercent);

        public abstract bool ShouldActivate(Vector3 playerPosition);

        public abstract bool ShouldMovePlayer();

    }    //立钻哥哥:public abstract class TeleportMarkerBase:MonoBehaviour{}

}    //立钻哥哥:namespace Valve.VR.InteractionSystem{}

++++[TeleportPoint(传送点)]:这是玩家可以传送到的传送点;当传送到这些东西上时,玩家将会在点的原点进行传送,而不管他们所指向的点在哪里

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第51张图片

++++[TeleportPoint(Prefab)(传送点预制体)]:将预制体添加到场景中,以添加玩家可以传送到的位置

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第52张图片

 

++++立钻哥哥:这里篇幅有过长了,还没有写完呢!只能分开几篇了!

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第53张图片

++++SteamVR2.2.0教程(一)https://blog.csdn.net/VRunSoftYanlz/article/details/89324067

++++SteamVR2.2.0教程(二)https://blog.csdn.net/VRunSoftYanlz/article/details/89894097

 

 

 

【XR游戏开发QQ群:784477094

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第54张图片

++立钻哥哥推荐的拓展学习链接(Link_Url)

立钻哥哥推荐的拓展学习链接(Link_Url)

++++立钻哥哥Unity 学习空间: http://blog.csdn.net/VRunSoftYanlz/

++++虚拟现实VR资讯: https://blog.csdn.net/VRunSoftYanlz/article/details/89165846

++++HTC_VIVE开发基础https://blog.csdn.net/VRunSoftYanlz/article/details/81989970

++++Oculus杂谈https://blog.csdn.net/VRunSoftYanlz/article/details/82469850

++++Oculus安装使用https://blog.csdn.net/VRunSoftYanlz/article/details/82718982

++++Unity+SteamVR=>VRhttps://blog.csdn.net/VRunSoftYanlz/article/details/88809370

++++Unity减少VR晕眩症https://blog.csdn.net/VRunSoftYanlz/article/details/89115518

++++SteamVR简介https://blog.csdn.net/VRunSoftYanlz/article/details/86484254

++++SteamVR脚本功能分析https://blog.csdn.net/VRunSoftYanlz/article/details/86531480

++++SteamVR2.0开发指南https://blog.csdn.net/VRunSoftYanlz/article/details/86618187

++++SteamVR2.2.0开发指南https://blog.csdn.net/VRunSoftYanlz/article/details/88784527

++++SteamVR2.2.0快速入门https://blog.csdn.net/VRunSoftYanlz/article/details/88833579

++++SteamVR2.2.0交互系统https://blog.csdn.net/VRunSoftYanlz/article/details/89199778

++++SteamVR2.2.0官方教程https://blog.csdn.net/VRunSoftYanlz/article/details/89324067

++++SteamVR/Extrashttps://blog.csdn.net/VRunSoftYanlz/article/details/86584108

++++SteamVR/Inputhttps://blog.csdn.net/VRunSoftYanlz/article/details/86601950

++++OpenXR简介https://blog.csdn.net/VRunSoftYanlz/article/details/85726365

++++VRTK杂谈https://blog.csdn.net/VRunSoftYanlz/article/details/82562993

++++VRTK快速入门(杂谈)https://blog.csdn.net/VRunSoftYanlz/article/details/82955267

++++VRTK官方示例(目录)https://blog.csdn.net/VRunSoftYanlz/article/details/82955410

++++VRTK代码结构(目录)https://blog.csdn.net/VRunSoftYanlz/article/details/82780085

++++VRTK(SceneResources)https://blog.csdn.net/VRunSoftYanlz/article/details/82795400

++++VRTK_ControllerEventshttps://blog.csdn.net/VRunSoftYanlz/article/details/83099512

++++VRTK_InteractTouchhttps://blog.csdn.net/VRunSoftYanlz/article/details/83120220

++++虚拟现实行业应用https://blog.csdn.net/VRunSoftYanlz/article/details/88360157

++++Steam平台上的VRhttps://blog.csdn.net/VRunSoftYanlz/article/details/88960085

++++Steam平台热销VRhttps://blog.csdn.net/VRunSoftYanlz/article/details/89007741

++++VR实验:以太网帧的构成https://blog.csdn.net/VRunSoftYanlz/article/details/82598140

++++实验四:存储器扩展实验https://blog.csdn.net/VRunSoftYanlz/article/details/87834434

++++FrameVR示例V0913https://blog.csdn.net/VRunSoftYanlz/article/details/82808498

++++FrameVR示例V1003https://blog.csdn.net/VRunSoftYanlz/article/details/83066516

++++SwitchMachineV1022https://blog.csdn.net/VRunSoftYanlz/article/details/83280886

++++PlaySceneManagerV1022https://blog.csdn.net/VRunSoftYanlz/article/details/83280886

++++Unity5.x用户手册https://blog.csdn.net/VRunSoftYanlz/article/details/81712741

++++Unity面试题ABChttps://blog.csdn.net/vrunsoftyanlz/article/details/78630687

++++Unity面试题Dhttps://blog.csdn.net/VRunSoftYanlz/article/details/78630838

++++Unity面试题Ehttps://blog.csdn.net/vrunsoftyanlz/article/details/78630913

++++Unity面试题Fhttps://blog.csdn.net/VRunSoftYanlz/article/details/78630945

++++Cocos2dx面试题https://blog.csdn.net/VRunSoftYanlz/article/details/78630967

++++禅道[zentao]https://blog.csdn.net/VRunSoftYanlz/article/details/83964057

++++Lua快速入门篇(Xlua拓展):https://blog.csdn.net/VRunSoftYanlz/article/details/81173818

++++Lua快速入门篇(XLua教程):https://blog.csdn.net/VRunSoftYanlz/article/details/81141502

++++Lua快速入门篇(基础概述)https://blog.csdn.net/VRunSoftYanlz/article/details/81041359

++++框架知识点https://blog.csdn.net/VRunSoftYanlz/article/details/80862879

++++游戏框架(UI框架夯实篇)https://blog.csdn.net/vrunsoftyanlz/article/details/80781140

++++游戏框架(初探篇)https://blog.csdn.net/VRunSoftYanlz/article/details/80630325

++++.Net框架设计https://blog.csdn.net/VRunSoftYanlz/article/details/87401225

++++从零开始学架构https://blog.csdn.net/VRunSoftYanlz/article/details/88095895

++++设计模式简单整理https://blog.csdn.net/vrunsoftyanlz/article/details/79839641

++++专题:设计模式(精华篇)https://blog.csdn.net/VRunSoftYanlz/article/details/81322678

++++U3D小项目参考https://blog.csdn.net/vrunsoftyanlz/article/details/80141811

++++Unity小游戏算法分析https://blog.csdn.net/VRunSoftYanlz/article/details/87908365

++++Unity案例(Vehicle)https://blog.csdn.net/VRunSoftYanlz/article/details/82355876

++++UML类图https://blog.csdn.net/vrunsoftyanlz/article/details/80289461

++++PowerDesigner简介https://blog.csdn.net/VRunSoftYanlz/article/details/86500084

++++Unity知识点0001https://blog.csdn.net/vrunsoftyanlz/article/details/80302012

++++Unity知识点0008https://blog.csdn.net/VRunSoftYanlz/article/details/81153606

++++U3D_Shader编程(第一篇:快速入门篇)https://blog.csdn.net/vrunsoftyanlz/article/details/80372071

++++U3D_Shader编程(第二篇:基础夯实篇)https://blog.csdn.net/vrunsoftyanlz/article/details/80372628

++++Unity引擎基础https://blog.csdn.net/vrunsoftyanlz/article/details/78881685

++++Unity面向组件开发https://blog.csdn.net/vrunsoftyanlz/article/details/78881752

++++Unity物理系统https://blog.csdn.net/vrunsoftyanlz/article/details/78881879

++++Unity2D平台开发https://blog.csdn.net/vrunsoftyanlz/article/details/78882034

++++UGUI基础https://blog.csdn.net/vrunsoftyanlz/article/details/78884693

++++UGUI进阶https://blog.csdn.net/vrunsoftyanlz/article/details/78884882

++++UGUI综合https://blog.csdn.net/vrunsoftyanlz/article/details/78885013

++++Unity动画系统基础https://blog.csdn.net/vrunsoftyanlz/article/details/78886068

++++Unity动画系统进阶https://blog.csdn.net/vrunsoftyanlz/article/details/78886198

++++Navigation导航系统https://blog.csdn.net/vrunsoftyanlz/article/details/78886281

++++Unity特效渲染https://blog.csdn.net/vrunsoftyanlz/article/details/78886403

++++Unity数据存储https://blog.csdn.net/vrunsoftyanlz/article/details/79251273

++++Unity中Sqlite数据库https://blog.csdn.net/vrunsoftyanlz/article/details/79254162

++++WWW类和协程https://blog.csdn.net/vrunsoftyanlz/article/details/79254559

++++Unity网络https://blog.csdn.net/vrunsoftyanlz/article/details/79254902

++++Unity资源加密https://blog.csdn.net/VRunSoftYanlz/article/details/87644514

++++PhotonServer简介https://blog.csdn.net/VRunSoftYanlz/article/details/86652770

++++编写Photon游戏服务器https://blog.csdn.net/VRunSoftYanlz/article/details/86682935

++++C#事件https://blog.csdn.net/vrunsoftyanlz/article/details/78631267

++++C#委托https://blog.csdn.net/vrunsoftyanlz/article/details/78631183

++++C#集合https://blog.csdn.net/vrunsoftyanlz/article/details/78631175

++++C#泛型https://blog.csdn.net/vrunsoftyanlz/article/details/78631141

++++C#接口https://blog.csdn.net/vrunsoftyanlz/article/details/78631122

++++C#静态类https://blog.csdn.net/vrunsoftyanlz/article/details/78630979

++++C#中System.String类https://blog.csdn.net/vrunsoftyanlz/article/details/78630945

++++C#数据类型https://blog.csdn.net/vrunsoftyanlz/article/details/78630913

++++Unity3D默认的快捷键https://blog.csdn.net/vrunsoftyanlz/article/details/78630838

++++游戏相关缩写https://blog.csdn.net/vrunsoftyanlz/article/details/78630687

++++UnityAPI.Rigidbody刚体https://blog.csdn.net/VRunSoftYanlz/article/details/81784053

++++UnityAPI.Material材质https://blog.csdn.net/VRunSoftYanlz/article/details/81814303

++++UnityAPI.Android安卓https://blog.csdn.net/VRunSoftYanlz/article/details/81843193

++++UnityAPI.AndroidJNI安卓JNIhttps://blog.csdn.net/VRunSoftYanlz/article/details/81879345

++++UnityAPI.Transform变换https://blog.csdn.net/VRunSoftYanlz/article/details/81916293

++++UnityAPI.WheelCollider轮碰撞器https://blog.csdn.net/VRunSoftYanlz/article/details/82356217

++++UnityAPI.Resources资源https://blog.csdn.net/VRunSoftYanlz/article/details/83155518

++++JSON数据结构https://blog.csdn.net/VRunSoftYanlz/article/details/82026644

++++CocosStudio快速入门https://blog.csdn.net/VRunSoftYanlz/article/details/82356839

++++Unity企业内训(目录)https://blog.csdn.net/VRunSoftYanlz/article/details/82634668

++++Unity企业内训(第1讲)https://blog.csdn.net/VRunSoftYanlz/article/details/82634733

++++Unity企业内训(第2讲)https://blog.csdn.net/VRunSoftYanlz/article/details/82861180

++++Unity企业内训(第3讲)https://blog.csdn.net/VRunSoftYanlz/article/details/82927699

++++Unity企业内训(第4讲)https://blog.csdn.net/VRunSoftYanlz/article/details/83479776

++++Unity企业内训(第5讲)https://blog.csdn.net/VRunSoftYanlz/article/details/83963811

++++Unity企业内训(第6讲)https://blog.csdn.net/VRunSoftYanlz/article/details/84207696

++++钻哥带您了解产品原型https://blog.csdn.net/VRunSoftYanlz/article/details/87303828

++++插件https://blog.csdn.net/VRunSoftYanlz/article/details/83963905

++++计算机组成原理(教材篇)https://blog.csdn.net/VRunSoftYanlz/article/details/82719129

++++5G接入:云计算和雾计算https://blog.csdn.net/VRunSoftYanlz/article/details/88372718

++++云计算通俗讲义https://blog.csdn.net/VRunSoftYanlz/article/details/88652803

++++立钻哥哥Unity 学习空间: http://blog.csdn.net/VRunSoftYanlz/

--_--VRunSoft:lovezuanzuan--_--ww4ww--_--

《SteamVR2.2.0官方教程(一)》(Yanlz+Unity+XR+VR+AR+MR+SteamVR+Valve+Oculus+Tutorials+Interaction+立钻哥哥++ok++)_第55张图片

你可能感兴趣的:(SteamVR)