简介这份Unity3d C#源码资源面向AR应用开发者与空间计算方向的学习者聚焦Rokid AR眼镜平台上的图像识别与跟踪功能实现。工程基于Rokid SDK的事件驱动架构通过OnTrackedImageAdded、OnTrackedImageUpdate、OnTrackedImageRemoved三类事件完成图像检测、实时位姿跟踪与虚拟对象清理帮助读者理解虚拟内容如何与真实图像建立稳定空间关系。资源以插件V3.0.3为例需配合Unity 2022 LTS、Android SDK/NDK与OpenJDK环境并适配Rokid Station Pro/Station2及Max系列眼镜。压缩包共723个文件约20.92MB包含58个cs脚本、50个unity场景、53个asset资源、44个mat材质、40个png贴图、16个shader及13个prefab等覆盖脚本逻辑、场景搭建与渲染材质等模块。目前已有204人学习适合具备一定Unity与C#基础、希望快速上手Rokid AR图像识别跟踪的开发者参考。1. 从一次现场调试说起这套 Rokid AR 图片识别跟踪源码到底能干什么去年帮一个做工业巡检的团队调设备他们用 Rokid AR 眼镜做产线巡检辅助需求很具体工人走到设备前眼镜扫到贴在机身上的标识图屏幕上立刻叠出这台设备的实时参数和操作指引人走动的时候标识图得跟得住不能飘。当时他们卡在识别率上光线一变就丢目标后来换了一套基于 Unity3d C# 的图片识别与跟踪方案才稳住。这份源码就是干这个的——在 Rokid AR 眼镜上用 Unity 做图片识别与跟踪识别到预设图片后在画面里叠加虚拟内容并持续跟踪图片位置。适合做 AR 巡检、展陈导览、设备维保提示这类需要“扫图出内容”的开发者尤其是手里已经有 Rokid 设备、想快速跑通识别跟踪链路的团队。它不是一个通用 AR 框架而是把图片识别与跟踪这条链路在 Rokid 平台上打通的可运行工程拿来就能改。2. 技术选型与工程结构为什么是 Unity Rokid SDK 这套组合2.1 图片识别跟踪在 AR 眼镜上的技术路线在 AR 眼镜上做图片识别与跟踪常见做法有三条路一是纯视觉方案用 OpenCV 自己写特征匹配二是用 AR 引擎自带的图像跟踪能力比如 AR Foundation 的 ARTrackedImageManager三是用设备厂商 SDK 提供的识别跟踪接口。这份源码走的是第三条路基于 Rokid 的 AR SDK 做识别与跟踪Unity 负责渲染和逻辑。为什么这么选因为眼镜端的摄像头标定、畸变校正、SLAM 位姿这些底层东西厂商 SDK 已经封装好了自己从 OpenCV 撸一遍光相机内参标定就能耗掉两周而且不同批次设备还有差异。用厂商 SDK 的好处是识别跟踪的位姿直接给到 Unity 的 Transform你只管往上面挂虚拟物体。这里要区分两个概念识别和跟踪。识别是“这一帧画面里有没有目标图”跟踪是“目标图在连续帧里的位姿变化”。很多新手以为识别到了就完事结果人一走画面就丢就是因为没处理跟踪。这份源码里识别和跟踪是分开的两个阶段识别负责首次命中跟踪负责后续帧的位姿更新这个设计在后面代码里能看出来。2.2 工程目录与关键文件说明拿到源码后先别急着打开 Unity先看目录结构。一个典型的 Rokid AR 图片识别跟踪工程目录大致是这样组织的Assets/ ├── Scenes/ │ └── ImageTrackingDemo.unity // 主场景挂载识别跟踪管理器 ├── Scripts/ │ ├── ImageTrackingManager.cs // 识别跟踪核心逻辑 │ ├── TrackedImageEventHandler.cs // 识别到图片后的事件回调 │ └── ARContentController.cs // 虚拟内容显示控制 ├── Prefabs/ │ └── ARContentPrefab.prefab // 识别后叠加的虚拟内容预制体 ├── StreamingAssets/ │ └── ReferenceImages/ // 待识别的目标图片库 │ ├── target_01.jpg │ └── target_02.jpg └── Plugins/ └── RokidAR/ // Rokid SDK 的 Unity 插件 ├── Runtime/ └── Native/StreamingAssets/ReferenceImages/这个目录是关键待识别的图片放这里运行时加载成识别库。图片的命名和特征质量直接影响识别率后面避坑章节会细说。Plugins/RokidAR/是厂商 SDK一般不需要改但要知道它提供了哪些接口因为ImageTrackingManager.cs就是调它的。2.3 识别跟踪的核心数据流整个数据流是这样的眼镜摄像头采集画面 → Rokid SDK 做图像预处理和特征匹配 → 命中目标图后返回位姿位置 旋转→ Unity 把位姿赋给虚拟内容的 Transform → 渲染叠加。这条链路里SDK 是黑匣子你能控制的是目标图库的质量、虚拟内容的锚点对齐、以及识别到之后的逻辑响应。源码里ImageTrackingManager负责订阅 SDK 的识别回调ARContentController负责把虚拟内容挂到正确的位姿上。理解这条数据流后面看代码就不会迷。3. 核心模块拆解识别管理器与内容控制器的代码实现3.1 ImageTrackingManager 的初始化与目标图库加载先看识别管理器的初始化。这段代码负责在场景启动时把目标图库加载进 SDK并注册识别回调using UnityEngine; using RokidAR.ImageTracking; // Rokid SDK 的图片跟踪命名空间 public class ImageTrackingManager : MonoBehaviour { [SerializeField] private string[] targetImageNames; // 目标图文件名不含扩展名 [SerializeField] private float physicalWidth 0.2f; // 目标图物理宽度单位米 private IImageTrackingSubsystem trackingSubsystem; void Start() { // 获取 Rokid 的图片跟踪子系统实例 trackingSubsystem ImageTrackingSubsystem.GetInstance(); if (trackingSubsystem null) { Debug.LogError(Rokid 图片跟踪子系统初始化失败检查 SDK 是否导入); return; } // 逐个添加目标图physicalWidth 决定虚拟内容缩放基准 foreach (var imageName in targetImageNames) { var imageLib new MutableRuntimeReferenceImageLibrary(); var job imageLib.ScheduleAddImageWithValidationJob( LoadTextureFromStreamingAssets(imageName), imageName, physicalWidth); trackingSubsystem.AddReferenceImage(imageLib, job); } // 注册识别到图片的回调 trackingSubsystem.ImageDetected OnImageDetected; trackingSubsystem.ImageUpdated OnImageUpdated; trackingSubsystem.ImageLost OnImageLost; } private Texture2D LoadTextureFromStreamingAssets(string name) { // 从 StreamingAssets 读取图片路径拼接注意平台差异 string path System.IO.Path.Combine(Application.streamingAssetsPath, ReferenceImages, name .jpg); byte[] data System.IO.File.ReadAllBytes(path); Texture2D tex new Texture2D(2, 2); tex.LoadImage(data); return tex; } }这段代码有几个点要说明。physicalWidth这个参数很关键它告诉 SDK 这张目标图在真实世界里有多宽SDK 靠它反推虚拟内容该按什么比例缩放。如果你设成 0.2 米但实际贴的图是 0.5 米虚拟内容就会明显偏小。ScheduleAddImageWithValidationJob是带校验的添加方式会检查图片特征点够不够特征太少的图会被拒绝这是第一道防线。回调注册了三个事件ImageDetected首次识别、ImageUpdated位姿更新、ImageLost目标丢失这三个事件对应识别跟踪的三个阶段缺一不可。3.2 识别回调与虚拟内容挂载识别到图片后要把虚拟内容挂到对应的位姿上。这段代码处理识别和更新回调using System.Collections.Generic; using UnityEngine; public partial class ImageTrackingManager : MonoBehaviour { [SerializeField] private GameObject contentPrefab; // 虚拟内容预制体 private Dictionarystring, GameObject activeContents new Dictionarystring, GameObject(); private void OnImageDetected(ImageDetectedEventArgs args) { // args.ImageName 是目标图名args.Pose 是识别到的位姿 if (activeContents.ContainsKey(args.ImageName)) return; // 已存在则跳过避免重复实例化 GameObject content Instantiate(contentPrefab); // 把虚拟内容放到识别位姿上 content.transform.position args.Pose.position; content.transform.rotation args.Pose.rotation; // 按目标图物理宽度缩放保证虚拟内容与真实图比例一致 content.transform.localScale Vector3.one * args.PhysicalWidth; activeContents[args.ImageName] content; } private void OnImageUpdated(ImageUpdatedEventArgs args) { // 跟踪阶段每帧更新位姿这是“跟得住”的关键 if (activeContents.TryGetValue(args.ImageName, out GameObject content)) { content.transform.position args.Pose.position; content.transform.rotation args.Pose.rotation; } } private void OnImageLost(ImageLostEventArgs args) { // 目标丢失销毁或隐藏虚拟内容 if (activeContents.TryGetValue(args.ImageName, out GameObject content)) { Destroy(content); activeContents.Remove(args.ImageName); } } }OnImageDetected里做了去重判断因为有些 SDK 在识别瞬间会连续触发多次不去重就会叠出一堆虚拟物体这是血泪经验。OnImageUpdated是跟踪的核心每帧把最新位姿赋给虚拟内容人走动时虚拟内容才能跟着图走。OnImageLost里我一般选择销毁而不是隐藏因为隐藏的物体还在场景里占资源长时间运行会累积。如果你需要重新识别时快速恢复可以改成隐藏加对象池但那是优化阶段的事先跑通再说。3.3 ARContentController 的内容对齐与显示控制虚拟内容挂上去之后还有个对齐问题。识别位姿的原点通常在目标图中心但你的虚拟内容锚点不一定在中心这段代码处理对齐using UnityEngine; public class ARContentController : MonoBehaviour { [SerializeField] private Transform anchorOffset; // 内容锚点偏移 [SerializeField] private GameObject infoPanel; // 信息面板 void Start() { // 把内容锚点对齐到目标图中心 if (anchorOffset ! null) { transform.position anchorOffset.position; transform.rotation anchorOffset.rotation; } // 初始隐藏识别到再显示 if (infoPanel ! null) infoPanel.SetActive(false); } public void ShowContent() { if (infoPanel ! null) infoPanel.SetActive(true); } public void HideContent() { if (infoPanel ! null) infoPanel.SetActive(false); } }anchorOffset这个 Transform 决定了虚拟内容相对目标图的位置。常见做法是在预制体里放一个空物体作为锚点把信息面板挂在它下面这样调整偏移只动锚点不用改面板本身。ShowContent和HideContent由识别管理器在识别和丢失时调用把显示逻辑和识别逻辑解耦后面改 UI 不会牵动识别代码。4. 从零跑通环境搭建、真机部署与调试步骤4.1 开发环境与 SDK 导入跑这个工程需要 Unity 2021 LTS 或更高版本Rokid 的 Unity SDK 包以及 Rokid AR 眼镜一台用于真机调试。步骤是新建 Unity 3D 项目把源码里的Assets目录内容拷进去然后把 Rokid SDK 的.unitypackage导入。导入后检查Plugins/RokidAR/下有没有报错常见的是 Android 平台相关的库没勾选。在Player Settings里把平台切到 AndroidMinimum API Level设到 SDK 要求的最低版本Scripting Backend选 IL2CPPTarget Architectures勾上 ARM64。这几项不设对打包出来装到眼镜上会闪退。4.2 目标图库配置与场景搭建目标图库的配置直接决定识别效果。把待识别的图片放进StreamingAssets/ReferenceImages/然后在场景里ImageTrackingManager的targetImageNames数组填上文件名physicalWidth填实际打印出来的图的宽度米。场景搭建上把ImageTrackingManager挂到一个空物体上contentPrefab指向虚拟内容预制体。预制体里放ARContentController把信息面板挂到锚点下。这套搭完在编辑器里是跑不了识别跟踪的因为编辑器没有眼镜摄像头必须真机。4.3 真机部署与日志排查真机部署用 USB 连眼镜Unity 里Build And Run。装好后戴上眼镜对准目标图正常的话一两秒内虚拟内容就出来了。如果没反应先看日志。Android 日志用adb logcat过滤 Unity 和 Rokid 的 tag常见错误是“reference image validation failed”说明目标图特征点不够换一张纹理丰富的图。另一个常见错误是权限没给摄像头权限要在AndroidManifest.xml里声明SDK 一般会自带但如果你改过 manifest 可能被覆盖掉。调试阶段建议在OnImageDetected里加一行日志打印识别到的图名和位姿确认回调有没有触发这是最快的定位手段。5. 避坑与常见问题识别率、位姿抖动、性能这三类坑5.1 识别率低现象是时好时坏原因多在目标图本身现象同一张图光线好的时候能识别稍暗一点就丢或者换了角度就识别不到。原因目标图特征点不足或者图片反光、纹理重复。解决选目标图时优先选纹理丰富、对比度高、非对称的图避免大面积纯色和重复图案。打印出来贴的时候避免覆膜反光哑光材质最好。如果必须在暗光环境用考虑给目标图加辅助光源或者换用红外特征图。我一般会在正式用之前拿几张候选图在目标环境里各测二十次统计识别率低于八成的不上。5.2 位姿抖动现象是虚拟内容原地抖原因是跟踪位姿噪声现象识别到之后虚拟内容在人不动的时候也在轻微抖动或者缓慢漂移。原因跟踪阶段的位姿估计有噪声尤其是目标图在画面里占比小的时候。解决在OnImageUpdated里对位姿做平滑常见做法是位置用低通滤波旋转用球面插值。但平滑会引入延迟参数要调。另一个办法是让目标图在画面里占大一点识别跟踪的精度和图像占比正相关。如果抖动实在严重检查是不是眼镜的 SLAM 没初始化好有些 SDK 需要先做环境扫描再识别。5.3 性能问题现象是眼镜发热、帧率掉原因是每帧都在做识别现象跑一会儿眼镜就烫帧率从 60 掉到 30 以下。原因识别是计算密集型操作如果每帧都全图搜索GPU 和 CPU 都吃不消。解决识别和跟踪要分频识别不需要每帧做可以每三到五帧做一次跟踪每帧做但跟踪的计算量比识别小。SDK 一般有识别频率的配置项找出来调低。另外虚拟内容的面片数和材质也要控制AR 眼镜的 GPU 性能有限别挂太复杂的模型。我一般会在真机上用 Profiler 看 CPU 和 GPU 占用识别相关的耗时超过 5ms 就要优化。5.4 多目标图互相干扰现象是识别到 A 却显示 B 的内容现象场景里放了多张目标图识别到其中一张显示的却是另一张的内容。原因目标图特征太相似SDK 匹配错了或者回调里的图名映射写错了。解决目标图之间要有明显差异别用同一套模板改几个字。回调里用args.ImageName做字典键确保映射唯一。如果确实需要相似图考虑给每张图加不同的边框或角标作为辅助特征。这个坑我在展陈项目里踩过两面墙的图长得像观众站中间就串了后来给每张图加了不同颜色的角标才解决。6. 二次开发改造换识别库、加交互、做多图联动的具体做法拿到这套源码二次开发的方向通常有三个换识别库、加交互、做多图联动。换识别库最简单把StreamingAssets/ReferenceImages/里的图换掉改targetImageNames和physicalWidth就行但要注意新图的特征质量按上一章的方法先测识别率。加交互是往ARContentController里加逻辑比如识别到之后弹按钮点按钮触发操作。这里有个技巧交互的射线检测要用眼镜的注视点或者手柄别用触摸屏眼镜上没有触摸。多图联动是识别到 A 图之后在 B 图的位置也显示内容这需要维护一个图名到位姿的映射表在OnImageUpdated里更新所有已知图的位姿然后按业务逻辑决定显示什么。改造时我建议先做一个最小验证只保留一张目标图和一个信息面板把识别到显示的链路跑通再往上加东西。很多新手一上来就搭复杂场景结果识别出问题时分不清是识别库的锅还是场景的锅。验证通过后再逐步加图、加交互、加联动。每次加完都在真机上跑一遍别只在编辑器里看编辑器里没有识别跟踪看不出问题。还有一个容易忽略的点是虚拟内容的生命周期管理。识别到就实例化、丢失就销毁这个模式在单图场景没问题多图频繁切换时会有性能抖动。改造时可以引入对象池识别到从池里取丢失还回池里避免频繁 Instantiate 和 Destroy。对象池的容量按最大同时识别数设一般三到五个够用。这个优化在展陈导览这种观众来回走动的场景里效果明显帧率能稳不少。从那以后我每次拿到新的 AR 识别跟踪工程都强制先跑一遍单图最小验证确认识别、跟踪、丢失三个回调都正常触发再动其他代码。这个习惯帮我省了很多排查时间因为识别跟踪的问题往往不在你改的那部分而在你没验证的基础链路上。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?