在AR中制作一个重力感应标志

AR/VR的到来,让我们越来越离不开处理各种sensor数据的工作。尤其是来自手机IMU的数据,都可以使用API获取到。我们所要做的就是认识这些数据,正确的应用给物体。本文主要通过一个简单式例,介绍一下基于slam的ar应用中,常见的地面检测的标志物的制作。如图,该标志物辅助用户在现实中,指定创建三维物体的位置。



Setup

1. Camera设置

所有AR应用中,至少有两个摄像机,用来渲染Webcam视频的"背景Camera"和用来渲染前景三维物体的"ARCamera"。

背景Camera设置Clear Flags=Solid Color,CullingMask=UI,Project=Orthographic,Size=5,Depth=0;

ARCamera设置Clear Flags=Don't Clear,CullingMask=Everything,Project=Perspective,Depth=1。

ARCamera受陀螺仪控制旋转,添加脚本GyroManager。

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

public class GyroManager : MonoBehaviour
{
    private Quaternion rotFix;

    void Start()
    {
        Transform currentParent = transform.parent;

        GameObject camParent = new GameObject("GyroCamParent");
        camParent.transform.position = transform.position;
        transform.parent = camParent.transform;

        GameObject camGrandparent = new GameObject("GyroCamGrandParent");
        camGrandparent.transform.position = transform.position;
        camParent.transform.parent = camGrandparent.transform;
        camGrandparent.transform.parent = currentParent;

        if (SystemInfo.supportsGyroscope) //如果系统支持陀螺仪
        {
            Input.gyro.enabled = true;

            switch (Screen.orientation)
            {
                case ScreenOrientation.LandscapeLeft:
                    camParent.transform.eulerAngles = new Vector3(90, 90, 0);
                    rotFix = new Quaternion(0, 0, 0.7071f, 0.7071f);
                    break;
                case ScreenOrientation.Portrait:
                    camParent.transform.eulerAngles = new Vector3(90, 180, 0);
                    rotFix = new Quaternion(0, 0, 1, 0);
                    break;
                case ScreenOrientation.PortraitUpsideDown:
                    camParent.transform.eulerAngles = new Vector3(90, 180, 0);
                    rotFix = new Quaternion(0, 0, 1, 0);
                    break;
                case ScreenOrientation.LandscapeRight:
                    camParent.transform.eulerAngles = new Vector3(90, 180, 0);
                    rotFix = new Quaternion(0, 0, 1, 0);
                    break;
                default:
                    camParent.transform.eulerAngles = new Vector3(90, 180, 0);
                    rotFix = new Quaternion(0, 0, 1, 0);
                    break;
            }
        }
    }

    void Update()
    {
        if (SystemInfo.supportsGyroscope)
        {
            Quaternion quatMap = Input.gyro.attitude;
            transform.localRotation = Quaternion.Slerp(transform.localRotation, quatMap * rotFix, 0.05f);
        }
    }
}

2. Canvas设置

创建一个RawImage,用来播放WebcamTexture。

添加Aspect Ratio Fitter组件,Height Control Width,使视频铺满画布。

再添加播放视频的脚本WebCamManager。

using UnityEngine;
using UnityEngine.UI;

public class WebCamManager : MonoBehaviour
{
    private WebCamTexture webcamTexture;
    private RawImage rawImage;

    void Start()
    {
        webcamTexture = new WebCamTexture();
        webcamTexture.deviceName = WebCamTexture.devices[0].name;

        rawImage.texture = webcamTexture;
        //Debug.Log(webcamTexture.width + "*" + webcamTexture.height); //16*16

        if (!webcamTexture.isPlaying)
            webcamTexture.Play();
    }

    private void Update()
    {
        float cwNeeded = -webcamTexture.videoRotationAngle;
        if (webcamTexture.videoVerticallyMirrored)
        {
            cwNeeded += 180;
        }
        rawImage.rectTransform.localEulerAngles = new Vector3(0, 0, cwNeeded);
        float ratio = (float)webcamTexture.width / (float)webcamTexture.height;
    }
}

3. 标志物设置


这里特地用三维软件制作了一个模型,作为标志物。害羞

将模型到场景中作为ARCamera子物体,位置移到(0, 0, 5),相机裁剪平面有足够距离。这里注意!由于前面已经给ARCamera添加了由陀螺仪控制旋转的脚本,标志物作为子物体,被动受到多个方向的旋转控制,千万不能再使用Euler控制自身的旋转。将标志物作为ARCamera子物体,是为了让它永远能位于手机屏幕中央。再在代码中通过

transform.localRotation = Quaternion.Inverse(Camera.main.transform.rotation);

消除父物体旋转的影响。然后还加入了缩放,产生对目标位置近大远小的感觉。当手机屏幕朝下时(即摄像头朝天),自然看不到地面了,故隐藏标志物体。通过手机屏幕重力分量来判断即可。

using UnityEngine;

public class demo : MonoBehaviour
{
    private float temp;
    private MeshRenderer render;

    void Awake()
    {
        render = GetComponent<MeshRenderer>();
    }

    void Update()
    {
        transform.localRotation = Quaternion.Inverse(Camera.main.transform.rotation);

        temp = Mathf.Abs(Mathf.Tan(Camera.main.transform.eulerAngles.x * Mathf.PI / 360));
        transform.localScale = new Vector3(1f, 1f, 1f) * temp;

        //屏幕朝下的分量>0,就隐藏
        if (SystemInfo.supportsGyroscope)
        {
            render.enabled = Input.gyro.gravity.z < 0;
        }
    }
}

最后,无论手机处于什么姿态,都能通过标志物找到地面,并且让其他三位物体以它为基准在AR中创建出来。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值