#创新实训#VR漫游项目汇报

接着,各个成员在各自的博客中落实了三区VR场景漫游项目的规划——

项目时长:4月1日 至 5月31日

团队分工:

常雨晴 手势识别模块

叶子扬 语音识别模块

冯金虎 项目展示模块

肖绍天 虚拟实验室模块,协助项目展示模块

交互设计,美术建模场景设计等工作,具体工作再具体安排。


项目流程:各模块分别进行规划,规划场景规模;加入交互设计,创建场景,编写交互脚本代码;

导入HTC设备进行虚拟体验;整体模块整合,调试;项目最终调试。


实现目标:

再虚拟现实层面的创新实践交互等功能

虚拟软件园三区整体规划展示用平台


接着,各个成员学习并自行搭建了基于unity平台的VR环境——

1.



#创新实训#VR漫游项目汇报_第1张图片

2.


#创新实训#VR漫游项目汇报_第2张图片


#创新实训#VR漫游项目汇报_第3张图片


3.

#创新实训#VR漫游项目汇报_第4张图片


详细脚本解析:

SteamVR_GazeTracker.cs脚本解析 
这个脚本的作用是判断当前物体是否被用户(头显)所注视,进入注视和离开注视都会有回调。处于注视状态的物体与实际注视点的距离范围定义为小于0.15米,而离开注视状态的距离范围为大于0.4米。之所以有一个大概的范围,并且使用了一个平面来相交,是因为注视这个动作是比较粗略的,玩家比较难能精确注视。 
  Gaze回调的事件结构体,只有一个参数,即距离,表示凝视点与物体(中心)的距离


  1. public struct GazeEventArgs  
  2. {  
  3.     public float distance;  
  4. }  
  5.   
  6. public delegate void GazeEventHandler(object sender, GazeEventArgs e);  
  7.   
  8. public class SteamVR_GazeTracker : MonoBehaviour  
  9. {  
  10.     //当前是否处于gaze状态  
  11.     public bool isInGaze = false;  
  12.     //入gaze状态回调,使用者可以通过代码添加自己的事件处理方法(在Inspector      中不会出现)  
  13.     public event GazeEventHandler GazeOn;  
  14.     //离开gaze状态回调  
  15.     public event GazeEventHandler GazeOff;  
  16.     //定义的进入gaze与离开gaze的距离范围  
  17.     public float gazeInCutoff = 0.15f;  
  18.     public float gazeOutCutoff = 0.4f;  
  19.   
  20.     // Contains a HMD tracked object that we can use to find the user's gaze  
  21.     //头显的transform对象  
  22.     Transform hmdTrackedObject = null;  
  23.     // Use this for initialization  
  24.     void Start ()  
  25.     {  
  26.   
  27.     }  
  28.     public virtual void OnGazeOn(GazeEventArgs e)  
  29.     {  
  30.         //如果有注册GazeOff回调,调用它  
  31.         if (GazeOn != null)  
  32.             GazeOn(this, e);  
  33.     }  
  34.     public virtual void OnGazeOff(GazeEventArgs e)  
  35.     {  
  36.   
  37.         //如果有注册GazeOff回调,调用它  
  38.         if (GazeOff != null)  
  39.             GazeOff(this, e);  
  40.     }  
  41.     // Update is called once per frame  
  42.     void Update ()  
  43.     {  
  44.         // If we haven't set up hmdTrackedObject find what the user is looking at  
  45.         if (hmdTrackedObject == null)  
  46.         {  
  47.             //首次调用会去查找头显,方法是查找所有SteamVR_TrackedObject对象。所有的跟踪对象(比如头显、手柄、基站)都是SteamVR_TrackedObject对象(相应的对象上附加了SteamVR_TrackedObject脚本)  
  48.             SteamVR_TrackedObject[] trackedObjects = FindObjectsOfType<SteamVR_TrackedObject>();  
  49.             foreach (SteamVR_TrackedObject tracked in trackedObjects)  
  50.             {  
  51.                 if (tracked.index == SteamVR_TrackedObject.EIndex.Hmd)  
  52.                 {  
  53.                     //找到头显设备,取其transform对象。头显设备的索引是0号索引  
  54.                     hmdTrackedObject = tracked.transform;  
  55.                     break;  
  56.                 }  
  57.             }  
  58.         }  
  59.         if (hmdTrackedObject)  
  60.         {  
  61.             //构造一条从头显正方向的射线  
  62.             Ray r = new Ray(hmdTrackedObject.position, hmdTrackedObject.forward);  
  63.             //构造一个头显正方向、在当前物体位置的平面  
  64.             Plane p = new Plane(hmdTrackedObject.forward, transform.position);  
  65.   
  66.             float enter = 0.0f;  
  67.             //射线与物体平面正向相交,返回的enter为沿射线的距离。如果不相交,或者反向相交,则下面的Raycast返回false  
  68.             if (p.Raycast(r, out enter))  
  69.             {  
  70.                 //intersect为射线与物体平面在三维空间的交点  
  71.                 Vector3 intersect = hmdTrackedObject.position + hmdTrackedObject.forward * enter;  
  72.                 //计算空间两点的距离,即物体当前位置与交点的距离  
  73.                 float dist = Vector3.Distance(intersect, transform.position);  
  74.                 //Debug.Log("Gaze dist = " + dist);  
  75.                 if (dist < gazeInCutoff && !isInGaze)  
  76.                 {  
  77.                     //当前物体与凝视点的距离小于0.15米,则认为进入gaze状态  
  78.                     isInGaze = true;  
  79.                     GazeEventArgs e;  
  80.                     e.distance = dist;  
  81.                     OnGazeOn(e);  
  82.                 }  
  83.                 else if (dist >= gazeOutCutoff && isInGaze)  
  84.                 {  
  85.                     //当前物体与凝视点的距离超过0.4米,则认为离开gaze状态  
  86.                     isInGaze = false;  
  87.                     GazeEventArgs e;  
  88.                     e.distance = dist;  
  89.                     OnGazeOff(e);  
  90.                 }  
  91.             }  
  92.         }  
  93.     }  
  94. }  

这个脚本的作用与上面的SteamVR_GazeTracker相关及类似。GazeTracker是通过头显的正视方向与物体相交来计算交点的。而这里是通过所谓的激光束来与物体相交的。激光束就是手柄指向的方向,可以在游戏里面把这个方向渲染出一条激光束出来,特别是在通过手柄进行菜单的UI操作的时候。在github openvr的sample目录下的unity_teleport_sample示例有使用,它被加到右手柄上 

4.Unity通过旋转手势控制转盘旋转

在VR虚拟场景的物理实验室模块中,我想做一个切割磁感线发电机的模拟装置;为了让用户更加真实的操作设备,让用户通过手柄的旋转手势,实现转盘的同步转动。。原理,获取到需要转动的物体中心的位置,记录鼠标按下的瞬间的位置,按下后计算每帧的鼠标移动的位置,通过这三个位置,计算角度,(即鼠标按下时与物体中心的连线 和 每一帧鼠标位置与物体中心的连线的夹角)。

通过四元数判断旋转的方向的,通过 transform.localEluerAngles方法,控制物体旋转。

#创新实训#VR漫游项目汇报_第5张图片


transform.localEulerAngles = new Vector3(90,0,0);沿x轴指向,逆时针旋转90度。

transform.localEulerAngles = new Vector3(0,90,0);沿y轴指向,逆时针旋转90度。

如果将上述角度改成负数,沿着改变轴的方向,变为顺时针。

源码——

public Camera ca;  
  
    private Quaternion q;  
  
    private Vector3 mousePos;  
    private Vector3 preMousePos;  
    private Vector3 modelPos;  
  
    private Vector3 localEluer;  
  
    private bool IsSelect = false;  
    private float RotateAngle;  
  
    private float angle;  
  
    public Transform target1;  
  
    // Use this for initialization  
    void Start () {  
        modelPos = ca.WorldToScreenPoint(target1.transform.position);  
        angle = localEluer.z;  
        target1.transform.localEulerAngles = localEluer;  
    }  
      
    // Update is called once per frame  
    void Update () {  
  
        if(Input.GetMouseButtonDown (0)){  
            IsSelect = true;  
            preMousePos = mousePos = Input.mousePosition;  
        }  
        if (Input.GetMouseButton (0) && IsSelect) {  
            IsSelect = true;  
            mousePos = Input.mousePosition;  
            RotateAngle = Vector3.Angle (preMousePos - modelPos, mousePos - modelPos);  
            //print (RotateAngle);  
  
            if (RotateAngle == 0) {  
                preMousePos = mousePos;  
            }  
            else {  
                q = Quaternion.FromToRotation (preMousePos - modelPos,mousePos - modelPos);  
                float k = q.z > 0 ? 1 : -1;  
                localEluer.z += k * RotateAngle;  
  
                Debug.Log (localEluer.x);  
  
                angle = localEluer.z = Mathf.Clamp (localEluer.z,-36000,36000);  
  
                target1.transform.localEulerAngles = localEluer;  
                preMousePos = mousePos;  
            }  
  
        }  
        if(Input.GetMouseButtonUp(0)){  
            IsSelect = false;  
        }  
    }  

你可能感兴趣的:(实训)