Bevy 引擎中的坐标系统详解
ZoOL 撰写的 Bevy 坐标系统完整指南,版本 0.16。原文是一份系统性的概念讲解,覆盖从世界空间到 NDC 的全链路。
坐标系统概览
Bevy 使用多套坐标系统,各自服务于不同任务:
| 坐标系统 | 原点 | Y轴方向 | 用途 |
|---|---|---|---|
| 世界空间 (2D) | 屏幕中心 | 向上 | 2D 游戏元素定位 |
| 世界空间 (3D) | 游戏定义 | 向上 | 3D 场景全局参考 |
| 局部空间 (Transform) | 父实体原点 | 相对于父 | 层级对象姿态 |
| 屏幕/UI 空间 | 左上角 | 向下 | UI 布局、鼠标输入 |
| 视口空间 | 视口左上角 | 向下 | 渲染目标子区域 |
| NDC | 投影中心 | 向上 | 渲染管线中间步骤 |
核心概念
世界空间:右手坐标系,Y轴向上
+X → 右
+Y → 上
+Z → 观察者(2D),-Z 为前进方向(3D)
- 与 Godot、Maya、OpenGL 相同
- 与 Unity 不同(Unity 是左手坐标系)
- 2D/3D 使用一致坐标系,简化跨维度逻辑共享
Transform vs GlobalTransform
| 组件 | 含义 | 由谁修改 |
|---|---|---|
Transform | 局部位置/旋转/缩放(相对于父实体) | 开发者 |
GlobalTransform | 世界绝对变换(仿射变换) | Bevy 内部自动计算 |
关键细节:
- 修改
Transform后,GlobalTransform不会立即更新 - 更新发生在
PostUpdate阶段的TransformSystem::TransformPropagate - 如果在同一帧
Update阶段先改 Transform 再查 GlobalTransform,会得到过时数据 TransformHelper系统参数可在传播前获取最新值,但有性能开销
GlobalTransform 以 Affine3A 存储而非简单 Vec3+Quat,因为复杂层级可能产生剪切(shearing),矩阵表示更鲁棒。
UI / 屏幕坐标
- 原点:左上角
- +X → 右,+Y → 下
- 单位:逻辑像素(已 DPI 缩放补偿)
- 光标位置遵循此约定
NDC(归一化设备坐标)
- X/Y: [-1, 1]
- Z(深度): [0, 1]
- 渲染管线的标准化中间空间
- GPU 光栅化器在此空间操作
坐标转换 API
Camera 组件提供核心转换方法:
| 方法 | 输入 | 输出 | 用例 |
|---|---|---|---|
world_to_viewport | 世界坐标 Vec3 | 屏幕像素 Vec2 | 3D → 2D 屏幕点 |
viewport_to_world | 屏幕点 Vec2 | 射线 Ray3d | 3D 拾取 |
viewport_to_world_2d | 屏幕点 Vec2 | 世界坐标 Vec2 | 2D 游戏/正交相机 |
world_to_ndc | 世界坐标 Vec3 | NDC Vec3 | 投影变换 |
ndc_to_world | NDC Vec3 | 世界坐标 Vec3 | 逆投影 |
设计影响
- 层级动画:父子 Transform 天然支持复杂关节结构(角色肢体、载具炮塔)
- 同步延迟:Transform/ GlobalTransform 不同步窗口可能导致难察觉的 bug
- 渲染解耦:视口允许分屏、小地图、渲染到纹理等灵活呈现
与其他引擎对比
| 引擎 | 坐标系 | Z轴 |
|---|---|---|
| Bevy | 右手 | Y上,-Z前进 |
| Unity | 左手 | Y上,+Z前进 |
| Godot | 右手 | Y上,-Z前进 |
| OpenGL | 右手 | Y上,-Z前进 |
文件位置
/Users/zool/workspace/ZoOL's Valut/Bevy 引擎中的坐标系统详解.md