简介:一份基于Unity与Vuforia开发的AR交互动画项目完整工程,以小猫为交互主角,点击不同按钮即可播放对应动画,适合Unity初学者、AR方向开发者以及高校课程设计、毕业设计、工程实训等场景参考。压缩包共2000个文件,大小90.91MB,文件类型覆盖1544个bin运行时资源、57个dll依赖库、21个asset场景与配置、18个pdf说明及设计报告、8个prefab预制体、8个shader着色器,以及FBX模型、C#脚本、材质、图片等;bin与dll保障运行环境,shader与prefab决定视觉与交互表现,pdf文件则辅助理解项目结构。项目经过严格测试,答辩评审平均分96分,目前已有135人学习下载。使用者既可整体复用此工程,也能针对按钮逻辑、动画切换、模型特效等模块进行二次开发;配套说明和设计报告对梳理AR交互实现流程、撰写课程或毕设文档也有直接帮助,适用于初期立项、大作业、竞赛练手等场景。
1. 基于 Unity 和 Vuforia 开发的 AR 交互动画:一张识别图撑起一个可交互展厅
展会海报、教材封面或者商店橱窗上印着一张图,手机扫过去,3D 模型从图面立起来,播一段旋转或爆炸演示,手指还能拖着换角度——这就是基于 Unity 和 Vuforia 开发的 AR 交互动画最典型的现场。它把一张平面印刷物变成 AR 内容的触发器和锚点,用户对准、识别、观看,一次产品演示或知识讲解就完成了。
拆开看,技术栈其实只有三块:Unity 负责 3D 渲染、动画系统和输入交互;Vuforia 负责从相机画面里识别图像并输出位姿;中间靠 Image Target 的事件把两者接起来。这套组合不需要深度相机,也不需要团队有视觉算法背景,属于最容易出成果的 AR 落地路线之一。
适合谁?做产品展示 App、教育课件、展会互动内容、文创周边应用的开发者,以及想快速拿出一份 AR 作品集的人。门槛不高是实话,但识别图评级、现场光照、动画节奏这些参数,直接决定交付物是“能跑”还是“能上展”。真正难的不是把模型识别出来,而是识别到之后那段交互动画怎么演得自然。
2. 为什么偏偏是 Unity 和 Vuforia:识别链路与动画载体的选型逻辑
接到 AR 需求,常见做法是先决定“自研识别”还是“用现成 SDK”。团队没有计算机视觉背景时,Vuforia 几乎是识别图这方向最省事的答案:特征点提取、匹配、位姿计算全部封装好,你在 Unity 侧拿到的是一个带坐标系的 Target,剩下的事基本是写动画和交互。选择这条路线,意味着把“识别准不准”的难题交给 SDK,把“演得好看不好看”的难题留给自己。
2.1 Vuforia 从识别图到位姿:Trackable 与特征点在做什么
识别图上传到 Target 数据库后,Vuforia 会提取并存储它的特征点。运行时把相机帧里的特征点与数据库做匹配,求解出识别图的 6 自由度位姿,最终把一个带坐标系的 Image Target 暴露给 Unity。你在场景里看到的 ImageTarget 预制体,本质上是挂在 ObserverBehaviour 上的一个追踪结果容器,脚本通过事件拿到 TargetStatus,里面两个字段最重要:Status 表示追踪状态,StatusInfo 说明异常原因。
Status 的取值直接决定动画逻辑怎么写,常见几个值先记清楚:
| Status 取值 | 含义 | 动画逻辑建议 |
|---|---|---|
| NOT_FOUND | 当前帧没找到识别图 | 暂停或淡出 |
| LIMITED | 找到了但位姿不可靠 | 忽略或降级处理 |
| TRACKED | 正常追踪 | 播放或继续 |
| EXTENDED_TRACKED | 图移出画面,靠环境特征续追踪 | 可继续播放但留意漂移 |
和 AR Foundation 比,差别在定位方式。AR Foundation 的平面检测做“地面放模型”这类场景很方便,但要做“识别一张指定图片并精确定位”,得自己写特征匹配或者接云端识别,时间成本翻倍。Vuforia 把这条路封装成了“上传图片—下载数据库—拖预制体”三步,代价是追踪质量高度依赖识别图本身的特征丰富程度和现场光照,这一块有时候挺玄学,后面单独讲参数。
还有一个容易忽略的点:Image Target 的原点在图像中心,模型放在它的 (0, 0, 0) 位置,正好站在识别图中心。建模软件里模型原点经常不在底面,这就会导致模型陷进图里,第 5 章会专门说这个坑。识别图的坐标方向按 Unity 惯例:图像平面是 XZ 面,Y 轴朝屏幕外。
2.2 动画载体怎么选:Animator、Legacy Animation 与 Timeline
识别链路解决“模型在哪”,动画链路解决“模型怎么动”。Unity 里能驱动动画的载体有三个,选错后面会返工:
| 载体 | 适合场景 | 优点 | 注意点 |
|---|---|---|---|
| Animator | 识别触发、状态切换、循环展示 | 状态机直观,条件驱动灵活 | 多 Clip 过渡要调好 Duration |
| Legacy Animation | 单段简单动画 | 代码少,Play 即可 | 多状态穿插不方便 |
| Timeline | 多步骤演示编排 | 时间轴可视化,事件精确 | 运行时控制要靠 PlayableDirector |
我一般这么定:单模型展示用 Animator,因为“识别→播放→循环”本质是状态切换。装配爆炸图、分步骤讲解这类需要精确排序的内容,用 Timeline 做主序列,Animator 只留在最外层做入口状态。识别一触发,主序列从头播放;识别丢失,序列暂停;恢复后从断点续播。这套分层的好处是,动画师可以在 Timeline 里独立调节奏,不用每次改脚本。
有一点必须提前说:交互动画和传统 UI 动画不一样,它的播放时机不完全由你控制,而是由追踪状态驱动。所以动画系统必须能回答三个问题:识别到了播什么、丢帧了停在哪、恢复了从哪继续。这三个问题回答不清楚,后面就会出现动画反复重播、模型原地抽搐这类翻车现场。
2.3 License 与识别图库准备:开工前必须做对的三件事
动手搭场景之前,有三件事必须做对,否则后面全是白忙:
第一,License Key。在 Vuforia 开发者门户创建许可证,Development 类型免费且足够调试用。拿到 Key 后在 Unity 的 Vuforia 配置面板里粘进去,AR Camera 初始化时会读这个全局配置。忘记填或者填错类型,真机上最常见的表现是相机黑屏或初始化失败,Editor 里反而不容易暴露。
第二,识别图数据库。在门户的 Target Manager 里创建 Database,上传识别图后系统会分析特征并给星级评级。导出时选 Unity 用的 Vuforia 包,下载导入后工程里会出现一个带识别图数据的预制体,直接拖进场景就完成绑定。这里有个习惯建议:数据库版本和代码一起提交到版本库,因为识别图更新后预制体 ID 会变,不同电脑不同版本之间容易互相覆盖。
第三,版本配套。建议用 Unity LTS 加配套的 Vuforia Engine 版本,新工程一次装好,别从老工程里半路升级。旧项目从 Asset Store 导入的 Vuforia 和新版 Package 混装,会出现两套 API 并存,编译报错指向不明的诡异问题。识别图评级这块,低于 3 星建议直接换图,具体标准第 4 章展开。
3. 搭建 AR 交互动画最小工程:场景、脚本与状态机
这一章的目标是 30 分钟内跑通一个最小闭环:相机识别到图,模型立起来播动画,手指能拖能缩放。这个闭环成立之后,再往里填业务内容。
3.1 创建 AR Camera 和 Image Target 场景的完整步骤
新建 Unity 工程,模板选 3D,版本用 LTS。按下面顺序操作,不要跳步:
- 从 Package Manager 导入 Vuforia Engine 包,导入完成后在菜单栏找到 Vuforia 的配置入口,把第 2.3 节的 License Key 填进去。
- 删除场景里默认的 Main Camera,从 Vuforia 菜单创建 AR Camera。AR Camera 负责相机画面渲染和追踪初始化,普通 Camera 干不了这个活。
- 从已导入的数据库资源里,把 Image Target 预制体拖进场景。如果工程里没有预制体,回到 Vuforia 菜单选择添加 Image Target,再手动指定数据库和识别图名称。
- 在 ImageTarget 这个节点下,创建空子物体 Alpha。把 3D 模型拖进 Alpha,让 Alpha 作为模型的居中容器。后续调位置只动 Alpha,不动模型本身。
- 给场景加一个 Directional Light,灯光角度对着识别图方向,因为下面的追踪质量测试需要光照。
最后一步是验证配置:运行工程,把带识别图的手机屏幕或打印件放到摄像头前,Game 视图里应该能看到跟踪框锁定识别图。如果相机画面黑屏,回 2.3 节检查 License;如果识别图上有网格但没跟踪框,检查数据库对应的识别图是否选对。
这里有个常见做法值得养成:把模型挂到 ImageTarget 子节点下,而不是挂到场景根节点。区别在于,识别图的位姿变化时,子节点会自动跟随,你不需要写任何同步代码;挂反了,模型就会停在原地,和现实中的识别图完全错位。
3.2 识别即触发动画的最小 C# 脚本
识别触发是这条链路的核心事件。注意用 Vuforia 10 以上推荐的 ObserverBehaviour 事件接口,早期教程里的 OnTrackableStateChanged 已经过时。新建脚本 AnimationTrigger.cs,挂在 ImageTarget 节点上:
using UnityEngine; using Vuforia; public class AnimationTrigger : MonoBehaviour { [SerializeField] private Animator targetAnimator; [SerializeField] private float triggerCooldown = 0.5f; private ObserverBehaviour observer; private float lastTriggerTime = -999f; private void Start() { // ObserverBehaviour 挂在 ImageTarget 上,负责上报追踪状态 observer = GetComponent<ObserverBehaviour>(); if (observer != null) { observer.OnTargetStatusChanged += OnTargetStatusChanged; } } private void OnTargetStatusChanged(ObserverBehaviour behaviour, TargetStatus targetStatus) { bool isTracked = targetStatus.Status == Status.TRACKED || targetStatus.Status == Status.EXTENDED_TRACKED; // 状态在 LIMITED 和 TRACKED 之间抖动时,用冷却时间挡掉重复触发 if (isTracked && Time.time - lastTriggerTime > triggerCooldown) { lastTriggerTime = Time.time; targetAnimator.SetTrigger("Show"); } } private void OnDestroy() { if (observer != null) { observer.OnTargetStatusChanged -= OnTargetStatusChanged; } } }这个脚本的逻辑只有一层:状态变为已追踪时,发一个 Trigger 给 Animator。targetAnimator 是序列化字段,在 Inspector 里拖目标 Animator;triggerCooldown 是防抖参数,手持不稳导致状态抖动时,0.3 到 0.6 秒比较稳,太小会反复触发,太大会让重识别响应变迟钝。
触发动画有个细节:TRACKED 和 EXTENDED_TRACKED 要不要分别处理,取决于你有没有开 Extended Tracking。开了,识别图移出画面后动画还能继续;没开,状态会直接回到 NOT_FOUND,动画要走暂停逻辑。如果发现这个脚本没反应,先在 OnTargetStatusChanged 里加一行 Debug.Log 打印 Status,确认事件有没有进来,再查状态机。
3.3 手势交互层:拖拽旋转与双指缩放的实现
交互动画不能只有“播放”,还得有“操作”。最简单的交互层是单指拖拽旋转、双指缩放,挂到模型容器 Alpha 上:
using UnityEngine; public class ModelTouchInteract : MonoBehaviour { [SerializeField] private float rotateSpeed = 0.12f; [SerializeField] private float minScale = 0.5f; [SerializeField] private float maxScale = 3f; private float prevTouchDistance; private void Update() { if (Input.touchCount == 1) { Touch touch = Input.GetTouch(0); if (touch.phase == TouchPhase.Moved) { // 水平滑动驱动模型绕 Y 轴旋转,Space.World 避免继承父节点转序 transform.Rotate(0f, -touch.deltaPosition.x * rotateSpeed, 0f, Space.World); } prevTouchDistance = 0f; } else if (Input.touchCount == 2) { Touch touch1 = Input.GetTouch(0); Touch touch2 = Input.GetTouch(1); float currentDistance = Vector2.Distance(touch1.position, touch2.position); // 用两指间距的比例做缩放,而不是绝对增量 if (prevTouchDistance > 0f) { float ratio = currentDistance / prevTouchDistance; float newScale = Mathf.Clamp(transform.localScale.x * ratio, minScale, maxScale); transform.localScale = Vector3.one * newScale; } prevTouchDistance = currentDistance; } else { prevTouchDistance = 0f; } } }两个参数说明:rotateSpeed 建议 0.08 到 0.15,数值越大越跟手,但过大模型会甩出去;minScale 和 maxScale 是缩放钳制,防止缩成负数或放大到穿透画面。旋转用 Space.World 是因为模型挂在 ImageTarget 子节点下,父节点本身在动,用局部空间会出现转序混乱。
这段代码用的是旧的 Input.touches 接口。如果项目启用了新输入系统,需要替换成 Touchscreen 读取,否则真机上触点无响应。另外,交互层不要直接改模型本身的 scale,应该改容器 Alpha,改模型的 scale 会连带影响它作为子节点的动画表现。
3.4 用 Animator 状态机把展示动画编排成可回放序列
脚本写完,动画侧要建一个最小的状态机,三个状态足够:
| 状态 | 进入条件 | 动画内容 |
|---|---|---|
| Idle | 初始 | 无动作 |
| Show | Trigger: Show | 模型从平面浮起并旋转入场 |
| Loop | Show 播到 75% 后自动过渡 | 持续旋转或轻微呼吸 |
Show 到 Loop 的连接要打开 Has Exit Time,Exit Time 设在 0.7 到 0.85 之间,Transition Duration 0.15 秒左右。设置太早会打断入场动作,太晚会让两段动画之间出现顿挫。Idle 到 Show 的连接不要开 Has Exit Time,让 Trigger 立即生效。
动画剪辑里还能嵌事件,在 Animation 窗口的对应帧添加 Animation Event,事件名写在函数参数里,再由接收脚本分发:
using UnityEngine; public class AnimationEventReceiver : MonoBehaviour { public AudioSource popSound; public ParticleSystem sparkEffect; // 事件名对应 Clip 时间轴上标记的名称 public void HandleClipEvent(string eventName) { switch (eventName) { case "pop": if (popSound != null) popSound.Play(); break; case "spark": if (sparkEffect != null) sparkEffect.Play(); break; } } }Animation Event 的触发时机跟着画面帧走,比脚本里用 Invoke 做延时精确得多,音效和粒子能卡在模型动作的节拍上。但事件名拼错了不会报错,只会静默失效,排查时先确认 Clip 的时间轴上确实有事件标记,再看接收脚本有没有挂在模型所在节点上。
4. 参数调优:识别更稳、动画不抖的三个关键设置
代码跑通只是开始,识别稳定性才是 AR 交互动画能不能用的分水岭。这一章的参数,是 Editor 里看不出来、必须拿到真机和真实光照下才能定的。
4.1 识别图评级与打印尺寸:先看图再写代码
识别图是这条链路的入口,图不行,后面全白搭。Vuforia 门户上传图片后会给星级评级,先把这个标准刻在脑子里:
| 评级 | 结论 |
|---|---|
| 5 星 | 特征丰富,适合做识别图 |
| 3 到 4 星 | 可用,但要控制遮挡和距离 |
| 低于 3 星 | 换图或改构图,别硬用 |
比星级更重要的是特征点分布。最常见的坑是特征全部集中在图像中心,四角是纯色背景,手机稍微一转,边角出画,追踪立刻丢失。改图时记住三个原则:增加高对比细节、避免大面积纯色、别用光面纸打印。图标、标题、边框都能提供特征,构图时尽量让四个角都有内容。
打印尺寸直接决定识别距离。A4 大小的识别图,手机距图 0.3 到 0.8 米效果最好;距离越远,图像在画面里越小,特征点越稀疏,识别越迟钝。做展会大屏项目时,识别物和观众之间的距离是固定的,先用卷尺量个大概,再定识别图物理尺寸,别在桌面上调好参数到现场才发现识别距离对不上。
4.2 对焦模式与 Extended Tracking:两个直接影响稳定性的开关
手机相机默认对焦模式在近距离识别时经常拉风箱,识别框会一抖一抖。先写一个对焦控制器,把焦点固定到连续自动对焦:
using UnityEngine; using Vuforia; public class AutoFocusController : MonoBehaviour { private void Start() { // 相机设备初始化完成后才能设置对焦,放在 Start 里执行 CameraDevice.Instance.SetFocusMode( CameraDevice.FocusMode.FOCUS_MODE_CONTINUOUSAUTO); } }这段代码在真机上能把近距离识别稳定性提升一个档次。要注意:SetFocusMode 返回 false 说明设备不支持连续对焦,低端机上需要做降级处理,回退到触发式自动对焦或普通模式。Editor 里模拟器的对焦行为和真机差异巨大,这个参数必须以真机为准,别在编辑器里调半天。
Extended Tracking 是另一个开关。它启用后,识别图移出画面时,Vuforia 会借用环境特征继续估算位姿,状态变为 EXTENDED_TRACKED。适合“模型从图面立起来后悬浮在空中展示”的场景,用户把手机移开,模型还能保持住。但它有个代价:位姿会随时间缓慢漂移,几秒后误差会变得明显。动画里如果有“贴图面”的元素,比如影子、文字标注,开 Extended Tracking 反而会穿帮。
不确定当前版本是否自动启用扩展追踪,最直接的办法是在状态回调里把 Status 打出来,看识别图出画后会不会自己切到 EXTENDED_TRACKED。会,就不管它;不会,再查当前版本的开启入口。
4.3 动画与追踪状态协调:识别抖动时怎么让动画不重播
第 3.2 节的冷却时间解决的是“重播”,但重播之外还有个“从头还是继续”的问题。手持手机时识别丢失是常态,每次恢复都从头播放,展示类内容会很烦人。更合理的做法是暂停在断点,恢复后从断点继续:
using UnityEngine; using Vuforia; public class AnimationResumeController : MonoBehaviour { [SerializeField] private Animator targetAnimator; [SerializeField] private string clipName = "Show"; private ObserverBehaviour observer; private float savedNormalizedTime; private void Start() { observer = GetComponent<ObserverBehaviour>(); observer.OnTargetStatusChanged += OnTargetStatusChanged; } private void OnTargetStatusChanged(ObserverBehaviour behaviour, TargetStatus targetStatus) { bool tracked = targetStatus.Status == Status.TRACKED || targetStatus.Status == Status.EXTENDED_TRACKED; if (tracked) { // 之前中断过就从断点续播,否则走正常触发 if (savedNormalizedTime > 0f) { targetAnimator.Play(clipName, 0, savedNormalizedTime); savedNormalizedTime = 0f; } else { targetAnimator.SetTrigger("Show"); } } else { // 丢失时记录进度并暂停,normalizedTime 是动画播放到第几秒的归一化值 if (targetAnimator.GetCurrentAnimatorStateInfo(0).IsName(clipName)) { savedNormalizedTime = targetAnimator.GetCurrentAnimatorStateInfo(0).normalizedTime; targetAnimator.speed = 0f; } } } }这套逻辑的价值在于,识别图短暂离开画面再回来,动画能无缝续上,而不是从头演一遍。需要注意:续播依赖 normalizedTime,这个值在循环动画里会涨过 1,不好控制,所以需要续播的 Clip 要关掉 Loop Time,让它播完一次就停在末尾。纯循环的展示动画,丢失时直接暂停、恢复时继续播放即可。
参数调整到这里,把几个关键数值汇总一下,新项目直接抄这份初始值:
| 参数 | 建议值 | 影响 |
|---|---|---|
| triggerCooldown | 0.3 到 0.6 秒 | 防抖,过大影响重识别响应 |
| rotateSpeed | 0.08 到 0.15 | 拖拽手感 |
| minScale / maxScale | 0.5 / 3.0 | 缩放钳制 |
| Show 的 Exit Time | 0.7 到 0.85 | 过渡时机,决定衔接顺滑度 |
| Transition Duration | 0.1 到 0.2 秒 | 状态切换过渡时间 |
5. AR 交互动画开发避坑指南:五个翻车现场与处理办法
这一章全是血泪经验,每一条都是我从真机测试里踩出来的。按“现象—原因—解决”的固定结构写,遇到直接对号入座。
5.1 真机黑屏或一直转圈:License 与相机权限的双重陷阱
现象:Editor 里一切正常,打包到真机后相机画面黑屏,或者一直转圈不初始化,控制台日志里能看到 Vuforia 初始化失败相关的报错。
原因:通常是三个叠加。License Key 没填或者填成了别的类型的 Key;Android 工程缺少相机权限,AndroidManifest 没有自动合并;识别图数据库没被打进 Build,运行时空数据库加载失败。
解决:先回 Vuforia 配置面板确认 Key 完整且类型匹配,Development Key 不能用在一个流量超过限制的正式包里。再检查 Player Settings 里 Android 的权限列表,相机权限必须存在,缺失就打开自动添加。最后在 Build 报告里确认 Vuforia 数据库资源确实在包里,排除掉这个环节后,再按“先 Editor 后真机”的顺序重新验证。
5.2 动画反复回弹重播:识别状态抖动引发的雪崩
现象:模型好不容易立起来,闪了一下立刻消失,又从头播放;手持不稳时尤其严重,动画像在原地抽搐。
原因:相机帧和识别图匹配在及格线附近波动,TargetStatus 在 TRACKED 和 LIMITED 之间来回切,而触发逻辑听着状态变化就发 Trigger,抖动会被放大成反复重播。
解决:3.2 节的 triggerCooldown 就是为此存在的。更稳的做法是加状态去抖:连续 N 帧(比如 5 帧)都处于 TRACKED 才认为识别成功,连续丢帧超过阈值才进入丢失态。去抖会带来约 0.1 秒的响应延迟,但换来的稳定感在展示类场景里完全值得。
5.3 模型埋地半截或悬浮:坐标单位与枢轴点
现象:模型一部分陷进识别图平面,或者整个悬浮在半空,怎么调都不对。
原因:两个。建模软件的单位和 Unity 不一致,导致导入后 scale 不是 1,模型尺寸失控;更常见的是模型原点不在底面,建模时原点在物体中心或某个角落,导入后 Unity 按中心对齐,半个模型就埋进了平面。
解决:导入模型时检查 File Scale,确保 1 个 Unity 单位对应 1 米,这个在模型导入面板里能直接看到。然后在 ImageTarget 下套一层空物体 Alpha,把模型拖进 Alpha,调整 Alpha 的 Y 坐标让模型底面正好落在 Y=0 的识别图平面上。以后所有位置修正都改 Alpha,绝不直接动模型顶点,这样换模型时不会把调整量一起丢掉。
5.4 材质变紫或模型变透明:渲染管线的兼容性问题
现象:Model 在 Editor 里颜色正常,真机上变紫,或者半透明部分完全穿透,交互动画看起来像残次品。
原因:项目用了 URP 或 HDRP 时,Vuforia 默认场景里的旧版标准着色器不兼容,显示为紫色。透明物体则是因为渲染队列排序不对,相机的深度写入和透明混合顺序没处理好。
解决:URP 工程里把模型的材质统一换成 URP/Lit,半透明材质用 Fade 模式而不是 Transparent,再手动调整 RenderQueue。检查相机组件的 Clear Flags 和 Depth 设置,AR Camera 的渲染顺序排在 UI 相机之前,UI 叠在上面才不会把模型盖掉。这类问题在 Editor 里经常被忽略,养成一个习惯:每周至少跑一次真机看渲染效果。
5.5 手机发热卡顿:交互动画开销失控
现象:识别正常,动画一播帧率掉到 20 以下,手机背面发烫,用户玩两分钟就想退。
原因:高模顶点数、实时阴影、骨骼动画的 CPU 开销,再加上 Vuforia 相机帧处理和 Unity 渲染,全部挤在移动 GPU 上。展示类模型动不动几十万面,是卡顿的主要来源。
解决:模型面数控制在手机能扛的范围内,高精度细节用贴图表达而不是堆顶点;关闭实时阴影,用一张暗色半透明贴图做假阴影,足以骗过眼睛;同一时间只允许一个 Trackable 处于激活播放状态。优化前用 Profiler 抓一段播放过程中的 CPU 和 GPU 曲线,看 Vuforia 相机处理占了多少、Animator 占了多少,再决定优先砍哪边。
6. 从 Demo 到可交付:验证清单与交互手感的两组技巧
Demo 跑通后,距离交付还有一段路,这一段拼的不是功能,而是验证方法和细节打磨。
6.1 固定机位与光照矩阵验证
识别系统最怕的是只在开发环境里验证。我的习惯是做一个验证清单:识别图分别用 A4 打印件和手机屏幕各测一轮;光照分强光、普通室内光、暗光三种;机位固定在三脚架上,分别距图 0.3 米、0.6 米、1 米录屏。每次调整参数后重跑一遍这套矩阵,把“哪组条件识别失败”记下来。你会发现同一个识别图,屏幕显示和打印在反光材质上的效果完全不同,打印尽量用哑光纸。
漂移测试要单独做:开启 Extended Tracking 后,识别图移出画面,观察模型在画面里停留多久开始偏移。能给用户容忍的漂移时间大约 2 到 3 秒,超过就关掉扩展追踪,改成丢失即暂停动画。录屏时顺手打开 Profiler 的帧耗时浮层,把这些数据留档,作为后续优化的基准。
6.2 用动画事件把音效、粒子和振动串成节奏
手感的好坏,往往不在模型动作本身,而在音效、粒子这些细节节奏。前面 3.4 节已经写了 Animation Event 的接收脚本,落地时注意一个原则:音效触发用动画事件而不是脚本延时。动画里的事件跟着画面帧走,模型动作到哪一帧,声音就在哪一帧起,天然同步;脚本里做 Invoke 延时,一旦真机帧率波动,声音就和动作错位。
最后说一个我的教训:第一次做这类项目时,我把触发逻辑写在 Update 里每帧检查追踪状态,结果识别抖动被放大成动画反复重播,排查了整整两天才意识到问题在“事件监听用错了地方”。后来统一改成 ObserverBehaviour 事件回调加状态去抖,这套代码复用到三个项目都没再出问题。交互动画的核心不是动画怎么做,而是“什么时候播、什么时候停、中断怎么续”这组状态机问题想清楚了,剩下的都水到渠成。希望帮到你。
本文还有配套的精品资源,点击获取