Unity基于Nolo开发非VR桌面2D应用

相信很多VR开发者都用过Nolo开发过6dofVR应用,但是今天我想别处心裁,说一下如何用Nolo开发普通桌面应用。

首先,我们需要一套Nolo CV1 Pro(注意:只有这套设备才支持普通桌面应用开发哦,其他几款暂不支持);

然后,我们需要下载一个官方支持程序Nolo Home,此程序安装的时候会相应的安装一些驱动,安装时选择默认安装路径就可以。

软件安装完成之后去GitHub上下载Unity的SDK,下载完成之后解压,然后新建工程,打开解压后的文件夹,找到Nolo-Nomal文件夹里的UnityPackage中的package包,并将其导入新建的Unity工程。新建一个脚本TwoDSceneTest,然后写下相关的交互逻辑,代码中涉及到世界坐标转画布坐标,放大缩小,UI拖动等,因涉及到公司项目,不能上传整个工程,在此将主要源码奉上。

using NoloClientCSharp;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class TwoDSceneTest : MonoBehaviour
{
    public Camera uiCamera;
    public NoloVR_SimplePointer rightPointer;
    public NoloVR_SimplePointer leftPointer;
    public Transform rightHandTrans, leftHandTrans;
    [SerializeField]
    private Image rightHand;
    [SerializeField]
    private Image leftHand;
    [SerializeField]
    private Sprite leftHandReleaseSprite, leftHandGripSprite, rightHandReleaseSprite, rightHandGripSprite, rightHandClickSprite;

    public List imagItemList;

    public RectTransform uiCanvas;

    public Transform rightHandParent;

    public Transform uiRoot;

    private float touchX = 0;

    private float delayTime = 0;

    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        try
        {

            if (NoloVR_System.GetInstance().realTrackDevices == 3)
            {
                
                Debug.Log("NoloVR_System.GetInstance().realTrackDevices:  " + NoloVR_System.GetInstance().realTrackDevices);
            }
            else
            {                

                if (rightPointer != null)
                {
                    float x = rightPointer.pointer.transform.position.x;
                    float y = rightPointer.pointer.transform.position.y;
                    float z = rightPointer.pointer.transform.position.z;
                    Vector2 screenPos = WorldToUgui(uiCanvas, new Vector3(x,y,z));
                    Debug.Log(WorldToUgui(uiCanvas, rightPointer.pointer.transform.position).x+"**********"+ WorldToUgui(uiCanvas, rightPointer.pointer.transform.position).y);
                    //Vector2 screenPos = WordSpaceToCanvas(uiCanvas, rightPointer.pointerTip.transform.position);
                    Debug.LogError(screenPos.x + "****************" + uiCanvas.sizeDelta.x / 2);

                    if (screenPos.x > uiCanvas.sizeDelta.x / 2 || screenPos.x < -uiCanvas.sizeDelta.x / 2)
                    {
                        if (screenPos.y > uiCanvas.sizeDelta.y / 2 || screenPos.y < -uiCanvas.sizeDelta.y / 2) return;
                        rightHandParent.GetComponent().anchoredPosition = new Vector2(rightHandParent.GetComponent().anchoredPosition.x, screenPos.y);
                    }
                    else if (screenPos.y > uiCanvas.sizeDelta.y / 2 || screenPos.y < -uiCanvas.sizeDelta.y / 2)
                    {
                        if (screenPos.x > uiCanvas.sizeDelta.x / 2 || screenPos.x < -uiCanvas.sizeDelta.x / 2) return;
                        rightHandParent.GetComponent().anchoredPosition = new Vector2(screenPos.x, rightHandParent.GetComponent().anchoredPosition.y);
                    }
                    else if (screenPos.x < uiCanvas.sizeDelta.x / 2 && screenPos.x > -uiCanvas.sizeDelta.x / 2 && screenPos.y < uiCanvas.sizeDelta.y / 2 && screenPos.y > -uiCanvas.sizeDelta.y / 2)
                    {
                        rightHandParent.GetComponent().anchoredPosition = screenPos;
                        //Vector2 a=Vector2.zero;
                        //rightHandParent.GetComponent().anchoredPosition = Vector2.SmoothDamp(rightHandParent.GetComponent().anchoredPosition, screenPos, ref a, 5*Time.deltaTime);
                    }
                }


                if (NoloVR_Controller.GetDevice(NoloDeviceType.RightController).GetNoloButtonDown(NoloButtonID.Trigger))
                {
                    for (int i = 0; i < imagItemList.Count; i++)
                    {
                        if (imagItemList[i].IsStaying() == true)
                        {
                            //imagItemList[i].transform.SetSiblingIndex(imagItemList.Count-1);
                            imagItemList[i].GetComponent().isOn = true;

                        }
                    }
                }

                if (NoloVR_Controller.GetDevice(NoloDeviceType.RightController).GetNoloButtonPressed(NoloButtonID.Trigger))
                {
                    Debug.Log("右手柄扳机键长按");
                    rightHand.sprite = rightHandGripSprite;
                    for (int i = 0; i < imagItemList.Count; i++)
                    {
                        if (imagItemList[i].IsStaying() == true && imagItemList[i].GetComponent().isOn/* == true && imagItemList[i].transform.GetSiblingIndex()==imagItemList.Count-1*/)
                        {
                            //imagItemList[i].transform.localPosition = Vector3.Lerp(imagItemList[i].transform.localPosition, rightHandTrans.localPosition, 0.9f);
                            imagItemList[i].transform.SetParent(rightHandParent);
                            imagItemList[i].transform.SetAsFirstSibling();
                        }
                    }

                }

                if (NoloVR_Controller.GetDevice(NoloDeviceType.RightController).GetNoloButtonUp(NoloButtonID.Trigger))
                {
                    rightHand.sprite = rightHandReleaseSprite;
                    for (int i = 0; i < imagItemList.Count; i++)
                    {
                        imagItemList[i].isStaying = false;
                        if (imagItemList[i].GetComponent().isOn == true)
                        {
                            imagItemList[i].GetComponent().isOn = false;
                            //imagItemList[i].isStaying = false;
                            imagItemList[i].transform.SetParent(uiRoot);
                            imagItemList[i].transform.SetAsLastSibling();
                        }
                    }
                }

                if (NoloVR_Controller.GetDevice(NoloDeviceType.RightController).GetNoloTouchDown(NoloTouchID.TouchPad) && !NoloVR_Controller.GetDevice(NoloDeviceType.RightController).GetNoloButtonPressed(NoloButtonID.Trigger))
                {
                    for (int i = 0; i < imagItemList.Count; i++)
                    {
                        if (imagItemList[i].IsStaying() == true)
                        {
                            imagItemList[i].GetComponent().isOn = true;
                            imagItemList[i].transform.SetAsLastSibling();
                        }
                    }
                    delayTime = 0;
                    touchX = NoloVR_Controller.GetDevice(NoloDeviceType.RightController).GetAxis(NoloTouchID.TouchPad).x;
                }

                if (NoloVR_Controller.GetDevice(NoloDeviceType.RightController).GetNoloTouchPressed(NoloTouchID.TouchPad) && !NoloVR_Controller.GetDevice(NoloDeviceType.RightController).GetNoloButtonPressed(NoloButtonID.Trigger))
                {
                    delayTime += Time.deltaTime;
                    if (delayTime <= 0.2f) return;
                    float touchPosX = NoloVR_Controller.GetDevice(NoloDeviceType.RightController).GetAxis(NoloTouchID.TouchPad).x - touchX;
                    if (touchPosX > 0)
                    {
                        for (int i = 0; i < imagItemList.Count; i++)
                        {
                            if (imagItemList[i].IsStaying() == true && imagItemList[i].transform.GetSiblingIndex()==imagItemList.Count-1/*GetComponent().isOn == true*/)
                            {
                                if (imagItemList[i].GetComponent().sizeDelta.x * (1 + touchPosX) * 0.8f <= 5120)
                                {
                                    imagItemList[i].transform.localScale = Vector3.one * (1 + touchPosX) * 0.8f;
                                }

                            }
                        }
                    }
                    else
                    {
                        for (int i = 0; i < imagItemList.Count; i++)
                        {
                            if (imagItemList[i].IsStaying() == true && imagItemList[i].transform.GetSiblingIndex() == imagItemList.Count - 1/*GetComponent().isOn == true*/)
                            {
                                if (imagItemList[i].GetComponent().sizeDelta.y * (1 + touchPosX) * 0.8f >= 30)
                                {
                                    imagItemList[i].transform.localScale = Vector3.one * (1 + touchPosX) * 0.8f;
                                }
                            }
                        }
                    }
                    //Debug.LogError(touchPosX);
                }
                if (NoloVR_Controller.GetDevice(NoloDeviceType.RightController).GetNoloTouchUp(NoloTouchID.TouchPad) && !NoloVR_Controller.GetDevice(NoloDeviceType.RightController).GetNoloButtonPressed(NoloButtonID.Trigger))
                {

                    for (int i = 0; i < imagItemList.Count; i++)
                    {
                        imagItemList[i].isStaying = false;
                        if (/*imagItemList[i].IsStaying() == true && */imagItemList[i].GetComponent().isOn == true)
                        {
                            imagItemList[i].GetComponent().sizeDelta *= imagItemList[i].transform.localScale;
                            imagItemList[i].GetComponent().size *= imagItemList[i].transform.localScale;
                            imagItemList[i].transform.localScale = Vector3.one;
                            imagItemList[i].GetComponent().isOn = false;
                            return;
                        }
                    }
                }
            }
        }
        catch (System.Exception e)
        {
            Debug.Log("Catch" + e.Message);
            throw;
        }
    }


    private Vector2 WordSpaceToCanvas(RectTransform canvas, Vector3 objPos)
    {
        Vector2 canvasSize = canvas.sizeDelta;
        Vector3 viewPortPos3d = uiCamera.WorldToViewportPoint(objPos);
        Vector2 viewPortRelative = new Vector2(viewPortPos3d.x - 0.5f, viewPortPos3d.y - 0.5f);
        Vector2 objScreenPos = new Vector2(viewPortRelative.x * canvasSize.x, viewPortRelative.y * canvasSize.y);
        return objScreenPos;
    }

    /// 
    /// 将世界坐标转换为UI坐标
    /// 
    /// 画布
    /// 坐标
    /// 
    public Vector2 WorldToUgui(RectTransform canvas, Vector3 position)
    {

        Vector2 screenPoint = uiCamera.WorldToScreenPoint(position);//世界坐标转换为屏幕坐标
        Vector2 screenSize = new Vector2(Screen.width, Screen.height);
        screenPoint -= screenSize / 2;//将屏幕坐标变换为以屏幕中心为原点
        Vector2 anchorPos = screenPoint / screenSize * canvas.sizeDelta;//缩放得到UGUI坐标
        return anchorPos;
    }

    /// 
    /// 世界坐标转UI坐标
    /// 
    /// UI画布
    /// 世界坐标
    /// 
    public static Vector2 WorldToCanvasPoint(Canvas canvas, Vector3 worldPos)
    {
        Vector2 pos;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas.transform as RectTransform,
            Camera.main.WorldToScreenPoint(worldPos), canvas.worldCamera, out pos);
        return pos;
    }

}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class ImageItem : MonoBehaviour
{
    public GameObject selectObj;
    private bool isToggleOn;
    public bool isStaying;

    public int layer = 0;
    // Start is called before the first frame update
    void Start()
    {
        GetComponent().onValueChanged.AddListener(OnToggleSwitch);
    }

    private void OnToggleSwitch(bool isOn)
    {
        isToggleOn = isOn;
        selectObj.SetActive(isOn);
    }

    public bool IsToggleOn()
    {
        return isToggleOn;
    }

    public bool IsStaying()
    {
        return isStaying;
    }

    private void OnTriggerStay2D(Collider2D collision)
    {
        //if(collision.gameObject.name=="RightHand")
        //{
        //    //Debug.Log("手在" + gameObject.name + "上");
        //    isStaying = true;
        //}
    }

    private void OnTriggerExit2D(Collider2D collision)
    {
        Debug.Log("手离开了" + gameObject.name );
        //isStaying = false;
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

以下为UI触发事件,之前也试过2D碰撞体,但由于多张图片重叠的时候会碰撞穿透,因此换成了射线检测。

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

public class HandControl : MonoBehaviour
{
    private bool isStaying;

    public List imageList;


    private void FixedUpdate()
    {
        //参数为:起点坐标,方向向量
        //Ray2D ray = new Ray2D(transform.position, Vector2.zero);
        //或者直接用点坐标,方向
        RaycastHit2D info = Physics2D.Raycast(transform.position,Vector3.zero,0.1f)/*Physics2D.Raycast(transform.position, Vector2.zero)*/;
        if (info.collider != null)
        {
            for (int i = 0; i < imageList.Count; i++)
            {
                if (info.collider.gameObject==imageList[i].gameObject)
                {
                    imageList[i].isStaying = true;
                }
                else
                {
                    imageList[i].isStaying = false;
                }
            }
            
        }
        else
        {
            imageList.ForEach(m => { m.isStaying = false; });
        }
    }
}

功能完成之后,就需要测试了,首先将Nolo的头部定位器连接到电脑上,然后开启基站开关和手柄开关,运行工程,发现一切都很顺利,然后打包测试。打包测试之后才发现,拖动图片从屏幕中间往两边移动的时候速度会越来越快,特别是屏幕分辨率越大,这种情况越严重,经过排查,发现是相机原因,由于相机是一个视锥角,所以越往两边,移动的位置在屏幕上的投影就越大,因此我将相机模式改为正交,Culling Mask改为UI,将画布改为屏幕相机模式,然后问题就完美解决了。

Unity基于Nolo开发非VR桌面2D应用_第1张图片

Unity基于Nolo开发非VR桌面2D应用_第2张图片

 

 

 

如有大佬有更好的解决方案,可以加我QQ共同探讨:741343816

你可能感兴趣的:(Unity3D,C#,AR/VR,unity,c#)