简介:面向Unity VR初学者与独立开发者的一套无头显开发配置与示例工程,重点解决没有Oculus Rift、HTC Vive等头显时,如何在桌面环境完成VR场景预览、交互调试与项目验证的问题。压缩包共2000个文件、约895.89MB,包含84个C#脚本、53个预制体、29个Unity场景、32个材质与14个Shader,以及大量asset项目配置、meta缓存和md、txt说明文档,覆盖VR摄像机、设备模拟、输入交互与示例场景等模块,目录体量完整。已有737人学习或下载,适合作为课程实践、毕设原型和VR交互入门的参考。读者可从中获取无头显环境下的XR Settings配置思路、基于预制体的双摄像机VR场景搭建方式、输入追踪与控制器交互的示例代码,以及材质光照和项目设置等配套内容;借助设备模拟器相关程序集与可运行场景,能较快理解无头显预览、键鼠模拟头盔移动旋转和后续真机迁移的流程。
1. 没头显也得开发:一次 Unity VR 工程在新机器上的配置复盘
第一次在没插头显的机器上打开 Unity VR 工程,我以为把场景按 Play 就完事,结果 Game 视图一片灰,手柄模型纹丝不动,Console 里只有一条 loader 初始化失败。后来才明白,无头显开发 VR 不是“少插一根线”,它要求把 XR 插件的启用顺序、输入系统和模拟器这三件事配齐,缺一项就黑屏或者相机不动。这套配置我在两台台式机和一台笔记本上重复过,覆盖 2021.3 到 Unity 6 的工程。谁最容易被卡住?接手别人 VR 工程、机器上没有头显、还得继续调交互逻辑的人。装不好不会报“你少装了插件”,只会给你一个静止的画面,让人以为代码写错了。
2. 环境先列清:Unity 版本、XR 插件包和平台模块的取舍
动手装之前,先把“用哪个 Unity、装哪些包、勾哪些平台模块”定下来,后面每一步都依赖这个前提。我见过太多人卡在第一步:Unity 装的是最新版,插件包从别的工程拷过来,结果 XR Plug-in Management 面板打开是空的,或者勾选 OpenXR 之后重启又变回未勾选。根本原因通常不是操作错,而是版本和包没对齐。
2.1 Unity 版本与渲染管线怎么定
Unity VR 的插件生态对版本敏感,核心是 XR Interaction Toolkit(下称 XRI)的大版本与 Unity 版本绑定。XRI 2.x 时代还能用旧版 Input Manager,到了 XRI 3.x 强制走 Input System,输入动作的结构也换了。所以选 Unity 版本实际上是在选 XRI 大版本。
| Unity 版本 | 常用 XRI | 无头显模拟的坑点 |
|---|---|---|
| 2021.3 LTS | 2.3.x | 需要额外装 XR Legacy Input Helpers,否则旧输入路径报空引用 |
| 2022.3 LTS | 2.5 / 2.6 | 模拟器已收进 Samples,导入路径稳定,我优先选这一档 |
| Unity 6(6000.x) | 3.x | Input System 成为硬依赖,XR Origin 层级结构调整,老工程的预制体直接拖进来会丢引用 |
我一般把工程固定在 2022.3 LTS 的最后一个补丁版本上,理由是 2.5 这一档的 XRI 既有完整的 XR Device Simulator 示例,又不需要处理 3.x 的结构变更。如果接手的是 Unity 6 工程,就先确认 Packages 里 XRI 是不是 3.x,再决定用哪套预制体,别把 2.x 的示例包往 3.x 工程里塞,十有八九是 Missing Script。
渲染管线方面,URP 和 Built-in 都能跑 VR,但 URP 要注意两件事:一是 Renderer 里勾上 SRP Batcher 对 VR 收益不明显,反而增加 shader 变体;二是 URP Asset 里的 HDR 和 MSAA 在移动端一体机上要关掉,否则双眼渲染的带宽直接翻倍。PC 端做无头显调试用 URP 完全没问题,只是记得把 Project Settings 里 Player 的 Color Space 改成 Linear,Gamma 空间下模拟器里的画面会发灰,你会误以为是模拟器渲染坏了。
还有一点常被忽略:切到 Android 平台时,Stereo Rendering Mode 建议用 Multiview,PC 端用 Single Pass Instanced。这个选项在 OpenXR 的 Rendering 设置里,不是 Player Settings 里的那个,后面 3.3 会细讲。
2.2 插件包清单:六个包一个都不能少
无头显配 VR,最少依赖这几个包。我按安装优先级列一下,后面的条目依赖前面的:
| 包名 | 作用 | 是否必装 |
|---|---|---|
| com.unity.xr.management | XR Plug-in Management 面板本体,负责启用 loader | 必装 |
| com.unity.xr.openxr | OpenXR loader 与功能组配置 | 必装 |
| com.unity.inputsystem | 新版输入系统,XRI 2.3 以后强依赖 | 必装 |
| com.unity.xr.interaction.toolkit | XRI 本体,含 XR Origin、Interactor、Grabbable | 必装 |
| com.unity.xr.core-utils | XRI 的依赖,通常随包自动解析,不用手动装 | 自动 |
| com.unity.xr.legacyinputhelpers | 2021.3 的 XRI 2.3 需要,2.5 之后基本不需要 | 视版本 |
装包有两条路。一条是 Window > Package Manager,左上角切到 Unity Registry,逐个搜索安装;另一条是直接改Packages/manifest.json,把依赖写进去让它自己解析。第二种在批量部署或者迁移工程时更稳,因为版本号写死在文件里,不会因为网络或缓存拿到不一致的版本。
{ "dependencies": { "com.unity.xr.management": "4.4.0", "com.unity.xr.openxr": "1.10.0", "com.unity.inputsystem": "1.7.0", "com.unity.xr.interaction.toolkit": "2.5.4" } }这段只列了四个关键包,实际 manifest 里还有一堆项目自带依赖,不要整份替换,按 key 合并进去。改完回编辑器,右下角会转圈解析,解析完成后 Project Settings 里才会出现 XR Plug-in Management 这一项。如果转完圈还是没出现,八成是包没拉到,先看 Console 有没有包解析失败的报错。
装完可以用一条命令确认包确实进了本地缓存,而不是只在 manifest 里写了个名字:
# 在工程根目录执行,列出已解析到本地的 XR 相关包目录 ls Library/PackageCache | grep -i "xr\.\|inputsystem"输出里应该能看到com.unity.xr.management@xxxx这样的目录,带版本号后缀。没有的话说明包没有真正下载成功,先解决网络和缓存,别急着往下配。
2.3 平台模块与安装体积
Unity Hub 装编辑器时默认只勾一个平台支持,这直接决定了 XR Plug-in Management 里能不能勾上 loader。我踩过最冤的一次:编辑器装了,工程也建了,OpenXR 死活勾不上,原因是 Windows Build Support 装的是 Mono 版本,没装 IL2CPP。
- 面向 PC 调试:Windows Build Support (IL2CPP) 必装,脚本后端要能切 IL2CPP。
- 面向 Android 一体机:Android Build Support 及其下的 SDK、NDK、OpenJDK 三个子项都要勾,少一个就打不了包。
- 只做编辑器内无头显调试:理论上 Mono 也能跑,但一旦要出包验证就会卡住,建议一次装全。
体积上有个心理准备,编辑器本体加两个平台模块,整个 Editor 目录通常在十几 GB 起步,再算上工程的 Library 缓存,几十 GB 很正常。装在系统盘上迟早会遇到空间告警,我一般单独划一个目录给 Hub 的安装路径,工程也放同盘,避免跨盘解析符号链接时出怪问题。
装完模块别急着新建工程,先在 Hub 里看一眼对应版本下勾选的模块列表,确认 IL2CPP 和 Android 那几项真的在。Hub 的进度条走完不等于装完,它有过装到一半网络断了但界面显示成功的情况,切换平台时报“找不到 Android 播放器”就是那时候留下的。
3. 无头显配置 OpenXR:从 Player Settings 到 Project Validation
环境齐了,接下来是把 OpenXR 这条路打通。这一章的顺序不能乱:先改 Player Settings 的基础项,再启用 loader,最后配交互配置和功能组。顺序反了会出现“勾了 OpenXR 但场景相机不跟随”的情况,排查起来非常费时间。
3.1 新工程的四个基础项先改掉
新建工程后,第一时间把这四项定下来,后面所有的 XR 配置都建立在这上面:
- Color Space 改成 Linear。
- Active Input Handling 改成 Input System Package (New),或至少 Both。
- Standalone 平台的脚本后端切 IL2CPP,架构勾 x86_64。
- Graphics API 保留默认,PC 端不用动,Android 端后面单独处理。
这四项里前两项可以写个编辑器脚本一次搞定,省得每次建工程手点。脚本放在Assets/Editor/目录下,菜单里就会出现入口:
using UnityEditor; using UnityEngine; // 放在 Assets/Editor/XRBaselineSetup.cs // 菜单入口:Tools/XR/Apply Baseline Settings public static class XRBaselineSetup { [MenuItem("Tools/XR/Apply Baseline Settings")] public static void Apply() { // 线性颜色空间,VR 下 Gamma 会让画面发灰、明暗对比失真 PlayerSettings.colorSpace = ColorSpace.Linear; // PC 端脚本后端走 IL2CPP,避免后面打包时才发现要重编 PlayerSettings.SetScriptingBackend( BuildTargetGroup.Standalone, ScriptingImplementation.IL2CPP); // 架构 1 表示 x86_64,OpenXR 的 loader 只认 64 位 PlayerSettings.SetArchitecture(BuildTargetGroup.Standalone, 1); AssetDatabase.SaveAssets(); Debug.Log("[XR] 基线设置已写入,Active Input Handling 请手动确认"); } }菜单执行后,前三条会落盘,最后一条我没写进脚本,因为 Active Input Handling 存在 ProjectSettings 的序列化字段里,用脚本硬改会触发编辑器重启,重启时如果还有编译错误就卡在半路。手动去 Project Settings > Player > Other Settings 里改更稳妥,改完编辑器会提示重启,让它重启即可。
Graphics API 这一项,PC 端保持 Auto 就行。Android 端要留意,Vulkan 和 OpenGLES3 的取舍在 5.2 那条坑里细说,这里先记着它是个开关。
3.2 启用 XR Plug-in Management 与 OpenXR Loader
Project Settings 里找到 XR Plug-in Management,第一次打开时它会提示 Install XR Plugin Management,如果 2.2 里已经把包写进 manifest,这里直接就是面板。
面板上是分平台的 tab,PC 对应 Standalone,一体机对应 Android。每个 tab 下的勾选是独立的,这是最容易翻车的地方:
- Standalone tab 下勾 OpenXR。
- 切到 Android tab,再勾一次 OpenXR。
切平台时如果忘记在对应 tab 下勾,运行时会提示找不到 loader。我见过有人在 PC tab 勾完,直接切 Android 打包,包能装上但一启动就黑屏,日志里是 loader 为 null。
勾完 OpenXR 后,面板下方会出现 OpenXR 的配置入口,点进去才是真正配功能组的地方。如果勾选框是灰的、点不动,说明 OpenXR 包没装好,回 2.2 检查 PackageCache 里有没有对应目录。
还有一点,勾选后会提示重启编辑器,按它说的重启。重启后再回来看一眼,确认勾还在。有些情况下重启后勾选被重置,通常是包版本和编辑器版本不匹配,比如把 XRI 3.x 的包放进 Unity 2021.3 里,这时候要退回去换包,不要硬试。
3.3 OpenXR 功能组与交互配置文件勾选
OpenXR 的配置面板分几块,无头显调试真正需要动的是这两块:Interaction Profiles 和 Rendering。
Interaction Profiles 决定手柄按键怎么映射。点加号,按你最终要面向的设备勾对应的 Controller Profile。PC 端调试时即使没有头显,也要勾一个 Profile,否则模拟器发出的输入动作没有绑定目标,抓取和扳机都是哑的。我一般勾一个最通用的手柄 Profile,模拟器走的就是它的按键映射。
Rendering 这一块有两个关键项:
| 配置项 | PC 端 | Android 一体机 | 说明 |
|---|---|---|---|
| Stereo Rendering Mode | Single Pass Instanced | Multiview | 选错会变成单眼渲染或直接黑屏 |
| Depth Submission Mode | None | Depth 16 或 Depth 24 | 需要深度交互的抓取遮挡才开,开了有性能开销 |
| Render Mode | 默认 | 默认 | 有特殊 UI 需求再动 |
Stereo Rendering Mode 是判断“你到底有没有在跑 VR”的第一个外观信号。设成 Single Pass Instanced 后,Game 视图在模拟器激活的状态下会呈现双眼画面,能明显看出视角偏移;如果选了 None,画面就是普通的单相机视角,很容易误判成模拟器没生效。
功能组下面还有一堆 Feature 开关,比如手部追踪、手势识别之类。无头显调试阶段我建议全部不勾,勾了之后模拟器不一定能提供对应输入,Console 会刷一堆输入缺失的警告,干扰你判断真正的错误。
3.4 Project Validation 里必须先清掉的几条
OpenXR 面板底部有个 Project Validation 折叠项,点开是一份当前工程的合规检查清单。这份清单在真机打包前必须清零,否则打出来的包大概率跑不起来。
常见的几条和对应处理:
- Color Space 不是 Linear:回 3.1 改,改完重启。
- Input System 未启用:Active Input Handling 还是旧的 Input Manager,改完重启。
- Android 的 Minimum API Level 过低:一体机通常要求 API 29 以上,在 Player Settings 里抬上去。
- Scripting Backend 不是 IL2CPP:Android tab 下切 IL2CPP,这一条几乎是必现问题。
- Graphics API 列表里存在不兼容项:Android 端把 OpenGLES3 之外的多余项移除。
面板上有 Fix All 按钮,我一般不用它。它会把能自动修的项一次性改掉,包括一些你不希望它动的设置,改完还得挨个回看改了什么。逐条点 Issue 后面的 Fix 更可控,改一条确认一条,心里有数。
清单全部变绿之后,先别急着打包,回到编辑器跑一次空场景。如果此时 Game 视图能显示出模拟器的视角,说明 loader 链路是通的,剩下的就是模拟器本身的事。
4. XR Device Simulator 顶替头显:预制体挂载与键位调参
OpenXR 打通之后,头显仍然没有,这时候顶上来的就是 XR Device Simulator。它的作用是把你键盘鼠标的操作翻译成 XR 设备的位姿和输入,让 XR Origin 以为自己在被头显驱动。听起来像个黑匣子,其实结构很简单:一个预制体加一张输入动作表。
4.1 从 Samples 导入模拟器并接进场景
模拟器不在包里,在 XRI 的示例里。打开 Package Manager,找到 XR Interaction Toolkit,右侧有 Samples 标签,列表里找 XR Device Simulator 这一项,点 Import。导入后资源落在Assets/Samples/XR Interaction Toolkit/<版本号>/XR Device Simulator/下面。
导入完成后,场景里需要三样东西,缺一样都跑不起来:
- XR Interaction Manager:空物体挂这个组件就行,全局只需要一个。
- XR Origin:提供相机和左右手控制器,相机上要有 Tag MainCamera。
- XR Device Simulator 预制体:拖进来即可,它自己会找 XR Origin。
顺序上先放 XR Interaction Manager,再放 XR Origin,最后拖模拟器,这样模拟器在 Awake 阶段能正确注册到管理器。反过来放的话,偶尔会遇到模拟器抢在管理器之前初始化,表现为手柄模型有了但抓取没反应。
还有一处必做:删掉新场景自带的 Main Camera。XR Origin 内部已经有一台相机,场景里再留一台默认相机,两个 MainCamera 标签同时存在,Game 视图显示的是默认相机,你看到的是普通视角,会误以为模拟器没生效。这个坑我踩过一次,排查了半小时。
4.2 键位映射表与几个要改的参数
模拟器的默认键位我列一份常用的,不同 XRI 版本略有差异,最终以预制体上 XRDeviceSimulator 组件的提示或者它自带的控制面板为准:
| 操作 | 默认键位 |
|---|---|
| 旋转视角 | 按住鼠标右键并移动 |
| 前后左右平移 | 按住鼠标右键 + W/A/S/D |
| 升降 | 按住鼠标右键 + Q/E |
| 切换左手 / 右手 / 无 | Tab |
| 扳机 Trigger | 鼠标左键 |
| 抓握 Grip | 按住 G |
| 菜单键 | 键盘上对应按键,看模拟器面板提示 |
第一次用最容易懵的是:旋转视角必须按住右键。很多人以为直接移动鼠标就能转,结果镜头一动不动,判定成配置失败。这一条写在模拟器面板的顶部提示里,但位置不显眼。
参数上有几个值得改的:
- XR Origin 的 Camera Y Offset:站着调试设 1.36,坐着设 1.2 左右,太矮会一直仰视物体,太高会看不到地上的东西。
- 相机的 Clipping Planes Near:默认 0.3 太大,手伸到眼前会穿模,改成 0.05。
- 模拟器的移动速度 / 旋转速度:默认值在房间里够用,但示例场景跨度大的时候,平移会显得很慢,可以在 XRDeviceSimulator 组件的输入动作里调 Translation Speed 相关参数。
这些参数不涉及代码,改完即时生效,运行中也能调,调到手感舒服再退出,改动会保存到预制体上。注意是改场景里的实例还是改预制体资源,两者要分清楚,改实例不会影响其他场景。
4.3 示例源码与预制体的接入顺序
这份资源里带的示例源码和预制体,本质是一套已经配好的交互场景。接入自己的工程时,顺序很关键,乱序会导致引用丢失。
正确的做法是整目录迁移,而不是只拷 prefab 文件:
- 先在原工程里确认示例用的是哪个 XRI 版本,和目标工程对齐。
- 把示例的资源目录整体拷贝到目标工程的 Assets 下,保留相对路径。
- 打开示例场景,确认 XR Origin 上的组件引用都还在,特别是输入动作资产。
- 再把自己的场景需要的预制体单独拖过去,逐个检查 Inspector 里有没有 None。
只拷预制体是最常见的错误,预制体上挂的 MonoBehaviour 会变成 Missing Script,看起来像工程坏了,其实是脚本没跟着过来。材质也一样,示例里的材质引用的是包内路径,迁移时如果路径变了,物体会变成粉色。
接入之后,检查两处引用:一是 XR Origin 上 XRController 组件的 Input Action Asset 有没有被清空;二是预制体上 XRGrabInteractable 的 Interaction Layer Mask 有没有和目标工程的层对上。这两处任何一处为空,表现就是手柄能靠过去但抓不起来,而 Console 一句话都不报。
5. 避坑排查:无头显跑 VR 最容易翻车的五处
这一章的五条,全部是我实际遇到过的。每一条都按“看到什么现象、原因是什么、怎么解决”写,照着自己对号入座就行。
5.1 编辑器里卡住的三处
第一条:OpenXR 勾选框是灰的,或者勾了重启又没了。
现象是 XR Plug-in Management 面板里 OpenXR 前面的复选框点不动,或者能点但重启编辑器后自动取消。原因基本是两个:一是当前 Build Target 和面板 tab 不一致,比如你在 PC tab 勾了,但 Build Target 还停在 Android;二是对应的平台模块没装全,编辑器找不到该平台的 loader 实现。
解决顺序是先看 Build Target 和 tab 对不对,切到 Android 后要在 Android tab 里重新勾一次。如果 tab 一致还是灰的,退出编辑器,回 Unity Hub 看这个版本下 Windows Build Support (IL2CPP) 或 Android Build Support 是否真的勾上了。Hub 里显示已安装但实际缺文件的概率不高,真正高的是当初装的时候只勾了“Windows Build Support (Mono)”,那就只能补装。
第二条:按 Play 后画面完全静止,移动鼠标没有任何反应。
现象是 Game 视图有画面,但视角不跟着鼠标动,键盘也没反应。原因通常不是模拟器坏了,而是场景里有多台 MainCamera。新建场景自带一台,XR Origin 里还有一台,两者都带 MainCamera 标签,Game 视图渲染的是前者,那台相机是静止的。
解决是删掉场景里自建的 Main Camera,只留 XR Origin 里那台,并确认它的 Tag 是 MainCamera。删完如果画面变成一片纯色,那说明 XR Origin 的相机位置或者 Clipping 设置有问题,去看看 Camera Offset 的数值有没有被误改成很大。
第三条:手柄能伸出去,但抓不住东西,Console 什么都不报。
现象是模拟器驱动的手柄模型能跟着鼠标移动,靠近物体时没有高亮,按 G 也不抓。原因是链路上断了一环,常见的有三种:场景里没有 XR Interaction Manager,或者物体上只有 Collider 没有 Rigidbody,或者 Interactor 和 Interactable 的 Interaction Layer Mask 不重合。
排查顺序是从管理器开始:搜索场景里有没有 XR Interaction Manager 组件,没有就补一个。有了再看物体,XRGrabInteractable 要求物体带 Collider 和 Rigidbody,缺 Rigidbody 时物理交互直接不触发。最后看层,Interactor 上有一个 Interaction Layer Mask,Interactable 上也有一个,两者必须有交集,默认都在 Default 层时是没问题的,但从别人工程拷过来的预制体经常被设成自定义层,这时候就哑了。
5.2 打包与运行时崩的两处
第四条:同时启用 Mock HMD 和 OpenXR,追踪数据错乱或者初始化失败。
现象是编辑器里一切正常,切到某些场景后手柄位置乱跳,或者启动时直接报 loader 初始化异常。原因是 Mock HMD 和 OpenXR 都是 loader,同一平台上同时启用会争抢初始化,谁先起来看运气。Mock HMD 的作用是给你一个假的双眼显示,用来在完全没有 XR 输入的情况下验证渲染路径,它和模拟器不是一回事。
解决很简单:同一个平台 tab 下只保留一个 loader。做无头显交互调试时用 OpenXR + XR Device Simulator;只验证双眼渲染效果、不需要手柄输入时,才切到 Mock HMD,而且切之前把 OpenXR 取消勾选。两者不要同时开。
第五条:Android 一体机打包成功,装上后黑屏或只显示一只眼。
现象是 APK 能装能启动,但进去之后是黑的,或者画面只占左半边,右眼没有内容。原因集中在三处:Stereo Rendering Mode 和平台不匹配、Graphics API 列表里残留了不兼容项、Minimum API Level 低于设备要求。
解决是回 Project Settings 一条条过:OpenXR 的 Rendering 里 Android 端改成 Multiview;Player Settings 的 Graphics API 移除多余项,只留设备支持的;Minimum API Level 抬到 29 以上;脚本后端确认是 IL2CPP。改完重新走一遍 Project Validation,把红色条目清零再打包。只显示一只眼这个现象,十次有八次是 Stereo Rendering Mode 选错,不是渲染管线的问题。
打包验证阶段还有个习惯:连上设备后用日志看启动流程,比盯着黑屏干猜强。启动日志里能直接看到 loader 名字和 stereo mode,一眼就知道打包时配置有没有带进去。
6. 装完怎么验证:用一段日志脚本确认 OpenXR 和模拟器都在线
配置全部做完之后,不要靠“画面看起来像 VR”来判断成功,那只是外观。我一般在场景里挂一个一次性脚本,启动时把当前 XR 上下文打印出来,五秒钟就能确认三件事:loader 有没有起来、设备是不是激活状态、输入设备有没有被识别到。
using System.Collections.Generic; using System.Text; using UnityEngine; using UnityEngine.XR; using UnityEngine.XR.Management; // 挂在场景任意物体上,启动时打一份 XR 上下文快照 public class XRContextReport : MonoBehaviour { void Start() { var sb = new StringBuilder(); var mgr = XRGeneralSettings.Instance?.Manager; // activeLoader 为 null 说明 OpenXR 没被启用,或当前平台 tab 没勾 sb.AppendLine($"[XR] loader = {(mgr?.activeLoader != null ? mgr.activeLoader.name : "none")}"); // isDeviceActive 在模拟器下应为 true;stereoMode 能看出是单眼还是双眼 sb.AppendLine($"[XR] deviceActive = {XRSettings.isDeviceActive}, stereo = {XRSettings.stereoRenderingMode}"); var devices = new List<InputDevice>(); InputDevices.GetDevices(devices); foreach (var d in devices) { // 模拟器会注册 HMD 和左右手控制器,数量不对就是模拟器没挂上 sb.AppendLine($"[XR] device: {d.name} / {d.characteristics}"); } Debug.Log(sb.ToString()); } }这段脚本没有任何运行时开销,验证完可以删掉,也可以留在工程里当常驻自检。看输出的要点是:loader 那行必须是 OpenXR,显示 none 说明 loader 没启用;deviceActive 必须是 true;设备列表里至少要有头显和两个控制器,只有头显没有控制器,通常是对应的 Interaction Profile 没勾。
除了脚本,我还会跑一遍下面这张检查表,四项全过才算真的配好:
| 检查项 | 通过标准 | 不通过时先看哪 |
|---|---|---|
| loader 状态 | 日志里显示 OpenXR | 平台 tab 是否勾选、模块是否装全 |
| 双眼渲染 | Game 视图有明显左右视角偏移 | Stereo Rendering Mode 是否为 Single Pass Instanced |
| 手部输入 | 手柄模型跟随鼠标、按键有响应 | 模拟器预制体是否在场景、Interaction Profile 是否勾选 |
| 抓取交互 | 靠近物体高亮、按 G 能抓起 | XR Interaction Manager、Rigidbody、Interaction Layer Mask |
这套流程我后来固化成了一个习惯:每换一台机器,先建一个空工程把这四条跑通,再往里导别人的工程。因为空工程能跑通,说明环境没问题,剩下的错误一定在工程配置里;空工程都跑不通,那就别在业务场景里浪费时间排查。有一次我跳过这一步,直接打开一个从别人那儿拷来的 VR 场景,调了一下午才发现是那台机器压根没装 IL2CPP,跟工程一点关系都没有。从那以后我每次换机器都强制走一遍这四条,多花十分钟,省下的是半天。
希望这套配置能帮你把无头显的环境一次点通,示例源码和预制体拿到手之后,先照着第 6 章跑一遍验证,再往里加自己的逻辑。
本文还有配套的精品资源,点击获取