关于 hz-unity-code-review
hz-unity-code-review 是用于审查面向 Meta VR 头显的 Unity C# 代码和项目设置的技能,重点检查性能、渲染、输入、内存、物理和音频,并介绍使用 metavr 验证构建和设备行为。
主要功能
- 01审查 Meta VR 渲染设置
- 02绘制调用与着色器指南
- 03检查 GC 分配和热点代码
- 04审查控制器、手势与眼动输入
- 05检查物理和音频配置
- 06metavr 设备验证指南
适用场景
- 01审查 Unity 代码中的 VR 性能问题
- 02检查渲染和 XR 项目设置
- 03核对多种 VR 输入方式的处理
- 04在已连接的 Meta VR 设备上验证构建
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ meta-quest/ agentic-tools --skill hz-unity-code-review安装后在 Claude Code 中输入/hz-unity-code-review确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/common-pitfalls.mdinput-handling.mdperformance-checklist.mdrendering-best-practices.md详细介绍
面向 Meta VR 的 Unity 代码审查
使用时机
在审查面向 Meta VR 头显的 Unity C# 代码或项目设置时使用此技能。包括:
- 审查脚本中的 VR 性能问题
- 检查渲染管线配置和设置
- 确保遵循 Meta VR 特定的最佳实践
- 识别常见的 VR 开发陷阱
- 验证控制器、手部和眼动追踪的输入处理
- 审计内存用量和 GC 分配模式
重点审查领域
1. 渲染管线配置
Meta VR 应用必须使用经过特定设置优化的通用渲染管线(URP),以适配移动 VR。不建议在新的 Meta VR 项目中使用内置渲染管线。
需要核查的关键设置:
- 必须启用单通道多视图(Player Settings > XR Plug-in Management > Oculus > Stereo Rendering Mode)
- Vulkan 应作为主要图形 API
- 必须使用线性颜色空间,以确保光照正确
- 应在 URP 资源设置中禁用 HDR
- 后期处理应尽量精简或禁用
2. 绘制调用预算与批处理
Meta VR 的绘制调用预算因工作负载复杂度而异。每次绘制调用都会带来 CPU 开销,直接影响帧时间。
| 指标 | Quest 2 / Quest Pro | Quest 3 / Quest 3S | Meta VR Glasses |
|---|---|---|---|
| 绘制调用(繁忙模拟) | 80-200 | 200-300 | 200-300 |
| 绘制调用(中等模拟) | 200-300 | 400-600 | 400-600 |
| 绘制调用(轻量模拟) | 400-600 | 700-1000 | 700-1000 |
| 每帧三角形数 | 750K-1M | 1M-2M | 1M-2M |
| SetPass 调用 | < 50 | < 80 | < 80 |
启用并核查:
- 对非移动几何体启用静态批处理
- 对重复对象启用 GPU 实例化
- 对 URP 材质启用 SRP Batcher
- 对小型网格(< 300 个顶点)启用动态批处理
3. 着色器复杂度
Meta VR 上的移动 GPU 无法处理桌面级着色器。审查所有材质,确保:
- 使用 URP/Lit 或 URP/Simple Lit,而不是 Standard 着色器
- 自定义着色器尽量减少纹理采样和 ALU 运算
- 尽可能避免实时阴影(改用烘焙)
- 不使用屏幕空间效果(SSAO、SSR、屏幕空间阴影)
4. 内存管理
GC 分配会造成帧卡顿,必须从热点路径中消除。
// BAD: Allocates every frame
void Update() {
string label = "Score: " + score.ToString();
var enemies = FindObjectsOfType<Enemy>();
var filtered = enemies.Where(e => e.IsAlive).ToList();
}
// GOOD: Zero allocations in Update
private StringBuilder _sb = new StringBuilder(32);
private List<Enemy> _enemyCache = new List<Enemy>();
private Enemy[] _enemyArray;
void Start() {
_enemyArray = FindObjectsOfType<Enemy>();
}
void Update() {
_sb.Clear();
_sb.Append("Score: ");
_sb.Append(score);
}
5. 输入处理
Meta VR 支持多种输入方式。代码应处理:
- 控制器:新项目使用 Unity 的 Input System Package(推荐);
OVRInput仍维护用于旧版支持 - 手部追踪:使用
OVRHand和OVRSkeleton获取手部姿势数据 - 眼动追踪:使用
OVREyeGaze(Quest Pro / Meta VR Glasses,需要权限) - 在控制器与手部追踪模式之间平滑切换
6. 物理配置
物理模拟在移动设备上开销较大。审查以下内容:
- 将物理时间步长设为与目标帧率(72/90/120 Hz)匹配
- 使用简化的碰撞网格(使用基本形状,而非网格碰撞体)
- 减少求解器迭代次数(通常 4-6 次就足够)
- 使用基于层的碰撞矩阵,尽量减少碰撞对检查
- 适当配置 Rigidbody 睡眠阈值
7. 音频设置
音频常被忽视,但可能影响性能:
- 压缩音频片段(音乐使用 Vorbis,短音效使用 ADPCM)
- 对长度超过 1 秒的片段使用流式加载类型
- 限制同时播放的音频源数量(目标 < 16)
- 使用 Meta 的音频 SDK 对音频进行空间化,实现 3D 定位
快速审查清单
| 范围 | 目标 | 说明 |
|---|---|---|
| 绘制调用 | 80-200(繁忙场景)至 400-600(轻量场景) | 使用批处理、实例化和图集 |
| 三角形数量 | 750K-1M/帧 | 使用 LOD 和遮挡剔除 |
| 纹理分辨率 | 最高 2K,谨慎使用 4K | 必须使用 ASTC 压缩 |
| 着色器 | URP 移动端着色器 | 不使用 Standard 着色器或屏幕空间效果 |
| 渲染模式 | 单通道多视图 | 必须在 XR 设置中启用 |
| FFR | 已启用(High 或 HighTop) | 固定注视点渲染可降低边缘片元开销 |
| MSAA | 4x 画质 / 2x 性能 | 配置正确时,在基于 tile 的 GPU 上无需额外开销 |
| 目标帧率 | 最低 72 Hz | 建议 90 Hz,流畅体验可使用 120 Hz |
| GC 分配 | 稳定运行时为 0 B/帧 | 不要在 Update/LateUpdate/FixedUpdate 中分配内存 |
| 音频源 | 同时播放少于 16 个 | 使用对象池管理音频源 |
代码审查要点
高 GC 开销模式
// Flag these patterns in code review:
Camera.main // Calls FindWithTag internally
GameObject.Find("name") // Linear search every call
GetComponent<T>() in Update // Cache the result
new List<T>() in Update // Allocates on heap
string + string in Update // Creates new string objects
foreach on non-List collections // Enumerator allocation
LINQ queries (.Where, .Select) // Multiple allocations
Boxing (int -> object) // Heap allocation
delegate/lambda in hot paths // Closure allocation
滥用 Update()
// BAD: Empty Update still has overhead
void Update() { }
// BAD: Logic that doesn't need per-frame execution
void Update() {
SavePlayerPrefs(); // Should be event-driven
}
// GOOD: Use events, coroutines, or InvokeRepeating for non-per-frame logic
void OnScoreChanged(int newScore) {
UpdateScoreUI(newScore);
}
Camera.main 反模式
// BAD: Camera.main uses FindWithTag internally
void Update() {
transform.LookAt(Camera.main.transform);
}
// GOOD: Cache the reference
private Transform _cameraTransform;
void Start() {
_cameraTransform = Camera.main.transform;
}
void Update() {
transform.LookAt(_cameraTransform);
}
热路径中的 Find 调用
// BAD: Expensive search every frame
void Update() {
var player = GameObject.FindWithTag("Player");
var rb = player.GetComponent<Rigidbody>();
}
// GOOD: Cache in Awake/Start or use dependency injection
private Rigidbody _playerRb;
void Awake() {
_playerRb = GameObject.FindWithTag("Player").GetComponent<Rigidbody>();
}
使用 metavr 进行验证
你可以使用 metavr 工具验证构建并检查设备端行为。通过 metavr <args> 调用(以 npm 包 metavr 发布;如果 metavr 不在 PATH 中,请运行 npx -y metavr <args>)——无需安装。
# Check connected Meta VR device
metavr device list
# Install and run a build
metavr app install path/to/build.apk
metavr app launch com.company.app
# Check device logs for errors
metavr adb logcat --tag Unity
# Monitor GPU performance
metavr perf capture
使用设备端性能分析,验证代码审查中的发现是否能带来实际性能提升。
参考文档
如需了解特定主题的详细指南,请参阅以下参考文档:
评论
支持 Markdown