在对Github开源项目ARFoundation-NatCorder-NativeGallery-Example进行二次开发。主要记录以下几点:

1. 基于射线检测的GLB文件真实世界放置

2.射线安全保障

一、前言:

1. 什么是NatCorder和NativeGallery

NatCorder 主要聚焦于录制和导出视频和音频,适用于需要录屏功能的场景。

NativeGallery 主要用于处理和管理设备的相册文件(如图片和视频),适用于需要访问、保存和加载图库内容的场景。

2. 什么是Unity AR射线检测

在Unity AR开发中,射线检测(Raycasting) 是一种常见的技术,用于从某个起点发射一条射线,并检测它是否与场景中的物体发生碰撞或交互。在增强现实(AR)项目中,射线检测通常用于处理与现实世界物体的交互,例如,用户触摸屏幕时在虚拟环境中选择或操控物体。

二、开发工作

编辑器版本:Unity 2021.3.45f2c1

必要安装包:项目中已经预先配置了AR Foundation包。Unity 在打开项目时会根据项目的配置文件(如 Packages/manifest.json)自动识别并安装缺失的包。因此我们可无需关心源项目的安装包情况。

1. 自适应手机屏幕

该项目有一些小BUG需要修复一下,当然你也可以打包在手机上试一下。应用拍摄的照片会与图库的照片有所偏差,图库的照片仅仅展示的是720*1080。

为了防止应用修改我们图片的尺寸,我们在Assets > CameraRec > script > CameraRecReplayCam.cs文件中添加以下代码,让其拍摄时自适应手机屏幕大小:

...
private void Start()
{
    // 添加的代码
    videoWidth = Screen.width;
    videoHeight = Screen.height;
    // 源程序
    StartCoroutine("AddMicrophoneSource");
}
...

如何追踪CameraRecReplayCam.cs?

当点击拍摄按钮时,尤其是保存功能,必定会触发一些脚本,顺着这个脚本去分析即可。

2. 安装Unity glTFast插件

Unity glTFast插件允许你直接导入 .glb(二进制 glTF)和 .gltf(JSON 格式的 glTF)文件到 Unity 项目中。它能够解析并渲染这些文件中包含的几何数据、材质、纹理和动画。

安装流程:"Window" > "Package Manager" > 点击左上角的"+" > "Add package by name" > 输入"com.unity.cloud.gltfast" > "add"

这样就可以将GLB文件拖拽到Hierarchy里进行调设,然后封装成prefab。

如果拖拽进去,没有在Scene发现模型,请注意AR Camera的Far,原项目调的是2000,容易增加渲染开销。

3. AR Session Origin

3.1 组件解释

要实现基于射线检测的GLB文件真实世界放置,至少需要如图所示的四个组件,其中ARPlacementWithBlockUI是放置模型的C#脚本。

AR Session Origin:Unity AR 开发中管理虚拟内容与真实世界空间映射的核心根节点,通过自身位姿和缩放因子为所有子节点虚拟物体提供统一的空间基准,确保其基于设备跟踪数据正确锚定在真实世界中。

AR Place Manager:负责检测、跟踪并生成真实世界中的平面(如地面、桌面、墙面),同时管理平面的创建、更新与销毁,并向其他组件提供平面数据的核心管理器。

AR Raycast Manager:用于从屏幕坐标(如触摸点)向 AR 场景中发射射线,检测并获取与真实世界跟踪对象(如平面、锚点、特征点)相交结果的核心组件,是实现虚拟物体放置、交互的基础。

3.2 脚本编写

代码来源于Github开源项目的二次开发

主文件:Scripts/ARPlacementWithBlockUI.cs

using System;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.XR.ARFoundation;

[RequireComponent(typeof(ARRaycastManager))]
public class ARPlacementWithBlockUI : MonoBehaviour
{
    [SerializeField]
    private GameObject placedPrefab;

    private ARRaycastManager arRaycastManager;

    private static List<ARRaycastHit> hits = new List<ARRaycastHit>();

    private GameObject placedObject; // 跟踪当前放置的模型

    void Awake() 
    {
        arRaycastManager = GetComponent<ARRaycastManager>();
    }

    void Update()
    {
        if(Input.touchCount > 0)
        {
            Touch touch = Input.GetTouch(0);

            if(touch.phase == TouchPhase.Began)
            {
                var touchPosition = touch.position;

                bool isOverUI = touchPosition.IsPointOverUIObject();
                
                if(!isOverUI && arRaycastManager.Raycast(touchPosition, hits, UnityEngine.XR.ARSubsystems.TrackableType.PlaneWithinPolygon))
                {
                    if(placedObject != null)
                    {
                        // 如果模型已存在,则删除
                        Destroy(placedObject);
                        placedObject = null;
                    }
                    else
                    {
                        // 如果模型不存在,则放置新模型
                        var hitPose = hits[0].pose;
                        placedObject = Instantiate(placedPrefab, hitPose.position, hitPose.rotation);
                    }
                }
            }
        }
    }
}

扩展文件:Scripts/Extensions/Vector2Extensions.cs

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

public static class Vector2Extensions
{
    public static bool IsPointOverUIObject(this Vector2 pos)
    {
        if (EventSystem.current.IsPointerOverGameObject())
        {
            return false;
        }
        
        PointerEventData eventPosition = new PointerEventData(EventSystem.current);
        eventPosition.position = new Vector2(pos.x, pos.y);

        List<RaycastResult> results = new List<RaycastResult>();
        EventSystem.current.RaycastAll(eventPosition, results);

        return results.Count > 0;
    }
}

简单介绍这俩个C#文件的逻辑:

Scripts/ARPlacementWithBlockUI.cs

这是一个ARFoundation脚本,用于在AR场景中处理预制件的放置和删除。通过触摸检测和射线投射,用户可以在检测到的平面上放置或移除对象,同时避免在UI元素上触发操作。

Scripts/Extensions/Vector2Extensions.cs

这是一个Vector2扩展类,提供IsPointOverUIObject方法,用于检测给定的屏幕坐标是否位于UI元素上,通过EventSystem的射线投射来判断触摸是否应被UI拦截

4. 组件删除

编写完代码后,从Canvas找到组件CameraRecBtn,删除CameraRecBtn组件Image-flash。因为它的大小与Canvas相当,会影响射线投射,其次,它不影响拍摄和录像的功能,

最终完成项目打包,即可得到一个支持模型投放、拍照与录像功能的轻量 AR Demo

Logo

这里是一个专注于游戏开发的社区,我们致力于为广大游戏爱好者提供一个良好的学习和交流平台。我们的专区包含了各大流行引擎的技术博文,涵盖了从入门到进阶的各个阶段,无论你是初学者还是资深开发者,都能在这里找到适合自己的内容。除此之外,我们还会不定期举办游戏开发相关的活动,让大家更好地交流互动。加入我们,一起探索游戏开发的奥秘吧!

更多推荐