找回密码
 立即注册
查看: 238|回复: 2

Unity开发《一起来捉妖》教程 | 2.用摄像头图像做背景

[复制链接]
发表于 2023-3-1 10:04 | 显示全部楼层 |阅读模式
洪流学堂,让你快人几步。你好,我是郑洪智。
洪流学堂公众号回复捉妖,可以获取本教程的源码工程
<hr/>小新:“我们接下来是不是需要将显示融合到屏幕上,才能称得上是AR呢?”
大智:“没错,屏幕式AR就是通过摄像头获取现实世界的图像,显示在屏幕上,然后和虚拟的物体叠加显示。我们今天就来实现这个摄像头图像做背景。”



2.摄像头图像做背景

要使用摄像头图像做背景,那首先需要获取到摄像头的图像。在Unity中读取摄像头的数据主要需要用到WebCamTexture这个类。
核心代码如下:
IEnumrator Start()
{
    // 请求摄像头权限
    yield return Application.RequestUserAuthorization(UserAuthorization.WebCam);
    // 如果获取到摄像头权限
    if (Application.HasUserAuthorization(UserAuthorization.WebCam))
    {
        // 获取所有的摄像头设备
        WebCamDevice[] devices = WebCamTexture.devices;
        if (devices != null)
        {
            // 索引为0的摄像头一般为后置摄像头,参数分别为设备名称、图像宽度、高度、刷新率
            WebCamTexture tex = new WebCamTexture(devices[0].name, width, height, fps);
            // 实时获取摄像头的画面
            tex.Play();
        }
    }
}大智:“那么如何将摄像头的图像作为游戏背景现实呢?”
小新:“这个简单,直接使用全屏的UI图片就可以了吧?”
大智:“再详细点呢?”
小新:“恩么。。。应该是使用UI里面的RawImage组件,然后将WebCamTexture赋值给这个组件的texture属性。”
大智:“那你想到一个问题没有?我们需要在这个背景上显示3D模型,也就是我们要抓的妖怪,如何设置呢?”
小新:“哦哦,对哦,那我们应该把UI设置为3D的UI,由于UI是跟随相机移动的,可以设置Canvas为Screen Space - Camera。
大智:“嗯,那我们试试看喽。”



接下来我们需要把相机的画面赋给这个RawImage组件的texture,最后完整的代码如下:
using System.Collections;
using UnityEngine;
using UnityEngine.UI;

public class WebCameraBackground : MonoBehaviour
{
    RawImage cameraImage;
    private WebCamTexture webCamTex;

    IEnumerator Start()
    {
        cameraImage = GetComponent<RawImage>();

        // 请求摄像头权限
        yield return Application.RequestUserAuthorization(UserAuthorization.WebCam);
        // 如果获取到摄像头权限
        if (Application.HasUserAuthorization(UserAuthorization.WebCam))
        {
            // 获取所有的摄像头设备
            WebCamDevice[] devices = WebCamTexture.devices;
            if (devices != null)
            {
                // 索引为0的摄像头一般为后置摄像头,参数分别为设备名称、图像宽度、高度、刷新率
                webCamTex = new WebCamTexture(devices[0].name, 800, 1280, 30);
                // 实时获取摄像头的画面
                webCamTex.Play();

                cameraImage.texture = webCamTex;
            }
        }
    }
}最后将这个代码拖到RawImage这个物体上,就可以发布到真机上测试查看了!
小新:“这发布出来以后有点不太对,只有手机横着的时候,摄像头显示的图像方向和实际是一致的,其他的都不对。”
大智:“这是因为WebCamTexture返回的图像,实际上会根据手机的朝向有一定的旋转,我们把下面的代码加进来测试一下看看。”
private void OnGUI()
{
    // 使用下面的旋转角度(顺时针)来旋转摄像头,以保证正确的朝向
    GUILayout.Label(webCamTex.videoRotationAngle.ToString());
    // 摄像头的视频是否垂直翻转
    GUILayout.Label(webCamTex.videoVerticallyMirrored.ToString());
}使用竖屏时,你会看到第一个值显示的是90,意味着我们需要将图像顺时针旋转90度,才是正确的朝向。
小新:“我试着改了一下,还是不对,智哥你来吧。”
大智:“那我就直接上代码了,首先你把RawImage的Anchor的位置直接设置到中心就行。因为后面我们需要通过代码来修改这个RawImage的旋转和尺寸,否则会有冲突。”



具体完整代码如下:
using System.Collections;
using UnityEngine;
using UnityEngine.UI;

public class WebCameraBackground : MonoBehaviour
{
    RawImage cameraImage;
    private RectTransform rectTransform;
    private WebCamTexture webCamTex;
    private int lastRotationAngle;

    IEnumerator Start()
    {
        cameraImage = GetComponent<RawImage>();
        rectTransform = GetComponent<RectTransform>();

        // 请求摄像头权限
        yield return Application.RequestUserAuthorization(UserAuthorization.WebCam);
        // 如果获取到摄像头权限
        if (Application.HasUserAuthorization(UserAuthorization.WebCam))
        {
            // 获取所有的摄像头设备
            WebCamDevice[] devices = WebCamTexture.devices;
            if (devices != null)
            {
                // 索引为0的摄像头一般为后置摄像头,参数分别为设备名称、图像宽度、高度、刷新率
                webCamTex = new WebCamTexture(devices[0].name, 800, 1280, 30);
                // 实时获取摄像头的画面
                webCamTex.Play();

                cameraImage.texture = webCamTex;
            }
        }
    }

    private void Update()
    {
        if (webCamTex != null && lastRotationAngle != webCamTex.videoRotationAngle)
        {
            OnOrientationChanged();
            lastRotationAngle = webCamTex.videoRotationAngle;
        }
    }

    private void OnOrientationChanged()
    {
        // 旋转rawimage,为什么加一个负号呢?因为rawimage的z轴是背对图像的,直接使用videoRotationAngle旋转,相对于图片是逆时针旋转
        transform.localRotation = Quaternion.Euler(0, 0, -webCamTex.videoRotationAngle);

        // 判断是否是竖屏,竖屏时由于旋转的关系,需要将width和height调换
        if (webCamTex.videoRotationAngle % 180 != 0)
            rectTransform.sizeDelta = new Vector2(Screen.height, Screen.width);
        else
            rectTransform.sizeDelta = new Vector2(Screen.width, Screen.height);
    }

    private void OnGUI()
    {
        // 使用下面的旋转角度(顺时针)来旋转摄像头,以保证正确的朝向
        GUILayout.Label(webCamTex.videoRotationAngle.ToString());
        // 摄像头的视频是否垂直翻转
        GUILayout.Label(webCamTex.videoVerticallyMirrored.ToString());
    }
}小新:“旋转rawimage,为什么加一个负号呢?”
大智:“因为webCamTex.videoRotationAngle的返回值是相对于图像需要顺时针旋转一定的角度。也就是如下图所示:”



大智:“如果以Unity的左手坐标系来看的话,这个角度所对应的旋转轴应该是朝屏幕外的方向。但实际上rawimage的z轴是朝向屏幕内的,所以刚好相反,简单来计算就是取videoRotationAngle的负值即可。”
总结

大智:“今天学习了用Unity开发《一起来捉妖》的第二部分,实现了摄像头作为游戏的背景。”
小新:“加上背景以后呢,真的有些AR的感觉了呢。”
洪流学堂公众号回复捉妖,可以获取本教程的源码工程


https://www.zhihu.com/video/1110263763374161920
今日思考题

大智:“动手将今天的工程部署到真机上体验一下。” 小新:“好嘞!” 大智:“收获别忘了分享出来!也别忘了分享给你学Unity的朋友,也许能够帮到他。”
推荐阅读


  • Unity开发《一起来捉妖》教程 | 1.陀螺仪控制相机
  • Unity 2019.1 中文更新日志速览版
  • UnityWebRequest详解
  • Unity中编码Encoding脱坑指南
  • Unity中的Git最佳实践
  • Unity2019更新规划速览,将有官方的可视化编程!
  • Unity运行时更新带来了什么?
  • Unity2018.3新功能 | Prefab嵌套和变体
  • Unity3d中的百度语音识别及语音合成

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
发表于 2023-3-1 10:09 | 显示全部楼层
大神你好,竖屏时画面出现拉伸怎么处理
发表于 2023-3-1 10:12 | 显示全部楼层
里面有处理横竖屏的,是不是没写全?
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-6-24 14:50 , Processed in 0.095270 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表