SteamVR脚本功能分析 |
版本 |
作者 |
参与者 |
完成日期 |
备注 |
SteamVR_Functions_V01_1.0 |
严立钻 |
|
2019.01.16 |
|
|
|
|
|
|
##《SteamVR脚本功能分析》发布说明:
++++“SteamVR脚本功能分析”:是对SteamVR中脚本功能的介绍;(2019年度的重点技术突破点确立为:“SteamVR”,所以对SteamVR脚本功能的熟悉是非常关键的!)
++++“SteamVR脚本功能分析”:定位在一个介绍类说明,是立钻哥哥在探索SteamVR过程中的总结;
++++OpenVR的Github:https://github.com/ValveSoftware/openvr
++++OpenXR官网:https://www.khronos.org/openxr
++++SteamVR的Github:https://github.com/ValveSoftware/steamvr_unity_plugin
##《SteamVR脚本功能分析》目录
#第一篇:网络杂谈篇
#第二篇:视频杂谈篇
#第三篇:文档杂谈篇
#第四篇:项目杂谈篇
#第一篇:网络杂谈篇 |
#第一篇:网络杂谈篇
++++立钻哥哥:“网络杂谈篇”是对SteamVR脚本知识的全网搜索,利用“SteamVR脚本”;
++++A.1、SteamVR插件脚本详解
++++A.2、
++++A.3、
++++A.4、
++++A.5、
++SteamVR场景应用
++++立钻哥哥:开始研究学习SteamVR脚本功能前,我们先来看看SteamVR的作品吧:
##A.1、SteamVR插件脚本详解 |
++A.1、SteamVR插件脚本详解
++++立钻哥哥:是不是一脸懵逼呀,好吧,从什么地方开始呢?
++++先附上一张SteamVR的目录结构,找一下感觉!!!
++SteamVR目录结构
++++立钻哥哥:看了目录结构后,是不是还是没有方向?
++++那好,我们来Xmind分析一下:
++SteamVR/Scripts/下脚本功能说明
++++立钻哥哥:好吧,看完SteamVR的整体目录结构后,我们再来看一下“/Scripts/”目录吧;
++++还是利用Xmind分析一下:
++SteamVR/Extra/下脚本功能说明
++++立钻哥哥:好吧,Xmind分析了一下“/Scripts/”,那我们接着看一下“SteamVR/Extras/”目录下的脚本吧;
++++还是利用Xmind分析一下:
++[SteamVR/Extras/SteamVR_GazeTracker.cs]
++++立钻哥哥:\Assets\SteamVR\Extras\SteamVR_GazeTracker.cs
++++[SteamVR_GazeTracker.cs]:提供凝视时的事件;
using UnityEngine; using System.Collections;
namespace Valve.VR.Extras{ public class SteamVR_GazeTracker : MonoBehaviour{ public bool isInGaze = false; //当前是否处于gaze状态
//进入gaze状态回调,使用者可以通过代码添加自己的事件处理方法 public event GazeEventHandler GazeOn; public event GazeEventHandler GazeOff; //离开gaze状态回调
//定义的进入gaze与离开gaze的距离范围 public float gazeInCutoff = 0.15f; public float gazeOutCutoff = 0.4f;
protected Transform hmdTrackedObject = null; //头显的transform对象
public virtual void OnGazeOn(GazeEventArgs gazeEventArgs){} public virtual void OnGazeOff(GazeEventArgs gazeEventArgs){}
protected virtual void Update(){}
public struct GazeEventArgs{ public float distance; }
public delegate void GazeEventHandler(object sender, GazeEventArgs gazeEventArgs);
} //立钻哥哥:public class SteamVR_GazeTracker:MonoBehaviour{} } //立钻哥哥:namespace Valve.VR.Extras{} |
++++这个脚本的作用是判断当前物体是否被用户(头显)所注视,进入注视和离开注视都会有回调;
++++处于注视状态的物体与实际注视点的距离范围定义为小于0.15米,而离开注视状态的距离范围为大于0.4米;
++++之所以有一个大概的范围,并且使用了一个平面来相交,是因为注视这个动作时比较粗略的,玩家比较难能精确注视;
++++Gaze回调的事件结构体,只有一个参数,即距离,表示凝视点与物体(中心)的距离;
++++好吧,那我们好好看看这个脚本具体是怎么样的吧:
using UnityEngine; using System.Collections;
namespace Valve.VR.Extras{ public class SteamVR_GazeTracker : MonoBehaviour{ public bool isInGaze = false; //当前是否处于gaze状态
//进入gaze状态回调,使用者可以通过代码添加自己的事件处理方法 public event GazeEventHandler GazeOn; public event GazeEventHandler GazeOff; //离开gaze状态回调
//定义的进入gaze与离开gaze的距离范围 public float gazeInCutoff = 0.15f; public float gazeOutCutoff = 0.4f;
protected Transform hmdTrackedObject = null; //头显的transform对象
public virtual void OnGazeOn(GazeEventArgs gazeEventArgs){ //如果有注册GazeOn回调,则调用它 if(null != GazeOn){ GazeOn(this, gazeEventArgs); } }
public virtual void OnGazeOff(GazeEventArgs gazeEventArgs){ //如果有注册GazeOff回调,则调用它 if(null != GazeOff){ GazeOff(this, gazeEventArgs); } }
protected virtual void Update(){ //If we haven’t set up hmdTrackedObject find what the user is looking at if(null == hmdTrackedObject){ //立钻哥哥:首次调用会去查找头显,方法是查找所有SteamVR_TrackedObject对象;所有的跟踪对象(比如头显、手柄、基站)都是SteamVR_TrackedObject对象(相应的对象上附加了SteamVR_TrackedObject脚本) SteamVR_TrackedObject[] trackedObjects = FindObjectOfType<SteamVR_TrackedObject>(); foreach(SteamVR_TrackedObject tracked in trackedObject){ if(tracked.index == SteamVR_TrackedObject.EIndex.Hmd){ //立钻哥哥:找到头显设备,取其transform对象;头显设备的索引是0号索引; hmdTrackedObject = tracked.transform; break; } } } //立钻哥哥:if(null == hmdTrackedObject){}
if(hmdTrackedObject){ //立钻哥哥:构造一条从头显正方向的射线 Ray ray = new Ray(hmdTrackedObject.position, hmdTrackedObject.forward);
//立钻哥哥:构造一个头显正方向,在当前物体位置的平面 Plane plane = new Plane(hmdTrackedObject.forward, transform.position);
//立钻哥哥:射线与物体平面正向相交,返回的enter为沿射线的距离;如果不相交,或者反向相交,则下面的Raycast返回false; float enter = 0.0f; if(plane.Raycast(ray, out enter)){ //立钻哥哥:intersect为射线与物体平面在三维空间的交点 Vector3 intersect = hmdTrackedObject.position + hmdTrackedObject.forward * enter;
//立钻哥哥:计算空间两点的距离,即物体当前位置与交点的距离 float dist = Vector3.Distance(intersect, transform.position); //Debug.Log(“立钻哥哥:Gaze dist =” + dist);
if(dist < gazeInCutoff && !isInGaze){ //立钻哥哥:当前物体与凝视点的距离小于0.15米,则认为进入gaze状态 isInGaze = true; GazeEventArgs gazeEventArgs; gazeEventArgs.distance = dist; OnGazeOn(gazeEventArgs);
}else if(dist >= gazeOutCutoff && isInGaze){ //立钻哥哥:当前物体与凝视点的距离超过0.4米,则认为离开gaze状态 isInGaze = false; GazeEventArgs gazeEventArgs; gazeEventArgs.distance = dist; OnGazeOff(gazeEventArgs); } } //立钻哥哥:if(plane.Raycast(ray, out enter)){} } //立钻哥哥:if(hmdTrackedObject){} } //立钻哥哥:protected virtual void Update(){}
public struct GazeEventArgs{ public float distance; }
public delegate void GazeEventHandler(object sender, GazeEventArgs gazeEventArgs);
} //立钻哥哥:public class SteamVR_GazeTracker:MonoBehaviour{} } //立钻哥哥:namespace Valve.VR.Extras{} |
++++[GazeTracker]是通过头显的正视方向与物体相交来计算交点的;
++SteamVR_LaserPointer.cs(??已弃用??)
++++立钻哥哥:这个脚本(SteamVR_LaserPointer.cs)在新版本中已弃用,可作为一个参考;
public class SteamVR_LaserPointer : MonoBehaviour{ public bool active = true; public Color color; //激光的颜色
//激光束的粗细(创建了一个立方体,按下面的scale, x, y是0.002,z是100,就能看到是一条很长的细线了) public float thickness = 0.002f;
public GameObject holder; //一个空的GameObject, 用于做激光束的parent
//激光束本身,是用一个立方体来长来模拟的(立钻哥哥:为啥不用圆柱体?显然立方体要比圆柱体渲染简单得多,在很细的情况下,用立方体是明智的选择) public GameObject pointer;
bool isActive = false; //用来判断是否第一次调用
//这个是暴露在Inspector中的属性,用于控制是否给激光束(长方体)添加刚体;光线本身是没有重量的,没有必要添加刚体吧? 所以这里缺省是false; public bool addRigidBody = false;
public Transform reference;
//用于触发激光命中和离开事件 public Event PointerEventHandler PointerIn; public Event PointerEventHandler PointerOut;
//上次激光命中的物体的transform对象,用于判断是否命中同一个物体 Transform previousContact = null;
void Start(){}
public virtual void OnPointerIn(PointerEventArgs e){} public virtual void OnPointerOut(PointerEventArgs e){}
void Update(){}
} //立钻哥哥:public class SteamVR_LaserPointer:MonoBehaviour{}
public struct PointerEventArgs{}
public delegate void PointerEventHandler(object sender, PointerEventArgs e);
|
++++[LaserPointer]通过所谓的激光束来与物体相交的;激光束就是手柄指向的方向,可以在游戏里面把这个方向渲染出一条激光束出来,特别是在通过手柄进行菜单的UI操作的时候;
++++立钻哥哥:好吧,接下来我们来好好看一下这个脚本吧:
public class SteamVR_LaserPointer : MonoBehaviour{ public bool active = true; public Color color; //激光的颜色
//激光束的粗细(创建了一个立方体,按下面的scale, x, y是0.002,z是100,就能看到是一条很长的细线了) public float thickness = 0.002f;
public GameObject holder; //一个空的GameObject, 用于做激光束的parent
//激光束本身,是用一个立方体来长来模拟的(立钻哥哥:为啥不用圆柱体?显然立方体要比圆柱体渲染简单得多,在很细的情况下,用立方体是明智的选择) public GameObject pointer;
bool isActive = false; //用来判断是否第一次调用
//这个是暴露在Inspector中的属性,用于控制是否给激光束(长方体)添加刚体;光线本身是没有重量的,没有必要添加刚体吧? 所以这里缺省是false; public bool addRigidBody = false;
public Transform reference;
//用于触发激光命中和离开事件 public Event PointerEventHandler PointerIn; public Event PointerEventHandler PointerOut;
//上次激光命中的物体的transform对象,用于判断是否命中同一个物体 Transform previousContact = null;
void Start(){ //在脚本被加载的时候,做一些初始化
//首先创建一个holder(即激光束的父物体) holder = new GameObject();
//holder的transform的parent设为当前脚本所在的物体(通常这个脚本会加到控制器手柄上面) holder.transform.parent = this.transform;
//位置设在0点(本地坐标系,相对于父亲) holder.transform.localPosition = Vector3.zero; holder.transform.localRotation = Quaternion.identity;
//创建激光束,用长方体模拟 pointer = GameObject.CreatePrimitive(PrimitiveType.Cube);
//将父亲设为上面的holder pointer.transform.parent = holder.transform;
//设置localScale为(0.002, 0.002, 100),看起来就是一条很长的线 pointer.transform.localScale = new Vector3(thickness, thickness, 100f);
//立钻哥哥:位置设在父亲的(0, 0, 50)位置,因为对于立方体(长方体),其中心在立方体中心,因为上面被放大到了100倍,那移动位置到(0, 0, 50)可以让激光束的起点为父亲; pointer.transform.localPosition = new Vector3(0f, 0f, 50f); pointer.transform.localRotation = Quaternion.identity;
//立钻哥哥:如果指定了addRigidBody为true,则为激光束添加一个刚体,对应的Collider则只设为触发器(不会执行碰撞,但会进入代码);否则,会把Collider销毁掉,也就是不需要Collider; BoxCollider collider = pointer.GetComponent<BoxCollider>(); if(addRigidBody){ if(collider){ collider.isTrigger = true; } Rigidbody rigidbody = pointer.AddComponent<Rigidbody>(); rigidbody.isKinematic = true;
}else{ if(collider){ Object.Destroy(collider); } }
//新建纯色材质并添加到MeshRender中;Color值通过Inspector设置; Material newMaterial = new Material(Shader.Find(“Unlit/Color”)); newMaterial.SetColor(“_Color”, color); pointer.GetComponent<MeshRender>().material = newMaterial; }
public virtual void OnPointerIn(PointerEventArgs e){ //立钻哥哥:回调激光命中 委托 if(null != PointerIn){ PointerIn(this, e); } }
public virtual void OnPointerOut(PointerEventArgs e){ //立钻哥哥:回调激光不在命中 委托 if(null != PointerOut){ PointerOut(this, e); } }
void Update(){ if(!isActive){ //立钻哥哥:第一次调用时将holder设为active(当前物体transform的第一个child就是holder) isActive = true; this.transform.GetChild(0).gameObject.SetActive(true); }
//命中物体(或者说激光束)的最远距离记为100米 float dist = 100f;
//当前物体(手柄上)上还要挂一个SteamVR_TrackedController脚本 SteamVR_TrackedController controller = GetComponent<SteamVR_TrackedController>();
//构造一条射线 Ray raycast = new Ray(transform.position, transform.forward); RaycastHit hit;
//计算射线命中的场景中的物体 bool bHit = Physics.Raycast(raycast, out hit);
if(previousContact && previousContact != hit.transform){ //立钻哥哥:如果之前已经有一个命中的物体,而当前命中的物体发生了变化,那么说明前一个命中的物体就要收到一个不再命中的通知 PointerEventArgs args = new PointerEventArgs(); if(null != controller){ args.controllerIndex = controller.controllerIndex; } args.distance = 0f; args.flags = 0; args.target = previousContact; OnPointerOut(args); previousContact = null; } //立钻哥哥:if(previousContact && previousContact != hit.transform){}
if(bHit && previousContact != hit.transform){ //通知命中新的物体 PointerEventArgs argsIn = new PointerEventArgs(); if(null != controller){ argsIn.controllerIndex = controller.controllerIndex; }
//hit.distance为射线原点到命中点的距离 argsIn.distance = hit.distance; argsIn.flags = 0;
//target记录的是命中物体的transform argsIn.target = hit.transform; OnPointerIn(argsIn);
//记录上一次命中的物体的transform previousContact = hit.transform;
} //立钻哥哥:if(bHit && previousContact != hit.transform){}
if(!bHit){ previousContact = null; }
if(bHit && hit.distance < 100f){ //如果命中物体距离小于100,则记录下来,否则最远就是100米 dist = hit.distance; }
if(controller != null && controller.triggerPressed){ //立钻哥哥:当按下扳机键时,将光束的粗细增大5倍,同时长度会设为dist,这样看起来光束就会到命中点截止,不会穿透物体 pointer.transform.localScale = new Vector3(thickness * 5f, thickness * 5f, dist);
}else{ //按下扳机或者当前控制器没有添加SteamVR_TrackedController时,显示原始粗细的光束 pointer.transform.localScale = new Vector3(thickness, thickness, dist); }
//立钻哥哥:光束的位置总是设在光束长度的一半的位置,使得光束看起来总是从手柄发出来的 pointer.transform.localPosition = new Vector3(0f, 0f, dist/2f);
} //立钻哥哥:void Update(){}
} //立钻哥哥:public class SteamVR_LaserPointer:MonoBehaviour{}
public struct PointerEventArgs{ public uint controllerIndex; //控制器(手柄)索引 public uint flags; public float distance; //激光原点到命中点(交点)的距离 public Transform target; //命中物体的transform对象 }
public delegate void PointerEventHandler(object sender, PointerEventArgs e);
|
++示例:unity_teleport_sample
++++立钻哥哥:teleport瞬移场景:在场景中放一些球,然后在右控制器上做瞬移;做法是从控制器上发出一个激光束,按下扳机键就可以瞬移到激光束指到的地方;通过观察球的相对位置就能看到位置的变化;(一种是慢慢走过去;一种是直接跳过去;还有就是街景地图)
{ public bool teleportOnClick = false; public TeleportType teleportType = TeleportType.TeleportTypeUseZeroY;
Transform reference{ get{ //立钻哥哥:取的是最后渲染(depth最大)的相机(SteamVR_Camera)的原始点(这个origin实际就是将SteamVR_Camera添加到原始场景中的Camera的位置) var top = SteamVR_Render.Top();
//立钻哥哥:SteamVR相机的层次结构是最上层是origin,然后下面有左右手柄和head, head下面有eye和ears return (top != null) ? top.origin : null; } } //立钻哥哥:Transform reference{}
void Start(){ //立钻哥哥:这个脚本所在的物体必须添加SteamVR_TrackedController脚本(这个脚本的作用是将控制器的输入转换为事件回调),如果没有添加,则自动添加;这说明这个脚本所在的物体需要是控制器(手柄); var trackedController = GetComponent(); if(null == trackedController){ trackedController = gameObject.AddComponent(); }
//添加扳机按下的回调 trackedController.TriggerClicked += new ClickedEventHandler(YanlzDoClick); if(teleportType == TeleportType.TeleportTypeUseTerrain){ //Start the player at the level of the terrain var t = reference; if(null != t){ //立钻哥哥:如果是地形类型,会将相机origin(基本上可以认为就是玩家的位置)的Y坐标线调整为地形的采样高度(即相机origin所在位置的地形的实际Y坐标:即将相机origin放到地形表面,也就是在地形表面的垂直投影的位置),这样可以避免人钻到地形里面了 t.position = new Vector3(t.position.x, Terrain.activeTerrain.SampleHeight(t.position), t.position.z); } } //立钻哥哥:if(teleportType==TeleportType.TeleportTypeUseTerrain){} } //立钻哥哥:void Start(){}
void YanlzDoClick(object sender, ClickedEventArgs e){ //立钻哥哥:应该是通过这个变量来控制是否通过扳机键来瞬移,因为扳机键还可以用作其他用途,应该是在某种状态下才能通过扳机键来瞬移,比如:需要通过扳机键来瞬移时才需要将这个变量设为true if(teleportOnClick){ var t = reference; if(null == t){ return; }
float refY = t.position.y
//立钻哥哥:创建一个Y方向,-refY位置的平面(是-refY而不是refY的原因是这个是Plane的distance参数,而Plane的distance是原点到Plane的距离,而距离的正负决定了在平面的哪一边,为正表示原点在法线的正方向,为负表示原点在法线的反方向,这与通常的理解不一样,所以这里为-refY) Plane plane = new Plane(Vector3.up, -refY);
//当前脚本应该绑定在手柄上,因此才会有手柄方向的一条射线 Ray ray = new Ray(this.transform.position, transform.forward);
//hasGroundTarget指:射线是否与地面相交,或者说是否射到了地面上 bool hasGroundTarget = false;
//dist为射线原点(即手柄的原点)与相交点的距离 float dist = 0f; if(teleportType == TeleportType.TeleportTypeUseTerrain){ //立钻哥哥:与地形进行碰撞 RaycastHit hitInfo; TerrainCollider tc = Terrain.activeTerrain.GetComponent(); hasGroundTarget = tc.RayCast(ray, out hitInfo, 1000f); dist = hitInfo.distance;
}else if(teleportType == TeleportType.TeleportTypeUseCollider){ //立钻哥哥:与场景中的碰撞体进行碰撞 RaycastHit hitInfo; Physics.Raycast(ray, out hitInfo); dist = hitInfo.distance;
//立钻哥哥:这里并没有设置hasGroundTarget为true,那后面的瞬移就无法完成,所以设置为TeleportTypeUseCollider应该就不能瞬移(实测确实不可以),那为什么要设置这种类型呢???:从实际意义来说,确实是不能:我们扳机指向哪就瞬移到哪,人不是什么地方都能去的
}else{ //立钻哥哥:与地面(Y方向的一个平面)相交 hasGroundTarget = plane.Raycast(ray, out dist); }
if(hasGroundTarget){ //立钻哥哥:headPosOnGround是head(head就是头显的位置)在地面(Y=0)的投影,注意这里用的是localPosition Vector3 headPosOnGround = new Vector3(SteamVR_Render.Top().head.localPosition.x, 0.0f, SteamVR_Render.Top().head.localPosition.z);
//立钻哥哥:这里就是将origin移动到扳机位置了,ray.origin + ray.direction*dist 得到的就是射线与地形/地面交点的位置;后面减去的两个点分别是手柄(这里取的是第一个子物体,实际上就是左控制器)和头显相对于origin的位置(XZ平面);感觉没有必要减,按照所见即所得,玩家看到的激光束的交点,就直接把位置定到那就好了,不需要考虑头显或手柄的偏移; t.position = ray.origin + ray.direction * dist - new Vector3(t.GetChild(0).localPosition.x, 0f, t.GetChild(0).localPosition.z) - headPosOnGround;
} //立钻哥哥:if(hasGroundTarget){} } //立钻哥哥:if(teleportOnClick){} } //立钻哥哥: void YanlzDoClick(object sender, ClickedEventArgs e){}
public enum TeleportType{ //瞬移类型是根据与地形的交点来确定目的位置的 TeleportTypeUseTerrain,
//碰撞体类型是根据与任何带碰撞体的物体的交点来确定目的位置的 TeleportTypeUseCollider,
//这个是与Y坐标为0的平面(通常就是地面)的交点来确定目的位置的 TeleportTypeUseZeroY } //立钻哥哥:public enum TeleportType{}
} //立钻哥哥:unity_teleport_sample |
++SteamVR_TestThrow.cs
++++立钻哥哥:\Assets\SteamVR\Extras\SteamVR_TestThrow.cs
++++[SteamVR_TestThrow.cs]这个脚本是一个测试IK(更准确地说应该是[SteamVR_IK.cs]的,反向运动,就是根据手柄的运动模拟带动手臂的运动)的示例场景;这个场景里有一个模拟手臂:分左右手,分别在左右两个手柄控制器下面,在场景中的样子是这样的:它这里只有两个关节(肩关节和腕关节,SteamVR_IK就只支持两个关节),然后有一个手指;这个应该是测试通过手柄扔出一个物体的例子,主要是测试[SteamVR_TestThrow.cs]这个脚本,可以看到这个脚本被添加到了左右两个手柄上面:Template这个物体是被扔的物体,它由一个圆及一个子物体立方体组成;通过扳机键创建一个物体并抓在手中,然后通过甩臂并同时松开扳机将物体扔出去;
using UnityEngine; using System.Collections;
namespace Valve.VR.Extras{ [RequireComponent(typeof(SteamVR_TrackedObject))] public class SteamVR_TestThrow : MonoBehaviour{ //要扔掉的物体,并不是一个真正的prefab,而是一个场景中已经创建好的物体 public GameObject prefab;
//立钻哥哥:这个是手柄上tip(手柄模型的一部分)下面的一个rigidbody;在手柄的模型中,所有的子组件(相对于父组件,即整个model)的位置都是(0,0,0),但下面会再带一个attach的子对象,这个子对象是一个刚体,然后真正的位置是通过它来确定的 public Rigidbody attachPoint;
[SteamVR_DefaultAction(“Interact”)] public SteamVR_Action_Boolean spawn;
SteamVR_Behaviour_Pose trackedObj; //手柄这个跟踪对象 FixedJoint joint; //固定关节
private void Awake(){} private void FixedUpdate(){}
} //立钻哥哥:public class SteamVR_TestThrow:MonoBehaviour{} } //立钻哥哥:namespace Valve.VR.Extras{} |
++++立钻哥哥:[SteamVR_TestThrow.cs]这个脚本需要与SteamVR_TrackedObject.cs一起使用;实际上它会加到手柄上;那我们就来看看这个脚本吧:
using UnityEngine; using System.Collections;
namespace Valve.VR.Extras{ [RequireComponent(typeof(SteamVR_TrackedObject))] public class SteamVR_TestThrow : MonoBehaviour{ //要扔掉的物体,并不是一个真正的prefab,而是一个场景中已经创建好的物体 public GameObject prefab;
//立钻哥哥:这个是手柄上tip(手柄模型的一部分)下面的一个rigidbody;在手柄的模型中,所有的子组件(相对于父组件,即整个model)的位置都是(0,0,0),但下面会再带一个attach的子对象,这个子对象是一个刚体,然后真正的位置是通过它来确定的 public Rigidbody attachPoint;
[SteamVR_DefaultAction(“Interact”)] public SteamVR_Action_Boolean spawn;
SteamVR_Behaviour_Pose trackedObj; //手柄这个跟踪对象 FixedJoint joint; //固定关节
private void Awake(){ //立钻哥哥:Awake()函数不管脚本是否启用都会调用 trackedObj = GetComponent }
private void FixedUpdate(){ If(joint == null && spawn.GetStateDown(trackedObj.inputSource)){ //立钻哥哥:如果还没有建立关节,当按下扳机键时,建立物体与手柄的(关节)关联,相当于就是抓起了物体
//先创建了物体(复制了场景中的一个物体) Var go = GameObject.Instantiate(prefab);
//创建的物体的位置位于tip的关联点的位置 Go.transform.position = attachPoint.transform.position;
//添加固定关节,这样物体就能跟随手柄动而动了 Joint = go.AddComponent
//将其与手柄tip的attach关联 Joint.connectedBody = attachPoint;
}else if(){
}
}
} //立钻哥哥:public class SteamVR_TestThrow:MonoBehaviour{} } //立钻哥哥:namespace Valve.VR.Extras{} |
++立钻哥哥推荐的拓展学习链接(Link_Url):
立钻哥哥推荐的拓展学习链接(Link_Url) |
++++立钻哥哥Unity 学习空间: http://blog.csdn.net/VRunSoftYanlz/
++++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
++++SteamVR简介:https://blog.csdn.net/VRunSoftYanlz/article/details/86484254
++++SteamVR脚本功能分析:https://blog.csdn.net/VRunSoftYanlz/article/details/86531480
++++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_ControllerEvents:https://blog.csdn.net/VRunSoftYanlz/article/details/83099512
++++VRTK_InteractTouch:https://blog.csdn.net/VRunSoftYanlz/article/details/83120220
++++VR实验:以太网帧的构成:https://blog.csdn.net/VRunSoftYanlz/article/details/82598140
++++FrameVR示例V0913:https://blog.csdn.net/VRunSoftYanlz/article/details/82808498
++++FrameVR示例V1003:https://blog.csdn.net/VRunSoftYanlz/article/details/83066516
++++SwitchMachineV1022:https://blog.csdn.net/VRunSoftYanlz/article/details/83280886
++++PlaySceneManagerV1022:https://blog.csdn.net/VRunSoftYanlz/article/details/83280886
++++Unity5.x用户手册:https://blog.csdn.net/VRunSoftYanlz/article/details/81712741
++++Unity面试题ABC:https://blog.csdn.net/vrunsoftyanlz/article/details/78630687
++++Unity面试题D:https://blog.csdn.net/VRunSoftYanlz/article/details/78630838
++++Unity面试题E:https://blog.csdn.net/vrunsoftyanlz/article/details/78630913
++++Unity面试题F:https://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
++++设计模式简单整理: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案例(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知识点0001:https://blog.csdn.net/vrunsoftyanlz/article/details/80302012
++++Unity知识点0008:https://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
++++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安卓JNI:https://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/82719129
++++立钻哥哥Unity 学习空间: http://blog.csdn.net/VRunSoftYanlz/
--_--VRunSoft:lovezuanzuan--_--