第 19 课
菜单界面的框架搭建
本课将先确定菜单在三维空间中的大小和朝向,再分别搭建右侧页面区与左侧导航区。你会创建适合 PICO 手柄射线交互的 XR 世界空间画布,使用拉伸锚点规划页面区域,并通过九宫格切片保护两种背景图片的圆角。完成后,整套菜单能够共同移动和显示,两个区域又能按照各自的布局规则稳定响应画布尺寸变化。
搭建三维系统菜单的界面框架
在虚拟博物馆中建立一套“左侧选择功能、右侧查看内容”的世界空间菜单,为后续加入导航按钮、项目介绍、场馆导航和系统设置做好布局基础。
学完你将能够
学习目标
- 说明系统菜单为什么采用左侧导航栏与右侧页面区的分区方式。
- 说出 MenuUI、PageContainer 和 NavigatorBar 各自承担的任务。
- 区分屏幕空间画布与世界空间画布。
- 解释 Tracked Device Graphic Raycaster 如何帮助手柄射线识别界面。
- 创建尺寸为 980 × 550、缩放为 0.001 的 XR 世界空间画布。
- 根据画布宽高与缩放估算它在三维场景中的实际尺寸。
- 使用完整拉伸锚点和四边偏移量建立右侧页面区。
- 区分锚点与轴心点的作用。
- 使用圆角精灵图和 Sliced(九宫格切片)制作可伸缩背景。
- 为导航栏图片设置上、下保护边界。
- 使用左中锚点固定导航栏的尺寸与相对位置。
- 区分 NavigatorBar 场景对象与 NavigationBar 图片资源。
- 根据画布朝向、圆角变形和锚点错位等现象定位问题。
开始操作前
准备工作
- 打开虚拟博物馆主场景,确认 XR Origin 可以正常运行。
- 确认 XR Interaction Toolkit 已安装,并能在 GameObject > XR 中找到 UI Canvas。
- 确认场景中已有适用于 XR 界面的 EventSystem(事件系统)。
- 打开 Hierarchy(层级面板)、Inspector(属性面板)和 Scene(场景窗口)。
- 确认自己能够创建、选择和重命名场景对象。
- 确认自己能够调整 Rect Transform(矩形变换)中的锚点、位置和尺寸。
- 确认图片可以设置为 Sprite (2D and UI),并能打开 Sprite Editor。
- 保存当前场景;如果已有大型界面遮挡观察,可以先暂时隐藏,完成菜单后再恢复。
本课学习路线
按照学习模块逐步完成
每个模块都包含理解、跟随操作和独立实践。让菜单真正位于三维场景中
创建 XR 世界空间画布
普通应用中的菜单通常固定在屏幕上,而虚拟现实菜单需要像场景物体一样拥有位置、旋转和缩放。本项目使用 XR UI Canvas,它既能放入三维空间,也会准备适合手柄射线识别界面的组件。屏幕空间与世界空间
World Space 可以理解为“世界空间”,适合把菜单放在展厅中的具体位置。
左右滑动表格,可查看完整内容
| 对比项目 | 屏幕空间画布 | 世界空间画布 |
|---|---|---|
| 显示位置 | 固定在显示画面上 | 位于三维场景中 |
| 场景属性 | 不按普通场景平面使用 | 具有位置、旋转和缩放 |
| 观察方式 | 不按场景距离变化 | 可以从不同距离观察 |
| 本项目用途 | 不使用 | 用于三维系统菜单 |
手柄射线怎样找到界面
Tracked Device Graphic Raycaster 可以理解为“跟踪设备图形射线检测器”。Tracked Device 指能够提供位置和方向的 PICO 手柄,Graphic 指画布中的图片、文字和按钮,Raycaster 指沿射线寻找命中的组件。
交互时,手柄或射线交互器先指向世界空间画布,射线检测器判断命中了哪个界面图形,再由 EventSystem 把事件发送给按钮等元素。本课暂不放置按钮,但从一开始使用 XR UI Canvas,可以让后续交互建立在正确画布上。
建立 MenuUI
- 01
在顶部菜单选择 GameObject > XR > UI Canvas。
- 02
在层级面板中找到新创建的 Canvas,并重命名为 MenuUI。
- 03
确认 Canvas 组件的 Render Mode 为 World Space。
- 04
确认 Event Camera 指向 Main Camera。
- 05
保留 Canvas Scaler 与 Tracked Device Graphic Raycaster 等 XR UI 组件。
- 06
在 Rect Transform 中把 Width 设置为 980,Height 设置为 550。
- 07
把 Scale X、Scale Y、Scale Z 都设置为 0.001。
- 08
把画布移动到展厅中方便观察的位置,并从正面进行编辑。

重点核对画布宽高、三个缩放值和 World Space。场景位置可以按展厅空间调整,不必机械照抄截图坐标。
点击图片可以查看完整截图MenuUI 的核心属性
界面设计尺寸与三维实际尺寸由不同属性共同决定。
左右滑动表格,可查看完整内容
| 属性 | 本课数值 | 作用 |
|---|---|---|
| Width | 980 | 提供横向界面排版空间 |
| Height | 550 | 提供纵向界面排版空间 |
| Scale | 0.001, 0.001, 0.001 | 控制画布在场景中的实际大小 |
| Render Mode | World Space | 让画布成为三维场景中的平面 |
估算画布的实际尺寸
在父对象缩放为 1 的情况下,实际宽度约为 980 × 0.001 = 0.98 米,实际高度约为 550 × 0.001 = 0.55 米。
因此不要为了缩小画布而把 Width 改成 0.98。宽高负责界面排版,Scale 才负责把整套界面缩小到适合虚拟现实观察的尺寸。
判断画布方向
世界空间画布有正面和背面,本地 Z 轴可以帮助判断朝向。
左右滑动表格,可查看完整内容
| 观察现象 | 可能原因 | 处理方法 |
|---|---|---|
| 左右看起来相反 | 当前在画布背面 | 绕到另一侧观察 |
| 界面背对预期方向 | 画布朝向相反 | 根据空间需要把 Rotation Y 调整 180° |
| 射线从背面无法操作 | 交互方向与画布正面不一致 | 让画布正面朝向体验者 |
确认画布大小与朝向
创建 MenuUI 后,从场景中的不同位置观察它,并解释界面尺寸和实际尺寸的关系。
- 确认画布来自 GameObject > XR > UI Canvas。
- 确认画布名称为 MenuUI,渲染方式为 World Space。
- 核对 980 × 550 与三个 0.001。
- 沿本地坐标轴判断正面,并让正面朝向体验者。
- 说明画布实际宽度为什么约为 0.98 米。
用边距约束填满剩余空间
用拉伸锚点建立右侧页面区
PageContainer 是承载项目介绍、场馆导航和系统设置等页面的共同容器。它需要填满画布右侧,并在 MenuUI 尺寸变化时继续保持四边距离,因此使用横向、纵向完整拉伸,而不是写死宽高。锚点与轴心点解决不同问题
Anchor(锚点)表示子对象把位置关系系在父对象的哪里。锚点坐标通常在 0 到 1 之间,例如 (0, 0) 是父对象左下角,(1, 1) 是右上角。
Pivot(轴心点)位于子对象自身内部,决定旋转、缩放和位置计算以哪里为中心。可以记成:锚点回答“我系在父对象哪里”,轴心点回答“我自己的中心在哪里”。
把 PageContainer 设置为双向拉伸
- 01
在层级面板中右击 MenuUI,选择 UI > Image。
- 02
把新对象重命名为 PageContainer。
- 03
确认 PageContainer 是 MenuUI 的直接子对象。
- 04
打开 Rect Transform 左上角的锚点预设面板。
- 05
按住 Alt + Shift,选择横向、纵向都拉伸的预设。
- 06
确认 Anchor Min 为 (0, 0),Anchor Max 为 (1, 1)。
- 07
确认属性栏已经从位置与宽高切换为 Left、Right、Top、Bottom。

观察锚点标记:它覆盖父对象的完整范围;Rect Transform 显示四边偏移量,而不是固定 Width 与 Height。
点击图片可以查看完整截图锚点预设中的组合键
Alt + Shift 可以一次完成锚点、轴心点和边界对齐,操作后仍要核对最终数值。
左右滑动表格,可查看完整内容
| 按键 | 作用 |
|---|---|
| Shift | 同时设置轴心点位置 |
| Alt | 同时把对象边界对齐到所选锚点 |
| Alt + Shift | 同时设置锚点、轴心点和对象边界 |
设置四边偏移量
- 01
把 Left 设置为 202.45,为左侧导航栏预留空间。
- 02
把 Right 设置为 0.05,使右边缘几乎贴住父画布。
- 03
把 Top 设置为 0,使上边缘贴住父画布。
- 04
把 Bottom 设置为 0,使下边缘贴住父画布。
- 05
确认页面容器只占据右侧区域,没有覆盖左侧导航空间。
PageContainer 布局参数
完整拉伸后,Unity 根据父画布尺寸和四边偏移量计算页面容器宽高。
左右滑动表格,可查看完整内容
| 属性 | 数值 | 布局含义 |
|---|---|---|
| Anchor Min | (0, 0) | 锚定父对象左下角 |
| Anchor Max | (1, 1) | 锚定父对象右上角 |
| Left | 202.45 | 为左侧导航栏保留区域 |
| Right | 0.05 | 右侧几乎贴边 |
| Top | 0 | 上侧贴边 |
| Bottom | 0 | 下侧贴边 |
用偏移量算出页面区域
父画布宽度为 980,因此 PageContainer 宽度约为 980 - 202.45 - 0.05 = 777.5。父画布高度为 550,因此高度为 550 - 0 - 0 = 550。
当父画布宽度增加时,页面容器会自动增加宽度,左侧 202.45 和右侧 0.05 的距离仍然保持。相比固定写入 777.5,这种布局更适合后续调整菜单尺寸。
比较两种响应:页面容器依靠分开的锚点改变尺寸;导航栏依靠重合的左中锚点保持固定尺寸。下一步将分别完成两种布局。
手机上可左右滑动;点击图片可以查看完整图观察拉伸布局的响应
临时改变父画布宽度,观察 PageContainer 是否继续保持四边约束。
- 把 MenuUI 宽度从 980 临时改为 1080。
- 观察 PageContainer 宽度随父画布增加。
- 确认左侧预留空间仍约为 202.45。
- 把 MenuUI 宽度恢复为 980。
- 根据公式算出 PageContainer 的 777.5 × 550。
用九宫格保护四个圆角
制作可伸缩的圆角页面背景
正方形圆角图片如果被整体拉成长矩形,四角会变成扁椭圆。Unity 的 Sliced 表示“九宫格切片”:四角尽量保持形状,边缘和中心区域承担尺寸变化,适合制作需要自由伸缩的页面背景。下载圆角页面背景
下载后放入 Unity 的界面图片目录,并可将资源重命名为 Round Radius,便于在 Source Image 中识别。
- 图片具有透明圆角,适合作为页面容器背景。
- 导入后确认 Texture Type 为 Sprite (2D and UI)。
- 如果项目中已有同名圆角资源,可以直接使用现有资源。
确认 Round Radius 已具有九宫格边界
- 01
如果沿用上一课已经配置好的 Round Radius,可以直接核对 Border 后继续。
- 02
如果刚下载并重新导入图片,把 Texture Type 设置为 Sprite (2D and UI),把 Mesh Type 设置为 Full Rect,然后单击 Apply。
- 03
打开 Sprite Editor,参考设置 Left = 44、Right = 46、Top = 39、Bottom = 40。
- 04
确认四条边界位于圆角与直线区域的交界处。
- 05
在 Sprite Editor 中单击 Apply 保存边界。
- 06
重新选择图片,确认 Border 数值已经保留。
九宫格怎样保护圆角
九宫格把图片划分为四个角、四条边和中心区域。改变尺寸时,四个角保留基本形状,上下边主要横向伸缩,左右边主要纵向伸缩,中心同时适应宽度和高度。
Sliced 不会把原图裁成九个独立文件,它只是告诉 Image 组件怎样根据精灵图边界重新生成显示网格。
配置 PageContainer 的 Image 组件
- 01
选择 PageContainer,找到 Image 组件。
- 02
把 Source Image 设置为 Round Radius 圆角图片。
- 03
把 Color 设置为纯黑色并保持不透明。
- 04
把 Image Type 设置为 Sliced。
- 05
确认 Fill Center 已开启,让中间区域正常填充。
- 06
把 Pixels Per Unit Multiplier 设置为 1.5。
- 07
观察页面背景是否完整覆盖右侧区域,左侧导航空间是否仍然保留。

重点观察右侧页面背景的四角与 Image 组件:Source Image 使用圆角图片,Image Type 为 Sliced,倍率为 1.5。
点击图片可以查看完整截图页面背景属性
颜色、切片方式和单位倍率共同决定页面区域的视觉结果。
左右滑动表格,可查看完整内容
| 属性 | 数值 | 作用 |
|---|---|---|
| Source Image | Round Radius | 提供带透明圆角的源图形 |
| Mesh Type | Full Rect | 使用完整矩形网格,保证九宫格切片正确生成 |
| Color | 纯黑色、不透明 | 提高文字与场景之间的对比 |
| Image Type | Sliced | 按九宫格规则保护圆角和边缘 |
| Fill Center | 开启 | 绘制页面背景的中心区域 |
| Pixels Per Unit Multiplier | 1.5 | 调整保护边界换算到界面后的视觉厚度 |
单位倍率不会改变图片分辨率
Pixels Per Unit Multiplier 可以理解为“每单位像素倍率”。在 Sliced 图片中,数值会影响边界区域显示出的厚度:数值增大时,圆角保护区域在界面中相对更收敛。
它不会修改源图片文件,也不会把图片真正放大 1.5 倍。若背景仍然变形,应先检查精灵图边界和 Image Type,而不是只反复调整倍率。
验证圆角是否保持
改变父画布宽度并观察页面背景,确认中间区域伸缩而四角不被明显拉扁。
- 核对背景为黑色且没有透明漏出。
- 临时改变 MenuUI 的宽度。
- 观察 PageContainer 中心区域随之改变。
- 检查四个圆角是否仍保持自然形状。
- 把 MenuUI 宽度恢复为 980。
把知识变成作品
本课练习
请按顺序完成以下任务,并保存自己的学习成果。- 01
不查看参数表,画出 MenuUI、PageContainer 和 NavigatorBar 的父子关系。
- 02
根据 980 × 550 与 0.001,解释世界空间菜单的实际大小。
- 03
把 MenuUI 宽度临时改为 1080,比较 PageContainer 与 NavigatorBar 的响应。
- 04
故意把 PageContainer 改为中心锚点,观察问题后恢复完整拉伸。
- 05
故意把一个背景改为 Simple,观察圆角变化后恢复 Sliced。
- 06
从场景对象和图片资源中分别找到 NavigatorBar 与 NavigationBar,并说明两者区别。
把本课进度保存下来
登录后可以保存浏览内容、有效学习时间、完成状态和答题参与记录。

