美文网首页Unity技术VR/AR分享Unity教程合集
26 VR开发—— HTC Vive瞬移功能的实现

26 VR开发—— HTC Vive瞬移功能的实现

作者: _谭小坤 | 来源:发表于2017-03-07 10:14 被阅读252次

    一、为什么要实现瞬移这个功能##

    因为HTC Vive活动范围有限制(3m * 5m),所以我们在实际的使用中,为了更好的浏览场景,查看场景,会使用这种移动的方式,达到游戏中的视野移动。
    一般来说就是手柄选取一个位置,通过扳机键确认移动。
    移动的方式有两种:一种是水平移动即X,Z轴移动;另一种就是垂直移动,即Y轴移动。

    二、实现过程##

    这瞬移过程中最重要的是拿到目标位置的坐标,我们可以通过射线检测拿到位置.
    在Steam VR插件给我们提供了封装好的类与方法,我们做出相应的改变得到我们需要的结果.
    
    射线检测脚本
    重写代码展示:
    using UnityEngine;
    using System.Collections;
    
    //public struct PointerEventArgs
    //{
    //    public uint controllerIndex;
    //    public uint flags;
    //    public float distance;
    //    public Transform target;
    //}
    
    //public delegate void PointerEventHandler(object sender, PointerEventArgs e);
    
    
    
    public class Test_LaserPointer : MonoBehaviour
    {
        public bool active = true;
        public Color color;
        public float thickness = 0.002f;
        public GameObject holder;
        public GameObject pointer;
        bool isActive = false;
        public bool addRigidBody = false;
        public Transform reference;
        public event PointerEventHandler PointerIn;
        public event PointerEventHandler PointerOut;
    
        public Vector3 HitPoint;//添加的量找到目标位置
        Transform previousContact = null;
    
        // Use this for initialization
        void Start ()
        {
            holder = new GameObject();
            holder.transform.parent = this.transform;
            holder.transform.localPosition = Vector3.zero;
            holder.transform.localRotation = Quaternion.identity;
    
            pointer = GameObject.CreatePrimitive(PrimitiveType.Cube);
            pointer.transform.parent = holder.transform;
            pointer.transform.localScale = new Vector3(thickness, thickness, 100f);
            pointer.transform.localPosition = new Vector3(0f, 0f, 50f);
            pointer.transform.localRotation = Quaternion.identity;
            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);
                }
            }
            Material newMaterial = new Material(Shader.Find("Unlit/Color"));
            newMaterial.SetColor("_Color", color);
            pointer.GetComponent<MeshRenderer>().material = newMaterial;
        }
    
        public virtual void OnPointerIn(PointerEventArgs e)
        {
            if (PointerIn != null)
                PointerIn(this, e);
        }
    
        public virtual void OnPointerOut(PointerEventArgs e)
        {
            if (PointerOut != null)
                PointerOut(this, e);
        }
    
    
        // Update is called once per frame
        void Update ()
        {
            if (!isActive)
            {
                isActive = true;
                this.transform.GetChild(0).gameObject.SetActive(true);
            }
    
            float dist = 100f;
    
            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 (controller != null)
                {
                    args.controllerIndex = controller.controllerIndex;
                }
                args.distance = 0f;
                args.flags = 0;
                args.target = previousContact;
                OnPointerOut(args);
                previousContact = null;
            }
            if(bHit && previousContact != hit.transform)
            {
                PointerEventArgs argsIn = new PointerEventArgs();
                if (controller != null)
                {
                    argsIn.controllerIndex = controller.controllerIndex;
                }
                argsIn.distance = hit.distance;
                argsIn.flags = 0;
                argsIn.target = hit.transform;
                OnPointerIn(argsIn);
                previousContact = hit.transform;
            }
            if(!bHit)
            {
                previousContact = null;
            }
            if (bHit && hit.distance < 100f)
            {
                dist = hit.distance;
            }
    
            if (bHit)//添加的实现代码;
            {
                HitPoint = hit.point;
            }
    
            if (controller != null && controller.triggerPressed)
            {
                pointer.transform.localScale = new Vector3(thickness * 5f, thickness * 5f, dist);
            }
            else
            {
                pointer.transform.localScale = new Vector3(thickness, thickness, dist);
            }
            pointer.transform.localPosition = new Vector3(0f, 0f, dist/2f);
        }
    }
    
    
    SteamVR_TrackedController脚本
    下面就是自己写代码实现瞬移过程:
    代码展示及逻辑:
    public class Test_Teleporter : MonoBehaviour {
    
        // 拿到手柄对象
        public GameObject LeftController;
        //修改后的射线检测脚本
        private Test_LaserPointer Pointer;
        // 右手柄的控制器
        private SteamVR_TrackedController LeftSt;
        // 事件调用函数
        ClickedEventHandler ce;
        // 当前的目标位置
        Transform currentTransform;
        // 碰撞事件
        PointerEventArgs arg;
        void Start()
        {
            Pointer = LeftController.GetComponent<Test_LaserPointer>();
            LeftSt = LeftController.GetComponent<SteamVR_TrackedController>();
            // 利用Laserpoint里面的事件函数来检测目标位置
            Pointer.PointerIn += LeftPointIn;
            //  利用Laserpoint里面的事件函数来检测目标位置
            Pointer.PointerOut += LeftPointOut;
            // 利用手柄控制器来检测我们的扳机事件
            LeftSt.TriggerClicked += TriggerClicked;
        }
    
        // 没有检测到碰撞信息
        void LeftPointOut(object sender, PointerEventArgs e)
        {   // 当前位置没有
            currentTransform = null;
        }
        // 检测到碰撞信息
        void LeftPointIn(object sender, PointerEventArgs e)
        {   // 设置目标位置为检测到的目标
            currentTransform = e.target;
        }
        // 扳机事件
        void TriggerClicked(object sender, ClickedEventArgs e)
        {
            // 如果检测到目标位置
            if (currentTransform != null)
            {    // 移动
                this.gameObject.transform.position = new Vector3(Pointer.HitPoint.x - LeftController.transform.localPosition.x, Pointer.HitPoint.y, Pointer.HitPoint.z - LeftController.transform.localPosition.z);
            }
        }
    }
    
    

    三、结果实现##

    挂载脚本,实现结果

    相关文章

      网友评论

        本文标题:26 VR开发—— HTC Vive瞬移功能的实现

        本文链接:https://www.haomeiwen.com/subject/wzwugttx.html